Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Allyn Bauer

« Newer Snippets
Older Snippets »
Showing 1-1 of 1 total  RSS 

Pousse (Game)

   1  
   2  #! /usr/bin/ruby
   3  # Pousse.rb   Ruby implementation of the game of Pousse.
   4  class Hash
   5    #add a method to Hash that gets the next key in the hash, given a key.
   6    def next(key)
   7      keys = self.keys
   8      pos  = keys.index(key)
   9      if pos+1 == keys.length
  10        return keys[0]
  11      else
  12        return keys[pos+1]
  13      end
  14    end  
  15  end
  16    
  17  class Pousse
  18    def initialize(size = 4)
  19      @size       = size.to_i.freeze                      #our size can't change
  20      @board      = Array.new(@size){ Array.new(@size) }  #2d board array
  21      @previous   = []                                    #previous boards
  22      @players    = {:one => 'X', :two => 'O'}.freeze     #hash of players as:
  23                                                          # :name => piece
  24      run                                                 #run the game
  25    end
  26    
  27    #returns true if a victor is found, false if not
  28    def victory?
  29      grand_total = Hash.new(0)
  30      inv_players = @players.invert
  31      
  32      #add all the rows/cols representing a straight to grand_total
  33      @board.each_index do |x|
  34        r_sub, c_sub = Hash.new(0), Hash.new(0)
  35        @board[x].each_index do |y|
  36          r_sub[inv_players[@board[x][y]]] += 1 if @board[x][y]
  37          c_sub[inv_players[@board[y][x]]] += 1 if @board[y][x]
  38        end
  39        #add up subtotal vals
  40        [c_sub, r_sub].each do |a|
  41          a.each do |x|
  42            grand_total[x[0]] += 1 if x[1] == @size
  43          end
  44        end
  45      end
  46      
  47      #check for victory with straights
  48      if grand_total.values.inject{|sum, n| sum+n}
  49        if grand_total[@player] == grand_total[@players.next(@player)]
  50          puts "It's a tie!"
  51        elsif grand_total[@player] > grand_total[@players.next(@player)]
  52          puts "Player #{@player.to_s}, you win!"
  53          return true
  54        else
  55          puts "Player #{@players.next(@player)}, you win!"
  56          return true
  57        end
  58      end
  59      
  60      #check to see if this board is not a new one..
  61      @previous.each do |x|
  62        if x == @board
  63          puts "Player #{@player.to_s}, that board is a REPEAT! YOU LOSE!"
  64          return true
  65        end
  66      end
  67      #add a deep copy of the current board to the previous board list
  68      @previous << Marshal.load(Marshal.dump(@board))
  69      false
  70    end
  71    
  72    #print help messages
  73    def display_help
  74      puts "--------"
  75      puts "General commands:
  76      h - display this help dialog
  77      d - draw the board
  78      q - quit the program"
  79      
  80      puts "move? commands (i is an integer from 1 to #{@size})
  81      Li - Left
  82      Ri - Right
  83      Ti - Top
  84      Bi - Bottom"
  85      puts "--------"
  86    end
  87    
  88    #draw a grid representing current board status
  89    def draw_board
  90      #build numbers for top
  91      print "\n  "
  92      @size.times do |x|
  93        print " #{x+1}"
  94      end
  95      puts ""
  96      
  97      #main board section
  98      (@size * 2).times do |x|
  99        if (x % 2 == 0) #print a boundry
 100          print "  "
 101          @size.times { print "+-" }
 102          puts "+"
 103        else #print a data row
 104          print "#{x/2+1} "
 105          @size.times do |y|
 106            print "|"
 107            print @board[x/2][y] ? @board[x/2][y] : " "
 108          end
 109          puts "|"
 110        end
 111      end
 112      
 113      #bottom border
 114      print "  "
 115      @size.times { print "+-" }
 116       puts "+"
 117    end
 118  
 119    #execute a move? command. returns true if the move? was successful,
 120    #false if not
 121    def move?(command)
 122      direction, row = command.split(//)
 123      row = row.to_i
 124      
 125      if row > @size or row < 1 #we have a problem.
 126        puts "Invalid index value (#{row}) supplied."
 127        return false
 128      end
 129      
 130      row -= 1 #offset because of array index
 131      
 132      #setup values for shift_board call
 133      case direction.upcase
 134        when "L" then x = row;      y = 0;        dx = 0;   dy =  1
 135        when "R" then x = row;      y = @size-1;  dx = 0;   dy = -1
 136        when "T" then x = 0;        y = row;      dx = 1;   dy =  0
 137        when "B" then x = @size-1;  y = row ;     dx = -1;  dy =  0
 138      end
 139      shift_board(x, y, dx, dy, @players[@player])
 140      true
 141    end
 142    
 143    #game run loop. this method returns when the game is over
 144    def run
 145      puts "Welcome to Pousse!"
 146      display_help
 147      @player = :one
 148      loop do
 149        puts "Player #{@player.to_s}'s (#{@players[@player]}) turn."
 150        
 151        #get a value from the command line
 152        print "> "
 153        _input = $stdin.gets
 154        
 155        #process the input
 156        if    _input =~ /^[q|Q]/                  then break
 157        elsif _input =~ /^[h|H]/                  then display_help
 158        elsif _input =~ /^[d|D]/                  then draw_board
 159        elsif _input =~ /^[L|R|T|B|l|r|t|b][\d]/  then
 160          if move?(_input)
 161             draw_board
 162             break if victory? #exit the loop if we find a winner
 163             @player = @players.next(@player)
 164          end
 165        else puts "Command not recognized."
 166        end
 167      end
 168      puts "Thanks for playing Pousse!"
 169    end
 170    
 171    #shift cells in the board until our new data is appended and old data
 172    #is shifted into blank spaces or lost
 173    def shift_board(to_x, to_y, dx, dy, append)
 174      if to_y < @size and to_x < @size then #only handle existing cells
 175        if @board[to_x][to_y] != nil then
 176          mv = @board[to_x][to_y]
 177          @board[to_x][to_y] = nil
 178          shift_board(to_x+dx, to_y+dy, dx, dy, mv)
 179        end
 180        @board[to_x][to_y] = append
 181      end
 182    end
 183  end
 184  
 185  if ARGV[0]
 186    Pousse.new(ARGV[0]) 
 187  else
 188    Pousse.new
 189  end
« Newer Snippets
Older Snippets »
Showing 1-1 of 1 total  RSS