Files
2025-05-02 18:03:19 -05:00

198 lines
8.4 KiB
Fortran

! ============================================
! Module: Make_Unmake
! Purpose: Apply and revert moves on the board
! ============================================
MODULE Make_Unmake
USE Chess_Types
USE Board_Utils
IMPLICIT NONE
PRIVATE
PUBLIC :: make_move, unmake_move
CONTAINS
! --- Make Move ---
SUBROUTINE make_move(board, move, unmake_info)
TYPE(Board_Type), INTENT(INOUT) :: board
TYPE(Move_Type), INTENT(IN) :: move
TYPE(UnmakeInfo_Type), INTENT(OUT) :: unmake_info
INTEGER :: r_from, f_from, r_to, f_to, player_color, opponent_color
INTEGER :: piece_moved, color_moved, r_capture, back_rank
TYPE(Square_Type) :: from_sq, to_sq
player_color = board%current_player
opponent_color = get_opponent_color(player_color)
from_sq = move%from_sq
to_sq = move%to_sq
r_from = from_sq%rank; f_from = from_sq%file
r_to = to_sq%rank; f_to = to_sq%file
! 1. Store info for unmake
unmake_info%prev_ep_target_present = board%ep_target_present
unmake_info%prev_ep_target_sq = board%ep_target_sq
unmake_info%prev_wc_k = board%wc_k
unmake_info%prev_wc_q = board%wc_q
unmake_info%prev_bc_k = board%bc_k
unmake_info%prev_bc_q = board%bc_q
piece_moved = board%squares_piece(r_from, f_from)
color_moved = board%squares_color(r_from, f_from)
IF (move%is_en_passant) THEN
unmake_info%captured_piece_type = PAWN
unmake_info%captured_piece_color = opponent_color
IF (player_color == WHITE) THEN
r_capture = r_to - 1
ELSE
r_capture = r_to + 1
END IF
unmake_info%captured_sq = file_rank_to_sq(f_to, r_capture)
! Remove the captured pawn
board%squares_piece(r_capture, f_to) = NO_PIECE
board%squares_color(r_capture, f_to) = NO_COLOR
ELSE IF (move%is_castling) THEN
unmake_info%captured_piece_type = NO_PIECE
unmake_info%captured_piece_color = NO_COLOR
unmake_info%captured_sq%rank = 0 ! Not used
ELSE
unmake_info%captured_piece_type = board%squares_piece(r_to, f_to)
unmake_info%captured_piece_color = board%squares_color(r_to, f_to)
unmake_info%captured_sq = to_sq ! Capture happens on 'to' square
END IF
! 2. Update Squares
! Clear 'from' square
board%squares_piece(r_from, f_from) = NO_PIECE
board%squares_color(r_from, f_from) = NO_COLOR
IF (move%is_castling) THEN
board%squares_piece(r_to, f_to) = KING
board%squares_color(r_to, f_to) = player_color
! Move the rook
IF (f_to == 7) THEN ! Kingside (g file)
board%squares_piece(r_from, 8) = NO_PIECE; board%squares_color(r_from, 8) = NO_COLOR
board%squares_piece(r_from, 6) = ROOK; board%squares_color(r_from, 6) = player_color
ELSE ! Queenside (f_to == 3, c file)
board%squares_piece(r_from, 1) = NO_PIECE; board%squares_color(r_from, 1) = NO_COLOR
board%squares_piece(r_from, 4) = ROOK; board%squares_color(r_from, 4) = player_color
END IF
ELSE
! Place moving piece (handle promotion)
IF (move%promotion_piece /= NO_PIECE) THEN
board%squares_piece(r_to, f_to) = move%promotion_piece
ELSE
board%squares_piece(r_to, f_to) = piece_moved
END IF
board%squares_color(r_to, f_to) = color_moved
END IF
! 3. Update EP Target
board%ep_target_present = .FALSE.
IF (piece_moved == PAWN .AND. ABS(r_to - r_from) == 2) THEN
board%ep_target_present = .TRUE.
board%ep_target_sq%rank = (r_to + r_from) / 2
board%ep_target_sq%file = f_from
END IF
! 4. Update Castling Rights
IF (piece_moved == KING) THEN
IF (player_color == WHITE) THEN
board%wc_k = .FALSE.; board%wc_q = .FALSE.
ELSE
board%bc_k = .FALSE.; board%bc_q = .FALSE.
END IF
END IF
IF (piece_moved == ROOK) THEN
IF (player_color == WHITE) THEN
IF (r_from == 1 .AND. f_from == 1) board%wc_q = .FALSE.
IF (r_from == 1 .AND. f_from == 8) board%wc_k = .FALSE.
ELSE
IF (r_from == 8 .AND. f_from == 1) board%bc_q = .FALSE.
IF (r_from == 8 .AND. f_from == 8) board%bc_k = .FALSE.
END IF
END IF
! Rook captured on home square
IF (unmake_info%captured_piece_type == ROOK) THEN
IF (unmake_info%captured_piece_color == WHITE) THEN
IF (r_to == 1 .AND. f_to == 1) board%wc_q = .FALSE.
IF (r_to == 1 .AND. f_to == 8) board%wc_k = .FALSE.
ELSE ! Black rook captured
IF (r_to == 8 .AND. f_to == 1) board%bc_q = .FALSE.
IF (r_to == 8 .AND. f_to == 8) board%bc_k = .FALSE.
END IF
END IF
! 5. Switch Player
board%current_player = opponent_color
END SUBROUTINE make_move
! --- Unmake Move ---
SUBROUTINE unmake_move(board, move, unmake_info)
TYPE(Board_Type), INTENT(INOUT) :: board
TYPE(Move_Type), INTENT(IN) :: move
TYPE(UnmakeInfo_Type), INTENT(IN) :: unmake_info
INTEGER :: r_from, f_from, r_to, f_to, player_color, opponent_color
INTEGER :: piece_to_restore, color_to_restore
! 1. Switch Player Back
board%current_player = get_opponent_color(board%current_player)
player_color = board%current_player ! Color of player who made the move being unmade
! 2. Restore Board State
board%ep_target_present = unmake_info%prev_ep_target_present
board%ep_target_sq = unmake_info%prev_ep_target_sq
board%wc_k = unmake_info%prev_wc_k
board%wc_q = unmake_info%prev_wc_q
board%bc_k = unmake_info%prev_bc_k
board%bc_q = unmake_info%prev_bc_q
! 3. Reverse Piece Movements
r_from = move%from_sq%rank; f_from = move%from_sq%file
r_to = move%to_sq%rank; f_to = move%to_sq%file
! Determine the piece type that moved (was it a pawn before promotion?)
IF (move%promotion_piece /= NO_PIECE) THEN
piece_to_restore = PAWN
ELSE IF (move%is_castling) THEN
piece_to_restore = KING ! King moved during castling
ELSE
! Get the piece from the 'to' square (it must be there after make_move)
piece_to_restore = board%squares_piece(r_to, f_to)
END IF
color_to_restore = player_color
! Put the piece back on 'from' square
board%squares_piece(r_from, f_from) = piece_to_restore
board%squares_color(r_from, f_from) = color_to_restore
! Restore 'to' square (and potentially captured piece / EP pawn)
IF (move%is_castling) THEN
board%squares_piece(r_to, f_to) = NO_PIECE ! Clear king's landing sq
board%squares_color(r_to, f_to) = NO_COLOR
! Put rook back
IF (f_to == 7) THEN ! Kingside (g file)
board%squares_piece(r_from, 6) = NO_PIECE; board%squares_color(r_from, 6) = NO_COLOR
board%squares_piece(r_from, 8) = ROOK; board%squares_color(r_from, 8) = player_color
ELSE ! Queenside (f_to == 3, c file)
board%squares_piece(r_from, 4) = NO_PIECE; board%squares_color(r_from, 4) = NO_COLOR
board%squares_piece(r_from, 1) = ROOK; board%squares_color(r_from, 1) = player_color
END IF
ELSE IF (move%is_en_passant) THEN
board%squares_piece(r_to, f_to) = NO_PIECE ! Clear EP landing sq
board%squares_color(r_to, f_to) = NO_COLOR
! Put captured pawn back
board%squares_piece(unmake_info%captured_sq%rank, unmake_info%captured_sq%file) = PAWN
board%squares_color(unmake_info%captured_sq%rank, unmake_info%captured_sq%file) = unmake_info%captured_piece_color
ELSE
! Restore whatever was on the 'to' square (captured piece or nothing)
board%squares_piece(r_to, f_to) = unmake_info%captured_piece_type
board%squares_color(r_to, f_to) = unmake_info%captured_piece_color
END IF
END SUBROUTINE unmake_move
END MODULE Make_Unmake