Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No Checkmate detection on pawn promotion #8

Open
Skyfighter64 opened this issue Jan 12, 2022 · 6 comments
Open

No Checkmate detection on pawn promotion #8

Skyfighter64 opened this issue Jan 12, 2022 · 6 comments

Comments

@Skyfighter64
Copy link

Checkmates are not detected if they happen within a pawn promotion move.

Situation:

Board:

-- bK -- -- -- --
-- -- -- wR wp --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- wK -- -- --

White's turn.
Valid moves: ['Ra5', 'Rd2', 'Rc5', 'Kc2', 'e6', 'Rd1', 'Kd2', 'Rb5', 'Rd4', 'Kb1', 'Kd1', 'Rd3', 'Kb2', 'Rd6']
White makes move: 'e6'

Board:

-- bK -- -- wR --
-- -- -- wR -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- wK -- -- --

Expected Behaviour:

Pawn gets promoted to Rook. Black King is in Checkmate (gameState.checkMate evaluates to True)

Actual Behaviour:

Pawn gets promoted to Rook. Black King is not in Checkmate (gameState.checkMate evaluates to False)

@coolusaHD
Copy link
Contributor

An easy fix would be to add

# pawn promotion
        if move.isPawnPromotion:  # auto promotion to queen
            # promotedPiece = input("Promote to Q, R, B or N:")
            self.board[move.endRC] = move.pieceMoved[0] + "R"  # promotedPiece
            #+++new+++
            #change player
            self.whiteToMove = not self.whiteToMove
            #check for valid moves
            self.getValidMoves()

@Skyfighter64 Maybe you can test it in your descripted environment ?

After that it should update the checkMate boolean because there are bo possible moves for the enemy

@toddChavezz
Copy link
Collaborator

toddChavezz commented Jan 14, 2022

@Skyfighter64 I can't reproduce this behaviour. I checked with the position you posted (except the pawn was one row farther back, i.e. on e4, and the King on a6, one row farther to the right) and tracked game_state.checkMate and game_state.getValidMoves. I changed the board slightly to have one move before actual check mate happened but the behaviour was identical when I used your exact position.
Command:
python ChessMain.py --agent1 Human --agent2 /tmp/ai_competition/student_agents/expert.py --output_file /tmp/chess/out.txt --verbose --num_games 1 --time_control 5 --use_gui
Output:

White to move:
valid moves:  ['Kb1', 'Re5', 'Kc2', 'Ra5', 'Rf5', 'e5', 'Rd2', 'Rb5', 'Kb2', 'Kd1', 'Rd3', 'Rd6', 'Rd1', 'Rd4', 'Kd2', 'Rc5']
Black in checkmate is  False
Black to move:
valid moves:  ['Kb6']
Black in checkmate is  False
Black's move: Kb6
Current Depth is: 6
The Score this move has is: -10000

White to move:
valid moves:  ['Kc2', 'Rd3', 'Kd2', 'Rd6', 'Rb5', 'Kb1', 'Rd1', 'Kb2', 'Kd1', 'Ra5', 'Rc5', 'e6', 'Rd4', 'Rd2']
Black in checkmate is  False
Black to move:
valid moves:  []
Black in checkmate is  True
Final Results:
{'Draw by 50 move rule': 0, 'Draw by threefold position repetition': 0, 'Black wins by checkmate': 0, 'White wins by checkmate': 1, 'Black wins on time': 0, 'White wins on time': 0, 'Draw by insufficient material': 0, 'White wins by illegal move': 0, 'Black wins by illegal move': 0}

Here, I, as the white human player, I played e4, then black played the only move Kb6, I player e6=R#. Also, the output is semantically identical when agent2 is Human and agent1 the AI. The AI played the exact same moves.

So as you can see, it understands that it is in checkmate (game_state.checkMate evaluates to True) and there are no valid moves to make.
Where do you check game_state.checkMate with erroneous result? Was this the behaviour you meant? Did you maybe do some changes yourself to the code in ChessEngine or ChessMain?

@Skyfighter64
Copy link
Author

I just realized that I used an old engine version. Will try to replicate with the newest version later.

@Skyfighter64
Copy link
Author

Skyfighter64 commented Jan 14, 2022

Retested with the most current engine with no modifications, the problem seems to persist:

Results:

>-- Start Testing --<

Board:
-- bK -- -- -- --
-- -- -- wR wp --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- wK -- -- --

Valid moves: ['Rd3', 'Rd2', 'Rd1', 'Rc5', 'Rb5', 'Rd6', 'Ra5', 'Kd1', 'Rd4', 'Kd2', 'Kb2', 'Kc2', 'Kb1', 'e6']

Made move: 'e6'

Board:
-- bK -- -- wR --
-- -- -- wR -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- -- -- -- --
-- -- wK -- -- --

Checkmate? False

>-- Testing Complete --<

