Skip to content

Commit

Permalink
fix: consider threath not legal move for in_check?
Browse files Browse the repository at this point in the history
if i got this right, a king is still in check, even if the
potential move would leave your own king in check.
  • Loading branch information
Roland Studer committed Dec 27, 2021
1 parent 26bbde7 commit 2fc7c37
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 8 deletions.
15 changes: 10 additions & 5 deletions lib/board.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ def legal_target_positions_for(position)
end.flatten
end

def threatening_positions_for(position)
piece = get(position).piece
piece.move_types.map do |type|
type.new(self, position).threatening_positions
end.flatten
end

def move(origin, target)
move_type = find_move_type(origin, target)
current_move = move_type.new(self, origin, target)
Expand All @@ -54,14 +61,13 @@ def in_check?(color)
opposite_color = color == :black ? :white : :black
return false unless king_square(color)

(squares_occupied_by(opposite_color) - [king_square(opposite_color)]).any? do |square|
legal_target_positions_for(square.position).any? { |position| position == king_square(color).position }
squares_occupied_by(opposite_color).any? do |square|
threatening_positions_for(square.position).any? { |position| position == king_square(color).position }
end
end

def in_checkmate?(color)
king_square = find_king(color)
return false unless king_square
return false unless king_square(color)
return false unless in_check?(color)

squares_occupied_by(color).map do |square|
Expand Down Expand Up @@ -100,7 +106,6 @@ def create_squares
def king_square(color)
@squares.find { |square| square.piece == King.new(color) }
end
alias find_king king_square

def find_move_type(origin, target)
origin = Position.parse(origin)
Expand Down
11 changes: 9 additions & 2 deletions lib/move/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ def legal_target_positions
positions
end

# to check for check, an attack move that leaves your own king in check, is still relevant
def threatening_positions
positions = position_candidates
positions -= target_positions_that_are_occupied_by_friend
positions
end

private

def legal_target_positions_in_line(positions)
Expand Down Expand Up @@ -57,11 +64,11 @@ def occupied_by_enemy?(target_position)
end

def target_positions_that_are_occupied_by_friend
position_candidates.select { |target_position| occupied_by_friend?(target_position) }
position_candidates.compact.select { |target_position| occupied_by_friend?(target_position) }
end

def target_positions_that_leave_check_for_own_king
position_candidates.select do |target_position|
position_candidates.compact.select do |target_position|
temp_board = Marshal.load(Marshal.dump(@board))
temp_board.move(position, target_position)
temp_board.in_check?(piece.color)
Expand Down
2 changes: 1 addition & 1 deletion lib/piece/pawn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def black_move_types

def white_move_types
[
Move::Move::OneUp,
Move::OneUp,
(Move::TwoUp unless moved?),
Move::UpDiagonalCapture
].compact
Expand Down
5 changes: 5 additions & 0 deletions test/piece/king_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@ def test_black_king_can_castle
assert_equal Rook.new(:black), board.get("C8").piece
assert_equal King.new(:black), board.get("B8").piece
end

def test_king_cannot_castle_if_fields_are_threatened
board = Board.from_fen("r2qkbnr/p2ppppp/8/8/8/8/P2PPPPP/2RQKBNR w Kkq - 0 1")
assert !board.legal_target_positions_for("E8").include?(Position.parse("B8"))
end
end
end

0 comments on commit 2fc7c37

Please sign in to comment.