Closed LooveToLoose closed 1 year ago
public Move Think(Board board, Timer timer)
{
Console.WriteLine(board.ZobristKey);
// My Calculation
board.MakeMove(bestMove);
if (board.IsDraw())
Console.WriteLine("ABOUT TO MAKE A MOVE THAT RESULTS IN A DRAW. BUT WHY???");
board.UndoMove(bestMove);
Console.WriteLine(board.ZobristKey);
return bestMove;
}
ZobristKeys match up as well, so the board is definitely reset correctly.
Hi, I'm struggling to reproduce this issue. Would you be able to share a position and some more code for reproducing? Here's a simple test for example that shows IsDraw working for stalemate/repetition/insufficient material.
using ChessChallenge.API;
using System;
public class MyBot : IChessBot
{
public Move Think(Board board, Timer timer)
{
Console.WriteLine("Testing draw...");
// Stalemate test
Board testBoard = Board.CreateBoardFromFEN("3k4/8/3K4/8/8/8/8/4Q3 w - - 0 1");
Move stalemateMove = new Move("e1e6", testBoard);
testBoard.MakeMove(stalemateMove);
if (testBoard.IsDraw())
{
Console.WriteLine("Move enters stalemate");
}
// Repetition test
testBoard = Board.CreateBoardFromFEN("3k4/8/3K4/8/8/8/8/4Q3 w - - 0 1");
testBoard.MakeMove(new Move("e1e2", testBoard));
testBoard.MakeMove(new Move("d8c8", testBoard));
testBoard.MakeMove(new Move("d6c6", testBoard));
testBoard.MakeMove(new Move("c8d8", testBoard));
Move repeatedPositionMove = new Move("c6d6", testBoard);
testBoard.MakeMove(repeatedPositionMove);
// Note: this function will return true if the same position has occurred twice on the board
// (rather than 3 times, which is when the game is actually drawn).
// This quirk is to help bots avoid repeating positions unnecessarily.
if (testBoard.IsDraw())
{
Console.WriteLine("Move enters repeated position");
}
// Insufficient material test
testBoard = Board.CreateBoardFromFEN("3k4/8/3K4/8/8/8/8/4Q3 w - - 0 1");
testBoard.MakeMove(new Move("e1e8", testBoard));
testBoard.MakeMove(new Move("d8e8", testBoard));
if (testBoard.IsDraw())
{
Console.WriteLine("Move enters insufficient material draw");
}
// Return anything
return board.GetLegalMoves()[0];
}
}
Hey, thanks for having a look. Here is how to reproduce it.
1) Copy this into MyBot:
using ChessChallenge.API;
using System;
public class MyBot : IChessBot
{
const int maxSearchDepth = 10;
int defaultSearchDepth = 4;
Move[][] allPossibleMoves = new Move[maxSearchDepth][];
Move bestMove;
public MyBot()
{
for (int i = 0; i < maxSearchDepth; i++) {
allPossibleMoves[i] = new Move[218];
}
}
public Move Think(Board board, Timer timer)
{
Console.WriteLine(board.ZobristKey);
Span<Move> moves = allPossibleMoves[defaultSearchDepth].AsSpan();
moves.Clear();
board.GetLegalMovesNonAlloc(ref moves);
bestMove = moves[0];
MoveCalculation(board, defaultSearchDepth, true);
board.MakeMove(bestMove);
if (board.IsDraw())
Console.WriteLine("ABOUT TO MAKE A MOVE THAT RESULTS IN A DRAW.");
board.UndoMove(bestMove);
Console.WriteLine(board.ZobristKey);
return bestMove;
}
public float MoveCalculation(Board board, int depthleft, bool setBestMove)
{
if (depthleft == 0)
return EvaluatePosition(board);
Span<Move> moves = allPossibleMoves[depthleft].AsSpan();
board.GetLegalMovesNonAlloc(ref moves);
float bestScore = float.MinValue;
foreach (Move move in moves) {
board.MakeMove(move);
float score = -MoveCalculation(board, depthleft - 1, false);
board.UndoMove(move);
if (score > bestScore)
{
bestScore = score;
if (setBestMove)
{
bestMove = move;
}
}
}
return bestScore;
}
public float EvaluatePosition(Board board)
{
float evaluation = 0;
// If draw:
if (board.IsDraw())
return float.MaxValue; // Essentially treat being in a draw as a win if it is your turn, making sure the opponent should never allow a position where a draw is possible.
// If checkmate:
if (board.IsInCheckmate())
return float.MinValue; // Very bad outcome for the player who is checkmated so assigning a very negative score.
return evaluation;
}
}
2) Play a MyBot vs MyBot match
3) Outcome: The match results in a draw within only a few moves but we never get the "ABOUT TO MAKE A MOVE THAT RESULTS IN A DRAW" debug message. (So as far as I am aware it is only the draw by repetition that is not being detected, but that is usually the only way I draw to be honest.)
I am currently having the same issue where it is impossible for my ai to detect a draw. I directly test for the board position after a move being a draw before making that move and it will never return true regardless of the outcome of a match.
it is literally just
makemove- detect if draw- this never goes off return move-
Thanks for bringing this to my attention @LooveToLoose, I have just uploaded a patch for this bug. Please note -- in case you haven't seen it in the docs -- that you will get the 'results in draw' message one move early, but this is intended behaviour in this API:
Note: this function will return true if the same position has occurred twice on the board (rather than 3 times,
which is when the game is actually drawn). This quirk is to help bots avoid repeating positions unnecessarily.
One move early makes perfect sense cause the AIs will just keep spinning in circles otherwise anyways. Excellent.
I just tested it out and it now works as expected. So I can confirm that the issues has been resolved! Thanks a lot.
I hope you know how much joy you bring people with this little competition. This is so much fun. I am totally addicted. Haha. Thanks agian. Keep up the great work! <3
How to reproduce in version 1.17:
Expected behaviour: Whenever the AI makes a move that results in a draw, we should see "ABOUT TO MAKE A MOVE THAT RESULTS IN A DRAW." in the console
Current behaviour: The debug message never shows up in the console even if the next turn results in a draw. The play-out altorithm catches the draw, but you can't check for a draw in the Think function. As it is not currently possible to detect a draw, my AIs love spinning in circles and producing one tie after another. :D
Human error? I'm wondering if there is anything on my end that I might be doing wrong? If you have any ideas, please let me know, but I think the code example shown above is fairly waterproof, right? We should see the debug message if the game is about to result in a draw, but we don't.
Thanks for having a look! :)