R
Ruby Quiz
The three rules of Ruby Quiz:
1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.
2. Support Ruby Quiz by submitting ideas as often as you can:
http://www.rubyquiz.com/
3. Enjoy!
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
by Mark Van Holstyn
For my Computer Science class this month, we had to program a Kalah Player.
Sadly, we had to do our project in Java, but I ported the game code and the
sample players to ruby for this quiz though.
A good explanation of the game can be found at:
http://rubyurl.com/SqU
Your task is to create the best Kalah player you can. The player should look
like the following:
class HumanPlayer < Player
def choose_move
print 'Enter your move choice: '
gets.chomp.to_i
end
end
The 'choose_move' method is what the game will call to request a move from the
player. The Player class which you player should extend looks like so:
class Player
attr_accessor :name
attr_writer :game, :side
def initialize( name )
@name = name
end
def choose_move
if @side==KalahGame::TOP
(7..12).each { |i| return i if @game.stones_at?(i) > 0 }
else
(0..5).each { |i| return i if @game.stones_at?(i) > 0 }
end
end
end
The 'game' and 'side' attributes will be assigned by KalahGame. The side will
either be the constant KalahGame::TOP or KalahGame::BOTTOM. This is what you
will use to determine if you should be making moves from bowls 0-5 or 7-12 and
whether your Kalah is 6 or 13.
KalahMatch plays two games, one with each player on the each side of the board
and then averages their scores, so you must make you player be able to play both
on the top and the bottom.
Here's a sample game engine to get you started:
require 'Player'
require 'HumanPlayer'
class KalahMatch
def start( p1, p2 )
puts ''
puts '========== GAME 1 =========='
p1_score_1, p2_score_1 = KalahGame.new.play_game( p1, p2 )
if p1_score_1 > p2_score_1
puts p1.name+' won game #1: '+p1_score_1.to_s+'-'+p2_score_1.to_s
elsif p2_score_1 > p1_score_1
puts p2.name+' won game #1: '+p2_score_1.to_s+'-'+p1_score_1.to_s
else
puts 'game #1 was a tie: '+p1_score_1.to_s+'-'+p2_score_1.to_s
end
puts ''
puts '========== GAME 2 =========='
p2_score_2, p1_score_2 = KalahGame.new.play_game( p2, p1 )
if p1_score_2 > p2_score_2
puts p1.name+' won game #2: '+p1_score_2.to_s+'-'+p2_score_2.to_s
elsif p2_score_2 > p1_score_2
puts p2.name+' won game #2: '+p2_score_2.to_s+'-'+p1_score_2.to_s
else
puts 'game #2 was a tie: '+p1_score_2.to_s+'-'+p2_score_2.to_s
end
puts ''
puts '========== FINAL =========='
p1_final = p1_score_1+p1_score_2
p2_final = p2_score_1+p2_score_2
if p1_final > p2_final
puts p1.name+' won the match: '+p1_final.to_s+'-'+p2_final.to_s
elsif p2_final > p1_final
puts p2.name+' won the match: '+p2_final.to_s+'-'+p1_final.to_s
else
puts 'the match was tied overall : '+p1_final.to_s+'-'+p2_final.to_s
end
end
end
class KalahGame
NOBODY = 0
TOP = 1
BOTTOM = 2
def stones_at?( i )
@board
end
def legal_move?( move )
( ( @player_to_move==TOP and move >= 7 and move <= 12 ) ||
( @player_to_move==BOTTOM and move >= 0 and move <= 5 ) ) and
@board[move] != 0
end
def game_over?
top = bottom = true
(7..12).each { |i| top = false if @board > 0 }
(0..5).each { |i| bottom = false if @board > 0 }
top or bottom
end
def winner
top, bottom = top_score, bottom_score
if top > bottm
return TOP
elsif bottom > top
return BOTTOM
else
return NOBODY
end
end
def top_score
score = 0
(7..13).each { |i| score += @board }
score
end
def bottom_score
score = 0
(0..6).each { |i| score += @board }
score
end
def make_move( move )
( puts 'Illegal move...' ; return ) unless legal_move?( move )
stones, @board[move] = @board[move], 0
pos = move+1
while stones > 0
pos+=1 if( (@player_to_move==TOP and pos==6) ||
(@player_to_move==BOTTOM and pos==13) )
pos = 0 if pos==14
@board[pos]+=1
stones-=1
pos+=1 if stones > 0
end
if( @player_to_move==TOP and pos>6 and pos<13 and @board[pos]==1 )
@board[13] += @board[12-pos]+1
@board[12-pos] = @board[pos] = 0
elsif( @player_to_move==BOTTOM and pos>=0 and pos<6 and @board[pos]==1 )
@board[6] += @board[12-pos]+1
@board[12-pos] = @board[pos] = 0
end
if @player_to_move==TOP
@player_to_move = BOTTOM unless pos == 13
else
@player_to_move=TOP unless pos == 6
end
end
def display
puts ''
top = ' '
[12,11,10,9,8,7].each { |i| top += @board.to_s+' ' }
puts top
puts @board[13].to_s + ' ' + @board[6].to_s
bottom = ' '
(0..5).each { |i| bottom += @board.to_s+' ' }
puts bottom
puts ''
end
def reset
@board = Array.new( 14, 4 )
@board[6] = @board[13] = 0
@player_to_move = BOTTOM
end
def play_game( bottom, top )
reset
bottom.side = BOTTOM
top.side = TOP
top.game = bottom.game = self
puts bottom.name+' starts...'
display
until game_over?
puts ''
if @player_to_move == TOP
move = top.choose_move
puts top.name+' choose move '+move.to_s
else
move = bottom.choose_move
puts bottom.name+' choose move '+move.to_s
end
make_move( move )
display
end
[top_score, bottom_score]
end
end
p1 = Player.new( 'Player 1' )
p2 = Player.new( 'Player 2' )
KalahMatch.new.start( p1, p2 )
1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.
2. Support Ruby Quiz by submitting ideas as often as you can:
http://www.rubyquiz.com/
3. Enjoy!
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
by Mark Van Holstyn
For my Computer Science class this month, we had to program a Kalah Player.
Sadly, we had to do our project in Java, but I ported the game code and the
sample players to ruby for this quiz though.
A good explanation of the game can be found at:
http://rubyurl.com/SqU
Your task is to create the best Kalah player you can. The player should look
like the following:
class HumanPlayer < Player
def choose_move
print 'Enter your move choice: '
gets.chomp.to_i
end
end
The 'choose_move' method is what the game will call to request a move from the
player. The Player class which you player should extend looks like so:
class Player
attr_accessor :name
attr_writer :game, :side
def initialize( name )
@name = name
end
def choose_move
if @side==KalahGame::TOP
(7..12).each { |i| return i if @game.stones_at?(i) > 0 }
else
(0..5).each { |i| return i if @game.stones_at?(i) > 0 }
end
end
end
The 'game' and 'side' attributes will be assigned by KalahGame. The side will
either be the constant KalahGame::TOP or KalahGame::BOTTOM. This is what you
will use to determine if you should be making moves from bowls 0-5 or 7-12 and
whether your Kalah is 6 or 13.
KalahMatch plays two games, one with each player on the each side of the board
and then averages their scores, so you must make you player be able to play both
on the top and the bottom.
Here's a sample game engine to get you started:
require 'Player'
require 'HumanPlayer'
class KalahMatch
def start( p1, p2 )
puts ''
puts '========== GAME 1 =========='
p1_score_1, p2_score_1 = KalahGame.new.play_game( p1, p2 )
if p1_score_1 > p2_score_1
puts p1.name+' won game #1: '+p1_score_1.to_s+'-'+p2_score_1.to_s
elsif p2_score_1 > p1_score_1
puts p2.name+' won game #1: '+p2_score_1.to_s+'-'+p1_score_1.to_s
else
puts 'game #1 was a tie: '+p1_score_1.to_s+'-'+p2_score_1.to_s
end
puts ''
puts '========== GAME 2 =========='
p2_score_2, p1_score_2 = KalahGame.new.play_game( p2, p1 )
if p1_score_2 > p2_score_2
puts p1.name+' won game #2: '+p1_score_2.to_s+'-'+p2_score_2.to_s
elsif p2_score_2 > p1_score_2
puts p2.name+' won game #2: '+p2_score_2.to_s+'-'+p1_score_2.to_s
else
puts 'game #2 was a tie: '+p1_score_2.to_s+'-'+p2_score_2.to_s
end
puts ''
puts '========== FINAL =========='
p1_final = p1_score_1+p1_score_2
p2_final = p2_score_1+p2_score_2
if p1_final > p2_final
puts p1.name+' won the match: '+p1_final.to_s+'-'+p2_final.to_s
elsif p2_final > p1_final
puts p2.name+' won the match: '+p2_final.to_s+'-'+p1_final.to_s
else
puts 'the match was tied overall : '+p1_final.to_s+'-'+p2_final.to_s
end
end
end
class KalahGame
NOBODY = 0
TOP = 1
BOTTOM = 2
def stones_at?( i )
@board
end
def legal_move?( move )
( ( @player_to_move==TOP and move >= 7 and move <= 12 ) ||
( @player_to_move==BOTTOM and move >= 0 and move <= 5 ) ) and
@board[move] != 0
end
def game_over?
top = bottom = true
(7..12).each { |i| top = false if @board > 0 }
(0..5).each { |i| bottom = false if @board > 0 }
top or bottom
end
def winner
top, bottom = top_score, bottom_score
if top > bottm
return TOP
elsif bottom > top
return BOTTOM
else
return NOBODY
end
end
def top_score
score = 0
(7..13).each { |i| score += @board }
score
end
def bottom_score
score = 0
(0..6).each { |i| score += @board }
score
end
def make_move( move )
( puts 'Illegal move...' ; return ) unless legal_move?( move )
stones, @board[move] = @board[move], 0
pos = move+1
while stones > 0
pos+=1 if( (@player_to_move==TOP and pos==6) ||
(@player_to_move==BOTTOM and pos==13) )
pos = 0 if pos==14
@board[pos]+=1
stones-=1
pos+=1 if stones > 0
end
if( @player_to_move==TOP and pos>6 and pos<13 and @board[pos]==1 )
@board[13] += @board[12-pos]+1
@board[12-pos] = @board[pos] = 0
elsif( @player_to_move==BOTTOM and pos>=0 and pos<6 and @board[pos]==1 )
@board[6] += @board[12-pos]+1
@board[12-pos] = @board[pos] = 0
end
if @player_to_move==TOP
@player_to_move = BOTTOM unless pos == 13
else
@player_to_move=TOP unless pos == 6
end
end
def display
puts ''
top = ' '
[12,11,10,9,8,7].each { |i| top += @board.to_s+' ' }
puts top
puts @board[13].to_s + ' ' + @board[6].to_s
bottom = ' '
(0..5).each { |i| bottom += @board.to_s+' ' }
puts bottom
puts ''
end
def reset
@board = Array.new( 14, 4 )
@board[6] = @board[13] = 0
@player_to_move = BOTTOM
end
def play_game( bottom, top )
reset
bottom.side = BOTTOM
top.side = TOP
top.game = bottom.game = self
puts bottom.name+' starts...'
display
until game_over?
puts ''
if @player_to_move == TOP
move = top.choose_move
puts top.name+' choose move '+move.to_s
else
move = bottom.choose_move
puts bottom.name+' choose move '+move.to_s
end
make_move( move )
display
end
[top_score, bottom_score]
end
end
p1 = Player.new( 'Player 1' )
p2 = Player.new( 'Player 2' )
KalahMatch.new.start( p1, p2 )