Class: ChessData::Board

Inherits:
Object
  • Object
show all
Defined in:
lib/chess_data/board.rb

Overview

Holds information about a chess position, including:

  • location of all pieces

  • options for castling king or queen side

  • halfmove and fullmove counts

  • possible enpassant target

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBoard

Creates an instance of an empty chess board



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/chess_data/board.rb', line 34

def initialize
  @board = []
  8.times do
    @board << [nil] * 8
  end
  @to_move = "w"
  @white_king_side_castling = false
  @white_queen_side_castling = false
  @black_king_side_castling = false
  @black_queen_side_castling = false
  @enpassant_target = "-"
  @halfmove_clock = 0
  @fullmove_number = 1
end

Instance Attribute Details

#black_king_side_castlingObject

True if black king-side castling is valid



23
24
25
# File 'lib/chess_data/board.rb', line 23

def black_king_side_castling
  @black_king_side_castling
end

#black_queen_side_castlingObject

True if black queen-side castling is valid



25
26
27
# File 'lib/chess_data/board.rb', line 25

def black_queen_side_castling
  @black_queen_side_castling
end

#enpassant_targetObject

If enpassant is possible, holds the target square, or “-”



27
28
29
# File 'lib/chess_data/board.rb', line 27

def enpassant_target
  @enpassant_target
end

#fullmove_numberObject

Counts the number of full moves



31
32
33
# File 'lib/chess_data/board.rb', line 31

def fullmove_number
  @fullmove_number
end

#halfmove_clockObject

Counts the number of half moves



29
30
31
# File 'lib/chess_data/board.rb', line 29

def halfmove_clock
  @halfmove_clock
end

#to_moveObject

The next player to move, “w” or “b”.



17
18
19
# File 'lib/chess_data/board.rb', line 17

def to_move
  @to_move
end

#white_king_side_castlingObject

True if white king-side castling is valid



19
20
21
# File 'lib/chess_data/board.rb', line 19

def white_king_side_castling
  @white_king_side_castling
end

#white_queen_side_castlingObject

True if white queen-side castling is valid



21
22
23
# File 'lib/chess_data/board.rb', line 21

def white_queen_side_castling
  @white_queen_side_castling
end

Class Method Details

.coords_to_square(col, row) ⇒ Object

Converts array coordinates into a square representation.

> ChessBoard::Board.coords_to_square 0, 7 => "A8"
> ChessBoard::Board.coords_to_square 7, 0 => "H1"
> ChessBoard::Board.coords_to_square 4, 4 => "E5"

The conversion is cached, for speed.



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/chess_data/board.rb', line 212

def Board.coords_to_square col, row
  unless defined? @coords_store
    @coords_store = []
    8.times do
      @coords_store << [nil] * 8
    end
    8.times do |cl|
      8.times do |rw|
        @coords_store[cl][rw] = Board.square_from_coords(cl, rw)
      end
    end
  end

  return @coords_store[col][row]
end

.from_fen(fen) ⇒ Board

Creates a chessboard from a FEN description. The FEN description may be a single string, representing a board or a full six-field description. Raises an ArgumentError if fen is not a valid FEN description.

Parameters:

  • fen (String)

    a board definition in FEN format

Returns:

  • (Board)

    an instance of board matching the FEN description



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/chess_data/board.rb', line 175

def Board.from_fen fen
  fields = fen.split " "
  unless fields.length == 1 || fields.length == 6
    raise ArgumentError, "Invalid FEN description"
  end
  # create and populate a new instance of ChessBoard
  board = Board.new
  board.send(:setup_board_from_fen, fields[0])
  if fields.length == 6
    board.to_move = fields[1].downcase
    board.white_king_side_castling = fields[2].include? "K"
    board.white_queen_side_castling = fields[2].include? "Q"
    board.black_king_side_castling = fields[2].include? "k"
    board.black_queen_side_castling = fields[2].include? "q"
    board.enpassant_target = fields[3]
    board.halfmove_clock = fields[4].to_i
    board.fullmove_number = fields[5].to_i
  end

  return board
end

.square_to_coords(square) ⇒ Object

Converts a square represention into array coordinates.

> ChessData::Board.square_to_coords "e4" => [4, 4] 
> ChessData::Board.square_to_coords "a8" => [0, 7] 
> ChessData::Board.square_to_coords "h1" => [7, 0]

The conversion is cached, for speed.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/chess_data/board.rb', line 236

def Board.square_to_coords square
  unless defined? @square_hash
    @square_hash = {}
    8.times do |col|
      8.times do |row|
        @square_hash[Board.square_from_coords(col, row)] = [col, row]
      end
    end
  end

  square = square.to_s.upcase # convert symbols to strings, ensure upper case
  unless @square_hash.has_key? square
    raise ArgumentError, "Invalid board notation -|#{square}|-"
  end

  return @square_hash[square]
end

.start_positionObject

Creates a board instance representing the start position.



198
199
200
201
# File 'lib/chess_data/board.rb', line 198

def Board.start_position
  Board.from_fen \
    "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
end

Instance Method Details

#==(board) ⇒ Object

Compare two boards for equality



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/chess_data/board.rb', line 90

def == board
  return false unless @to_move == board.to_move &&
    @white_king_side_castling == board.white_king_side_castling &&
    @white_queen_side_castling == board.white_queen_side_castling &&
    @black_king_side_castling == board.black_king_side_castling &&
    @black_queen_side_castling == board.black_queen_side_castling &&
    @enpassant_target == board.enpassant_target &&
    @halfmove_clock == board.halfmove_clock &&
    @fullmove_number == board.fullmove_number

  8.times do |i|
    8.times do |j|
      square = Board.coords_to_square i, j
      return false unless self[square] == board[square]
    end
  end

  return true
end

#[](square) ⇒ String

Provide a way of looking up items based on usual chess notation, i.e. :e4 or “E4”. Raises an ArgumentError if square is not a valid chessboard position.

Parameters:

  • square (String, Symbol)

    is location to find

Returns:

  • (String)

    chess on the given square



75
76
77
78
# File 'lib/chess_data/board.rb', line 75

def [](square)
  col, row = Board.square_to_coords square
  return @board[row][col]
end

#[]=(square, piece) ⇒ String

Change the piece on a given square.

Parameters:

  • square (String, Symbol)

    is location to change

  • piece (String)

Returns:

  • (String)

    chess on the given square



84
85
86
87
# File 'lib/chess_data/board.rb', line 84

def []=(square, piece)
  col, row = Board.square_to_coords square
  @board[row][col] = piece
end

#black_king_in_check?Boolean

Check if the black king is in check.

Returns:

  • (Boolean)


161
162
163
164
165
166
# File 'lib/chess_data/board.rb', line 161

def black_king_in_check?
  black_king = locations_of("k").first
  white_pieces.any? do |defn|
    Moves.can_reach self, defn.piece, defn.square, black_king
  end
end

#cloneObject

Makes a full copy of this board instance



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/chess_data/board.rb', line 50

def clone
  copy = Board.new

  8.times do |row|
    8.times do |col|
      copy.set row, col, @board[row][col]
    end
  end
  copy.to_move = @to_move
  copy.white_king_side_castling = @white_king_side_castling
  copy.white_queen_side_castling = @white_queen_side_castling
  copy.black_king_side_castling = @black_king_side_castling
  copy.black_queen_side_castling = @black_queen_side_castling
  copy.enpassant_target = @enpassant_target
  copy.halfmove_clock = @halfmove_clock
  copy.fullmove_number = @fullmove_number

  return copy
end

#count(piece) ⇒ Object

Count the number of occurrences of the given piece on the board.



131
132
133
# File 'lib/chess_data/board.rb', line 131

def count piece
  @board.flatten.count piece
end

#locations_of(piece, identifier = "") ⇒ Object

Return the location of given piece on board. Identifier can be a letter or number, and if present the piece location must contain it



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/chess_data/board.rb', line 112

def locations_of piece, identifier=""
  identifier = identifier.upcase
  result = []

  8.times do |row|
    8.times do |col|
      if @board[row][col] == piece
        square = Board.coords_to_square col, row
        if identifier.empty? || square.include?(identifier)
          result << square
        end
      end
    end
  end

  return result
end

#set(row, col, value) ⇒ Object

Provides a fast method to set value of board at given row/col index values – used to optimise clone



256
257
258
# File 'lib/chess_data/board.rb', line 256

def set row, col, value
  @board[row][col] = value
end

#to_sObject

Creates a simple 2D board representation, suitable for printing to a terminal.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/chess_data/board.rb', line 136

def to_s
  result = ""

  8.times do |i|
    8.times do |j|
      square = Board.coords_to_square j, i
      piece = self[square]
      piece = "." if piece.nil?
      result += piece
    end
    result += "\n"
  end

  return result
end

#white_king_in_check?Boolean

Check if the white king is in check.

Returns:

  • (Boolean)


153
154
155
156
157
158
# File 'lib/chess_data/board.rb', line 153

def white_king_in_check?
  white_king = locations_of("K").first
  black_pieces.any? do |defn|
    Moves.can_reach self, defn.piece, defn.square, white_king
  end
end