def apply_move!(move, player = @current_player)
raise(InvalidMoveError, "Piece #{move.piece} does not exist") unless @pieces.has_key?(move.piece.name)
raise(InvalidMoveError, "Player #{player} moving piece #{move.piece}") unless move.piece.colour == player
raise(InvalidMoveError, "Attempting to move captured piece #{move.piece}") if move.piece.captured
raise(InvalidMoveError, "Attempting to move #{move.piece} onto or via base without captured pieces") if move.via_base? and move.piece.contains.empty?
if move.destination.safe?
if (@pieces.find_all {|k, p| p.position == move.destination}).length >= 3
raise(InvalidMoveError, "Attempting to move #{move.piece} onto safe position #{move.destination} when there are already three or more pieces there")
end
end
if move.via_base?
moved_distance = board.distance_between[move.piece.position.place][player] +
board.distance_between[player][move.destination.place]
else
moved_distance = board.distance_between[move.piece.position.place][move.destination.place]
end
raise(InvalidMoveError, "Attempting to move piece #{move.piece} #{moved_distance} places (from #{move.piece.position} to #{move.destination})") if moved_distance < 1 or moved_distance > 6
move.piece.move_to(move.destination)
unless move.destination.safe? or move.destination.base?
@pieces.each do |name, target_piece|
if target_piece.position == move.destination and
target_piece != move.piece and
not move.piece.contains.member?(target_piece) and
target_piece.colour != player and
not target_piece.captured
move.piece.capture(target_piece)
end
end
end
if move.via_base?
capturers_base = board.positions[move.piece.colour]
move.piece.contains.each do |captured_piece|
captured_piece.move_to capturers_base
captured_piece.captured = false if captured_piece.colour == move.piece.colour
end
move.piece.contains = []
end
this_game_state = GameState.new(move, player, @pieces)
@history << this_game_state
potential_players = []
@players.each do |p|
if (@pieces.values.select {|piece| piece.colour == p}).any? {|piece| not piece.captured}
potential_players << p
end
end
if potential_players.length <= 1
raise(GameWonNotice, "Game won by #{potential_players[0]}")
end
@players = potential_players.sort
end