Class: ChessEngine::Game
- Inherits:
-
Object
- Object
- ChessEngine::Game
- Includes:
- MoveValidator
- Defined in:
- lib/chess_engine/game.rb
Overview
This class provides all the rules for the chess game. It recognizes check, checkmate and stalemate. Move validations logic can be found in the MoveValidator module, which is included in this class
Instance Attribute Summary collapse
-
#current_color ⇒ Object
readonly
Returns the value of attribute current_color.
-
#name ⇒ Object
Returns the value of attribute name.
Instance Method Summary collapse
- #[](str) ⇒ Object
-
#castling(length) ⇒ Object
Accepts a
length
sybmol :short or :long. -
#check? ⇒ Boolean
Returns true if current king is attacked.
-
#draw ⇒ Object
Returns the board in the nice-looking string.
-
#initialize ⇒ Game
constructor
A new instance of Game.
-
#move(string) ⇒ Object
Accepts the move string in algebraic notation, e.g.
-
#needs_promotion? ⇒ Boolean
Checks if pawn promotion is needed.
-
#over? ⇒ Boolean
Returns true if game is over.
-
#promotion(class_name) ⇒ Object
Accepts a string with name of the piece.
Methods included from MoveValidator
Constructor Details
Instance Attribute Details
#current_color ⇒ Object (readonly)
Returns the value of attribute current_color.
15 16 17 |
# File 'lib/chess_engine/game.rb', line 15 def current_color @current_color end |
#name ⇒ Object
Returns the value of attribute name.
14 15 16 |
# File 'lib/chess_engine/game.rb', line 14 def name @name end |
Instance Method Details
#[](str) ⇒ Object
70 71 72 73 74 |
# File 'lib/chess_engine/game.rb', line 70 def [](str) letters = ("a".."h").to_a return nil unless /[a-h][1-8]/.match?(str) @board.at([letters.find_index(str[0]), str[1].to_i - 1]) end |
#castling(length) ⇒ Object
Accepts a length
sybmol :short or :long. Ensures that castling is possible and commits appropriate moves. Otherwise, raises InvalidMove
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/chess_engine/game.rb', line 104 def castling(length) row = @current_color == :white ? 0 : 7 king = @board.at([4, row]) if length == :short rook = @board.at([7, row]) line = [5, 6] moves = [Move.new(@board, [4, row], [6, row]), Move.new(@board, [7, row], [5, row])] else rook = @board.at([0, row]) line = [1, 2, 3] moves = [Move.new(@board, [4, row], [2, row]), Move.new(@board, [0, row], [3, row])] end raise InvalidMove, "Invalid castling" unless king && rook && king.moves_count == 0 && rook.moves_count == 0 && line.all? { |x| @board.at([x, row]).nil? } moves.each { |move| move.commit } if king_attacked? moves.each { |move| move.rollback } raise InvalidMove, "Fatal move" end @last_piece = nil next_player end |
#check? ⇒ Boolean
Returns true if current king is attacked
150 151 152 |
# File 'lib/chess_engine/game.rb', line 150 def check? king_attacked? end |
#draw ⇒ Object
Returns the board in the nice-looking string
79 80 81 |
# File 'lib/chess_engine/game.rb', line 79 def draw @board.to_s end |
#move(string) ⇒ Object
Accepts the move string in algebraic notation, e.g. “e2e4”, and applies it to the board. Raises InvalidMove if:
-
Game is already over
-
Pawn promotion should be executed first
-
Empty square is chosen
-
Player tries to move piece of the opponent
-
Move is invalid (checks via the MoveValidator module)
-
Move is fatal (king is attacked after the move)
After successfull move, the method changes the current player or goes into “A pawn needs promotion” state, which can be checked by #needs_promotion? method
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/chess_engine/game.rb', line 42 def move(string) from, to = Game.string_to_move(string) piece = @board.at(from) raise InvalidMove, "Game is over" if over? raise InvalidMove, "#{@current_color} player should execute pawn promotion first" if needs_promotion? raise InvalidMove, "Empty square is chosen" if piece.nil? raise InvalidMove, "This is not your piece" unless piece.color == @current_color raise InvalidMove, "Invalid move" unless valid_moves(from).include?(to) move = Move.new(@board, from, to) move.commit if king_attacked? move.rollback raise InvalidMove, "Fatal move" end @last_piece = piece piece.moves_count += 1 @promotion_coord = to and return if piece.pawn? && [7, 0].include?(to[1]) next_player end |
#needs_promotion? ⇒ Boolean
Checks if pawn promotion is needed
143 144 145 |
# File 'lib/chess_engine/game.rb', line 143 def needs_promotion? !!@promotion_coord end |
#over? ⇒ Boolean
Returns true if game is over
134 135 136 137 138 |
# File 'lib/chess_engine/game.rb', line 134 def over? @board.piece_coordinates(@current_color).all? do |coord| safe_moves(coord).empty? end end |
#promotion(class_name) ⇒ Object
Accepts a string with name of the piece. Promotes a pawn and changes the current player. Raises InvalidMove if promotion is not needed or invalid class_name
has been passed
Example
game.promotion("queen")
91 92 93 94 95 96 97 98 |
# File 'lib/chess_engine/game.rb', line 91 def promotion(class_name) unless needs_promotion? && ["rook", "knight", "elephant", "queen"].include?(class_name.downcase) raise InvalidMove, "Invalid promotion" end @board.set_at(@promotion_coord, Module.const_get("ChessEngine::#{class_name.capitalize}").new(@current_color)) @promotion_coord = nil next_player end |