Class: Kalah
- Inherits:
-
Object
- Object
- Kalah
- Defined in:
- lib/kalah.rb
Defined Under Namespace
Classes: IllegalMoveError, IllegalStateError
Constant Summary collapse
- NUM_HOUSES =
Number of houses.
6
- STORE_INDEX_P1 =
Index of players’ stores.
NUM_HOUSES
- STORE_INDEX_P2 =
NUM_HOUSES * 2 + 1
Instance Attribute Summary collapse
-
#current_player ⇒ Object
readonly
Returns the value of attribute current_player.
-
#history ⇒ Object
readonly
Returns the value of attribute history.
-
#num_seeds ⇒ Object
readonly
Returns the value of attribute num_seeds.
-
#stores ⇒ Object
readonly
Returns the value of attribute stores.
Instance Method Summary collapse
-
#current_players_houses ⇒ Object
Returns the index-range of the current player’s houses.
-
#current_players_store ⇒ Object
Returns the index of the current player’s store.
-
#has_current_player_won ⇒ Object
Checks whether current player’s houses are empty.
-
#initialize(num_seeds = 6) ⇒ Kalah
constructor
A new instance of Kalah.
-
#player_1_houses ⇒ Object
The range of player 1’s houses.
-
#player_2_houses ⇒ Object
The range of player 2’s houses.
- #sow(index) ⇒ Object
-
#to_s ⇒ Object
Prints the Kalah board.
-
#undo(moves = 1) ⇒ Object
Undoes a number of moves.
Constructor Details
#initialize(num_seeds = 6) ⇒ Kalah
Returns a new instance of Kalah.
20 21 22 23 24 25 26 27 |
# File 'lib/kalah.rb', line 20 def initialize(num_seeds = 6) @stores = Array.new(NUM_HOUSES * 2 + 2, num_seeds) @stores[STORE_INDEX_P1] = 0 @stores[STORE_INDEX_P2] = 0 @history = Array.new @current_player = :P1 @num_seeds = num_seeds end |
Instance Attribute Details
#current_player ⇒ Object (readonly)
Returns the value of attribute current_player.
18 19 20 |
# File 'lib/kalah.rb', line 18 def current_player @current_player end |
#history ⇒ Object (readonly)
Returns the value of attribute history.
18 19 20 |
# File 'lib/kalah.rb', line 18 def history @history end |
#num_seeds ⇒ Object (readonly)
Returns the value of attribute num_seeds.
18 19 20 |
# File 'lib/kalah.rb', line 18 def num_seeds @num_seeds end |
#stores ⇒ Object (readonly)
Returns the value of attribute stores.
18 19 20 |
# File 'lib/kalah.rb', line 18 def stores @stores end |
Instance Method Details
#current_players_houses ⇒ Object
Returns the index-range of the current player’s houses.
133 134 135 136 137 138 139 |
# File 'lib/kalah.rb', line 133 def current_players_houses if @current_player == :P1 player_1_houses else player_2_houses end end |
#current_players_store ⇒ Object
Returns the index of the current player’s store.
117 118 119 |
# File 'lib/kalah.rb', line 117 def current_players_store return @current_player == :P1 ? STORE_INDEX_P1 : STORE_INDEX_P2 end |
#has_current_player_won ⇒ Object
Checks whether current player’s houses are empty.
122 123 124 125 126 127 128 129 130 |
# File 'lib/kalah.rb', line 122 def has_current_player_won current_players_houses.each do |i| if @stores[i] != 0 return false end end true end |
#player_1_houses ⇒ Object
The range of player 1’s houses
142 143 144 |
# File 'lib/kalah.rb', line 142 def player_1_houses 0..(STORE_INDEX_P1 - 1) end |
#player_2_houses ⇒ Object
The range of player 2’s houses
147 148 149 |
# File 'lib/kalah.rb', line 147 def player_2_houses (STORE_INDEX_P1 + 1)..(STORE_INDEX_P2 - 1) end |
#sow(index) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/kalah.rb', line 29 def sow(index) if index < 0 or index > @stores.length raise IllegalMoveError, "Index #{i} does not exist (Number of houses is #{@stores.length})" elsif index == STORE_INDEX_P1 or index == STORE_INDEX_P2 raise IllegalMoveError, "Player must not sow seeds from the store" elsif has_current_player_won raise IllegalMoveError, "Game is over" elsif (current_player == :P1 and index > STORE_INDEX_P1) or (current_player == :P2 and index < STORE_INDEX_P1) raise IllegalMoveError, "Current player must not sow from the opponent's houses" elsif @stores[index] == 0 raise IllegalMoveError, "House is empty." end # Copy to history. @history.push({ player: current_player, stores: Array.new(@stores) }) # Perform sow num_seeds = @stores[index] # Empty house. @stores[index] = 0 # Sow in other houses. i = 1 while num_seeds > 0 do house = (index + i) % @stores.length if (@current_player == :P1 and house == STORE_INDEX_P2) or (@current_player == :P2 and house == STORE_INDEX_P1) # Skip opponent's store. i += 1 next end @stores[house] += 1 num_seeds -= 1 i += 1 end # If last seed lands in empty house (size now 1), take opposite store. if current_players_houses.cover?((index + i - 1) % @stores.length) and i > NUM_HOUSES and @stores[(index + i - 1) % @stores.length] == 1 opposite = NUM_HOUSES * 2 - ((index + i - 1) % @stores.length) # Put to store. @stores[current_players_store] += @stores[opposite] @stores[current_players_store] += 1 # Empty houses. @stores[opposite] = 0 @stores[(index + i - 1) % @stores.length] = 0 end # Check if game has ended. if has_current_player_won # Move opponent's seeds to current player's store. range, store = 0 if @current_player == :P1 range = player_2_houses store = STORE_INDEX_P1 else range = player_1_houses store = STORE_INDEX_P2 end range.each do |i| @stores[store] += @stores[i] @stores[i] = 0 end end # Change turn if last seed did not land in own store. if !has_current_player_won and (index + i - 1) % @stores.length != current_players_store @current_player = @current_player == :P1 ? :P2 : :P1 end end |
#to_s ⇒ Object
Prints the Kalah board
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/kalah.rb', line 152 def to_s # Combine p2 (top) and p1 (bot) houses, and stores (mid) top = " " mid = "" bot = " " @stores.each_with_index do |v, i| if i == STORE_INDEX_P1 mid << "%02d\n" % v elsif i == STORE_INDEX_P2 mid.insert(0, "\n%02d " % v) elsif i > STORE_INDEX_P1 top.insert(3, "%02d " % v) else bot << "%02d " % v mid << " " end end top << mid << bot end |
#undo(moves = 1) ⇒ Object
Undoes a number of moves.
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/kalah.rb', line 104 def undo(moves = 1) raise IllegalStateError, "Cannot undo #{moves} moves. "\ "Only #{@history.length} moves performed."\ if history.length < moves state = @history.pop @current_player = state[:player] @stores = state[:stores] end |