DZone 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
Pousse (Game)
#! /usr/bin/ruby
# Pousse.rb Ruby implementation of the game of Pousse.
class Hash
#add a method to Hash that gets the next key in the hash, given a key.
def next(key)
keys = self.keys
pos = keys.index(key)
if pos+1 == keys.length
return keys[0]
else
return keys[pos+1]
end
end
end
class Pousse
def initialize(size = 4)
@size = size.to_i.freeze #our size can't change
@board = Array.new(@size){ Array.new(@size) } #2d board array
@previous = [] #previous boards
@players = {:one => 'X', :two => 'O'}.freeze #hash of players as:
# :name => piece
run #run the game
end
#returns true if a victor is found, false if not
def victory?
grand_total = Hash.new(0)
inv_players = @players.invert
#add all the rows/cols representing a straight to grand_total
@board.each_index do |x|
r_sub, c_sub = Hash.new(0), Hash.new(0)
@board[x].each_index do |y|
r_sub[inv_players[@board[x][y]]] += 1 if @board[x][y]
c_sub[inv_players[@board[y][x]]] += 1 if @board[y][x]
end
#add up subtotal vals
[c_sub, r_sub].each do |a|
a.each do |x|
grand_total[x[0]] += 1 if x[1] == @size
end
end
end
#check for victory with straights
if grand_total.values.inject{|sum, n| sum+n}
if grand_total[@player] == grand_total[@players.next(@player)]
puts "It's a tie!"
elsif grand_total[@player] > grand_total[@players.next(@player)]
puts "Player #{@player.to_s}, you win!"
return true
else
puts "Player #{@players.next(@player)}, you win!"
return true
end
end
#check to see if this board is not a new one..
@previous.each do |x|
if x == @board
puts "Player #{@player.to_s}, that board is a REPEAT! YOU LOSE!"
return true
end
end
#add a deep copy of the current board to the previous board list
@previous << Marshal.load(Marshal.dump(@board))
false
end
#print help messages
def display_help
puts "--------"
puts "General commands:
h - display this help dialog
d - draw the board
q - quit the program"
puts "move? commands (i is an integer from 1 to #{@size})
Li - Left
Ri - Right
Ti - Top
Bi - Bottom"
puts "--------"
end
#draw a grid representing current board status
def draw_board
#build numbers for top
print "\n "
@size.times do |x|
print " #{x+1}"
end
puts ""
#main board section
(@size * 2).times do |x|
if (x % 2 == 0) #print a boundry
print " "
@size.times { print "+-" }
puts "+"
else #print a data row
print "#{x/2+1} "
@size.times do |y|
print "|"
print @board[x/2][y] ? @board[x/2][y] : " "
end
puts "|"
end
end
#bottom border
print " "
@size.times { print "+-" }
puts "+"
end
#execute a move? command. returns true if the move? was successful,
#false if not
def move?(command)
direction, row = command.split(//)
row = row.to_i
if row > @size or row < 1 #we have a problem.
puts "Invalid index value (#{row}) supplied."
return false
end
row -= 1 #offset because of array index
#setup values for shift_board call
case direction.upcase
when "L" then x = row; y = 0; dx = 0; dy = 1
when "R" then x = row; y = @size-1; dx = 0; dy = -1
when "T" then x = 0; y = row; dx = 1; dy = 0
when "B" then x = @size-1; y = row ; dx = -1; dy = 0
end
shift_board(x, y, dx, dy, @players[@player])
true
end
#game run loop. this method returns when the game is over
def run
puts "Welcome to Pousse!"
display_help
@player = :one
loop do
puts "Player #{@player.to_s}'s (#{@players[@player]}) turn."
#get a value from the command line
print "> "
_input = $stdin.gets
#process the input
if _input =~ /^[q|Q]/ then break
elsif _input =~ /^[h|H]/ then display_help
elsif _input =~ /^[d|D]/ then draw_board
elsif _input =~ /^[L|R|T|B|l|r|t|b][\d]/ then
if move?(_input)
draw_board
break if victory? #exit the loop if we find a winner
@player = @players.next(@player)
end
else puts "Command not recognized."
end
end
puts "Thanks for playing Pousse!"
end
#shift cells in the board until our new data is appended and old data
#is shifted into blank spaces or lost
def shift_board(to_x, to_y, dx, dy, append)
if to_y < @size and to_x < @size then #only handle existing cells
if @board[to_x][to_y] != nil then
mv = @board[to_x][to_y]
@board[to_x][to_y] = nil
shift_board(to_x+dx, to_y+dy, dx, dy, mv)
end
@board[to_x][to_y] = append
end
end
end
if ARGV[0]
Pousse.new(ARGV[0])
else
Pousse.new
end




