Module: ChessData::Moves

Defined in:
lib/chess_data/moves.rb

Overview

Moves is a collection of regular expressions and methods to recognise how moves are written in PGN files, and to make the moves on a given board.

As the moves are obtained from PGN files, they are assumed to be correct.

Defined Under Namespace

Classes: KingsideCastles, PawnCapture, PieceMove, PromotionPawnCapture, PromotionPawnMove, QueensideCastles, SimplePawnMove

Constant Summary collapse

Square =

:nodoc: Regular expressions to match each of the move types.

/[a-h][1-8]/
Piece =
/[KQRBN]/
MatchKingsideCastles =
/^O-O\+?\Z/
MatchQueensideCastles =
/^O-O-O\+?\Z/
MatchPieceMove =
/^(#{Piece})([a-h]?|[1-8]?)x?(#{Square})\+?\Z/
MatchPawnCapture =
/^([a-h])x(#{Square})\+?\Z/
MatchPromotionPawnMove =
/^([a-h][18])=([QqRrBbNn])\+?\Z/
MatchSimplePawnMove =
/^(#{Square})\+?\Z/
MatchPromotionPawnCapture =
/^([a-h])x([a-h][18])=([QqRrBbNn])\+?\Z/
LegalMove =

Combined regular expression, to match a legal move.

/#{MatchKingsideCastles}|#{MatchQueensideCastles}|#{MatchPieceMove}|#{MatchPawnCapture}|#{MatchPromotionPawnMove}|#{MatchSimplePawnMove}|#{MatchPromotionPawnCapture}/

Class Method Summary collapse

Class Method Details

.bishop_can_reach(board, start, finish) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/chess_data/moves.rb', line 106

def Moves.bishop_can_reach board, start,finish
  return false unless Moves.step_h(start,finish) == Moves.step_v(start, finish)
  start_col, start_row = Board.square_to_coords start
  end_col, end_row = Board.square_to_coords finish
  dirn_h = (end_row - start_row) / (end_row - start_row).abs
  dirn_v = (end_col - start_col) / (end_col - start_col).abs
  1.upto(Moves.step_h(start,finish)-1) do |i|
    square = Board.coords_to_square(start_col+(i*dirn_v), 
                                    start_row+(i*dirn_h))
    unless board[square] == nil
      return false 
    end
  end
  return true
end

.can_reach(board, piece, start, finish) ⇒ Object

Return true if given piece can move from start square to finish on given board.



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/chess_data/moves.rb', line 48

def Moves.can_reach board, piece, start, finish
  start = start.upcase
  finish = finish.upcase
  case piece
  when "K", "k" then Moves.king_can_reach start, finish
  when "Q", "q" then Moves.queen_can_reach board, start, finish
  when "R", "r" then Moves.rook_can_reach board, start, finish
  when "B", "b" then Moves.bishop_can_reach board, start,finish
  when "N", "n" then Moves.knight_can_reach start, finish
  end
end

.king_can_reach(start, finish) ⇒ Object



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

def Moves.king_can_reach start, finish
  Moves.step_h(start, finish) <= 1 && Moves.step_v(start, finish) <= 1
end

.king_left_in_check(board, piece, start, finish) ⇒ Object

Return true if moving the giving piece from start to finish will leave the moving side’s king in check.



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/chess_data/moves.rb', line 64

def Moves.king_left_in_check board, piece, start, finish
  test_board = board.clone
  test_board[start] = nil
  test_board[finish] = piece

  if board.to_move == "w"
    test_board.white_king_in_check?
  else
    test_board.black_king_in_check?
  end
end

.knight_can_reach(start, finish) ⇒ Object



122
123
124
125
126
# File 'lib/chess_data/moves.rb', line 122

def Moves.knight_can_reach start, finish
  h = Moves.step_h start, finish
  v = Moves.step_v start, finish
  return (h == 2 && v == 1) || (h == 1 && v == 2)
end

.new_move(string) ⇒ Object

Returns an instance of the appropriate move type.

string

a move read from a PGN file.



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

def Moves.new_move string
  case string
  when MatchKingsideCastles then KingsideCastles.new
  when MatchQueensideCastles then QueensideCastles.new
  when MatchPieceMove then PieceMove.new string
  when MatchPawnCapture then PawnCapture.new string
  when MatchPromotionPawnMove then PromotionPawnMove.new string
  when MatchSimplePawnMove then SimplePawnMove.new string
  when MatchPromotionPawnCapture then PromotionPawnCapture.new string
  else raise InvalidMoveError.new("Invalid move: #{string}")
  end
end

.queen_can_reach(board, start, finish) ⇒ Object



80
81
82
83
# File 'lib/chess_data/moves.rb', line 80

def Moves.queen_can_reach board, start,finish
  Moves.rook_can_reach(board, start, finish) ||
    Moves.bishop_can_reach(board, start, finish)
end

.rook_can_reach(board, start, finish) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/chess_data/moves.rb', line 85

def Moves.rook_can_reach board, start, finish
  start_col, start_row = Board.square_to_coords start
  end_col, end_row = Board.square_to_coords finish
  if start_col == end_col # moving along column
    row_1 = [start_row, end_row].min + 1
    row_2 = [start_row, end_row].max - 1
    row_1.upto(row_2) do |row|
      return false unless board[Board.coords_to_square(start_col, row)] == nil
    end
  elsif start_row == end_row # moving along row
    col_1 = [start_col, end_col].min + 1
    col_2 = [start_col, end_col].max - 1
    col_1.upto(col_2) do |col|
      return false unless board[Board.coords_to_square(col, start_row)] == nil
    end
  else
    return false
  end
  return true
end

.step_h(start, finish) ⇒ Object

Return size of horizontal gap between start and finish



129
130
131
# File 'lib/chess_data/moves.rb', line 129

def Moves.step_h start, finish
  (start.bytes[0] - finish.bytes[0]).abs
end

.step_v(start, finish) ⇒ Object

Return size of vertical gap between start and finish



134
135
136
# File 'lib/chess_data/moves.rb', line 134

def Moves.step_v start, finish
  (start.bytes[1] - finish.bytes[1]).abs
end