Code:

Here is the code I used for testing:

from ChessEngine import *

if __name__ == '__main__':

    print('\n>-- Start Testing --<\n')

    # create a new testing state
    testState = GameState()
    # set the color of this player
    testState.whiteToMove = True
    #testAgent.isWhite = testState.whiteToMove

    #intialize the board with the test state
    testState.board = ['--', 'bK', '--', '--', '--', '--',
                       '--', '--', '--', 'wR', 'wp', '--',
                       '--', '--', '--', '--', '--', '--',
                       '--', '--', '--', '--', '--', '--',
                       '--', '--', '--', '--', '--', '--',
                       '--', '--', 'wK', '--', '--', '--']

    # print out the current state
    print('Board:\n%s' %(str(testState)))
    print("Valid moves: " + str([str(i) for i in testState.getValidMoves()]))

    # select the 'e6' move and execute it
    for i in testState.getValidMoves():
        if str(i) == 'e6':
            testState.makeMove(i)
            print("Made move: \'%s\'\n" %  (str(i)))
            break

    # print out the current board
    print('Board:\n%s' %(str(testState)))
    # check if the current game state is a checkmate
    # this should evaluate to True
    print("Checkmate? " + str(testState.checkMate))


    print('\n>-- Testing Complete --<\n')

Execute:

Save in a file ('testMain.py')

python3 testMain.py

@Skyfighter64
Copy link
Author

Skyfighter64 commented Jan 14, 2022

I just quickly threw together a game testing environment:

Testing environment

testMain.py:

import ChessMain
from ChessEngine import *
import sys
import argparse

def ParseArgs():
        parser = argparse.ArgumentParser()
        parser.add_argument('--agent1', type=str, required=True,
                            help='Either path to the .py file containing your agent or "MrRandom".')
        parser.add_argument('--agent2', type=str, required=True,
                            help='See --agent_one.')
        parser.add_argument('--output_file', type=str, default=None,
                            help='File to save results to. If not given, all output will be printed to terminal only.'
                                 'This file will be overwritten, if it exists.')
        parser.add_argument('--verbose', default=False, action='store_true',
                            help='Whether the output file only contains the final result or all moves.')
        parser.add_argument('--use_gui', default=False, action='store_true',
                            help='Whether the output file only contains the final result or all moves.')
        parser.add_argument('--num_games', type=int, default=1,
                            help='How many games you want to play with this settings and agents.'
                                 'Agents do NOT switch sides after each game.')
        parser.add_argument('--time_control', type=int, default=20,
                            help='How many seconds per move each player has.')
        parser.add_argument('--evaluation', default=False, action='store_true',
                            help="Sets graphics driver to 'dummy', so that this runs on a server without optical output.")
        return parser.parse_args()



if __name__ == '__main__':
    # modfy arguments to start a game
    sys.argv = 'testMain.py --agent1 Human --agent2 Agent1 --output_file out.txt --verbose --num_games 1 --time_control 20 --use_gui'.split(' ')
    testBoard = ['--', 'bK', '--', '--', '--', '--',
                 '--', '--', '--', '--', 'wR', 'wp',
                 '--', '--', '--', '--', '--', '--',
                 '--', '--', '--', '--', '--', '--',
                 '--', '--', '--', '--', '--', '--',
                 '--', '--', 'wK', '--', '--', '--']
    # create a new game state for testing
    GameState.board = testBoard
    print(GameState.board)

    # start the actual game
    ChessMain.main(ParseArgs())
    print('\n>-- Testing Complete --<\n')

Changes in ChessMain.py:

Change ChessMain.py, Line 144-147:
From:

    game_state = ChessEngine.GameState()
    valid_moves = game_state.getValidMoves()

To:

    game_state = ChessEngine.GameState()

    # changes for testing
    if hasattr(ChessEngine.GameState, 'board'):
        game_state.board = ChessEngine.GameState.board
    # end changes

    valid_moves = game_state.getValidMoves()

Execute:

1.:

python3  testMain.py
  1. Move the pawn up.

Results

In this case the checkmate is detected by the ChessEngine itself (showing on screen, game exits).
Imo, the problem persists though as the agent itself can't identify the move as checkmate because of the results of the previous tests.

@Skyfighter64
Copy link
Author

An easy fix would be to add

# pawn promotion
        if move.isPawnPromotion:  # auto promotion to queen
            # promotedPiece = input("Promote to Q, R, B or N:")
            self.board[move.endRC] = move.pieceMoved[0] + "R"  # promotedPiece
            #+++new+++
            #change player
            self.whiteToMove = not self.whiteToMove
            #check for valid moves
            self.getValidMoves()

@Skyfighter64 Maybe you can test it in your descripted environment ?

After that it should update the checkMate boolean because there are bo possible moves for the enemy

Just tried, did not change the outcome of gameState.checkMate = False

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants