Class: ChessRB::Position

Inherits:
Object
  • Object
show all
Defined in:
lib/chess_rb/position.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fen) ⇒ Position

Returns a new instance of Position.



6
7
8
9
10
11
# File 'lib/chess_rb/position.rb', line 6

def initialize(fen)
  @fen = fen
  @fen_components = fen.split(' ')
  @board = fen_to_board(fen)
  @valid = valid?
end

Instance Attribute Details

#fenObject

Returns the value of attribute fen.



4
5
6
# File 'lib/chess_rb/position.rb', line 4

def fen
  @fen
end

Class Method Details

.valid_square?(s) ⇒ Boolean

Returns:

  • (Boolean)


13
14
15
16
17
# File 'lib/chess_rb/position.rb', line 13

def self.valid_square?(s)
  i = s[0]; j = s[1]
  return i.is_a?(Integer) && j.is_a?(Integer) &&
    i >= 0 && i < 8 && j >= 0 && j < 8
end

Instance Method Details

#check?Boolean

Returns if the current position is check, false otherwise

Returns:

  • (Boolean)


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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/chess_rb/position.rb', line 60

def check?
  raise RuntimeError "Invalid Position" if !valid?

  t = turn().upcase
  not_t = t == 'W' ? 'B' : 'W'
  king_vector = Vector[*(squares_with([t + 'K'])[0])]

  # check pawn squares
  pawn_vectors = t == 'W' ? [[-1, -1], [1, -1]] : [[-1, 1], [1, 1]]
  pawn_vectors.each do |s|
    s = (king_vector + Vector[*s]).to_a
    next if !self.class.valid_square?(s)
    return true if piece_on(s).desc == (not_t + 'P')
  end

  # check knight squares
  knight_vectors = [[1,2], [-1,2], [1,-2], [-1,-2], [2,1], [-2,1], [2,-1],
    [-2,-1]]
  knight_vectors.each do |s|
    s = (king_vector + Vector[*s]).to_a
    next if !self.class.valid_square?(s)
    return true if piece_on(s).desc == (not_t + 'N')
  end

  # check bishop/queen squares
  diagonal_vectors = [[1, 1], [-1, 1], [1, -1], [-1, -1]]
  diagonal_vectors.each do |v|
    dist = 1
    v = Vector[*v]
    while dist < 8
      current_vector = v * dist
      current_square = (king_vector + current_vector).to_a

      break if !self.class.valid_square?(current_square)

      p = piece_on(current_square).desc
      return true if p == (not_t + 'B') || p == (not_t + 'Q')
      break if p != 'E'

      dist += 1
    end
  end

  # check rook/queen squares
  straight_vectors = [[1, 0], [0, 1], [-1, 0], [0, -1]]
  straight_vectors.each do |v|
    dist = 1
    v = Vector[*v]
    while dist < 8
      current_vector = v * dist
      current_square = (king_vector + current_vector).to_a

      break if !self.class.valid_square?(current_square)

      p = piece_on(current_square).desc
      return true if p == (not_t + 'B') || p == (not_t + 'Q')
      break if p != 'E'

      dist += 1
    end
  end

  return false
end

#make_move(move) ⇒ Object



155
156
157
158
159
160
# File 'lib/chess_rb/position.rb', line 155

def make_move(move)
  move([8 - move.from_rank, move.from_file - 1],
    [8 - move.to_rank, move.to_file - 1])

  update_fen(move, true)
end

#mate?Boolean

Returns if the current position is checkmate, false otherwise

Returns:

  • (Boolean)


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/chess_rb/position.rb', line 126

def mate?
  return false if !check?

  t = turn().upcase
  king_vector = Vector[*(squares_with([t + 'K'])[0])]

  around_vectors = [[1, 0], [0, 1], [-1, 0], [0, -1], [1, 1], [-1, 1],
    [1, -1], [-1, -1]]
  around_vectors.each do |v|
    v = Vector[*v]
    current_square = (king_vector + v).to_a
    if !self.class.valid_square?(current_square) ||
      piece_on(current_square).color == t

      next
    else
      undo_code = piece_on(current_square).code
      move(king_vector.to_a, current_square)
      if !check?
        undo(king_vector.to_a, current_square, undo_code)
        return false
      end
      undo(king_vector.to_a, current_square, undo_code)
    end
  end

  return true
end

#piece_on(square) ⇒ Object

Returns the piece code on the given square



31
32
33
34
35
36
37
38
39
# File 'lib/chess_rb/position.rb', line 31

def piece_on(square)
  if square.is_a?(String)
    file = ChessRB::Move.file(square)
    rank = ChessRB::Move.rank(square)
    return ChessRB::Piece.new(@board[8 - rank][file - 1])
  else
    return ChessRB::Piece.new(@board[square[0]][square[1]])
  end
end

#squares_with(pieces) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/chess_rb/position.rb', line 41

def squares_with(pieces)
  squares = []
  codes = []
  pieces.each do |piece|
    codes << ChessRB::Piece.const_get(piece)
  end

  @board.each_with_index do |r , i|
    r.each_with_index do |p, j|
      if codes.include?(p)
        squares << [i, j]
      end
    end
  end

  return squares
end

#to_s(dark_background = true) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/chess_rb/position.rb', line 169

def to_s(dark_background = true)
  str = ""
  @board.each_with_index do |r, i|
    str += (8 - i).to_s + ""
    r.each do |s|
      str += " "
      if s == 0
        str += ""
      else
        str += ChessRB::Piece.new(s).to_s(dark_background)
      end
    end
    str += "\n"
  end
  str += " ╚════════════════\n   A B C D E F G H"
  return str
end

#turnObject

Returns ‘w’ or ‘b’ if it is white or black’s move, respectively



26
27
28
# File 'lib/chess_rb/position.rb', line 26

def turn
  return @fen_components[1]
end

#undo_move(move, piece) ⇒ Object



162
163
164
165
166
167
# File 'lib/chess_rb/position.rb', line 162

def undo_move(move, piece)
  undo([8 - move.from_rank, move.from_file - 1],
    [8 - move.to_rank, move.to_file - 1], piece.code)

  update_fen(move, false)
end

#valid?Boolean

TODO

Returns:

  • (Boolean)


20
21
22
23
# File 'lib/chess_rb/position.rb', line 20

def valid?
  return @valid if !@valid.nil?
  return true
end