Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

DZone's Guide to

# Pousse (Game)

· ·
Free Resource

Comment (0)

Save
{{ articles[0].views | formatCount}} Views
``````
#! /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
[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
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
``````
Topics:

Comment (0)

Save
{{ articles[0].views | formatCount}} Views

Opinions expressed by DZone contributors are their own.