Tiny Chess Bot Coding Challenge

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Tiny Chess Bot Coding Challenge

Post by leanchess »

PeSTO evaluation:

Code: Select all

    ulong[] pst = {
        0x04BE53FA54055052,0x30C0140E5C47C052,0x2D41E3FA46C97852,0x1DC0D42052090052,
        0x0943C438550C7052,0x1442D3CC50C78052,0x2642C3F85D0A1052,0x2BC2E41059473052,
        0x33BE93F054C840B4,0x24BDA3FA5F4940D8,0x1B3FC42E56CCC88F,0x21C02436580BA8B1,
        0x213F145A62CB4096,0x2343A4406A0C78D0,0x1241D3EE5FCAC074,0x16C374124F8A0047,
        0x20BF43B05749104C,0x313F03E0648C6859,0x264083EE660BB06C,0x1D409402654C9071,
        0x1B41E3DC640D2893,0x2843941467CE908A,0x30430434648CD06B,0x1A43A3DA5ACBE83E,
        0x1CBE638A5A4A4044,0x1B3E63A45C8B105F,0x1F3F13C8600B2058,0x17BF13EE67CC3067,
        0x164003EA648BB069,0x18C12400648CB05E,0x1E3FF3AA5D0B1863,0x134023925ACB383B,
        0x0CBF837259CA2037,0x24BE73865E8AA850,0x17BF83A25E8B084D,0x11BF73B861CAF05E,
        0x0E3FF3CC63CB6863,0x0F3FD3AC5E4B2058,0x14C043C65DCB305C,0x0BBFE38C5C4A4839,
        0x1E3F33605B49D038,0x1E4033885F0A404E,0x1A3F639A5F0AE84E,0x0E3FF3985F0AD848,
        0x0F3FC3C05ECB2055,0x164033BA620B1055,0x1DC0F3B05FCB5073,0x17C063785DCA0846,
        0x25BDE3625C49A02F,0x28BF939A5F08E051,0x2140C3925F4A283E,0x054033A85B4A703B,
        0x0FC093B85D0A8043,0x1D4103D0608B186A,0x29BFE3AE638A1878,0x2940232C5B89F03C,
        0x1DC0039453074052,0x373EF3A05A89E052,0x2B3F83BC57C8B852,0x0A40B3DC56098052,
        0x293F23DA580A0052,0x173E83C85849A852,0x313E23705189F052,0x2C3CF3865609D052,
        0x0039F41A46C6F85E,0x13BBE4144507985E,0x1C3BE4244788605E,0x1C3C341E4847E85E,
        0x1FBC34184887D05E,0x2CBBB4184807F05E,0x273B24104606D05E,0x1CBBC40A4445B05E,
        0x1F39741648480110,0x2DBBC41A4948890B,0x2C3C841A4C0800FC,0x2DBD14164748B8E4,
        0x2DBE23FA498880F1,0x383C1406470800E2,0x30BC641049480903,0x2ABA840646C72919,
        0x2A39440E4AC808BC,0x2DBAE40E484828C2,0x30BB140E4A4918B3,0x2CBD940A4A0910A1,
        0x2F3D740849C8C096,0x3BBCB3FA4BC88093,0x3B3BB3F64A4830B0,0x2BBB13FA4B4780B2,
        0x213AB4084988407E,0x303BE4064C88E076,0x313C041A4D49786B,0x32BD54024C897863,
        0x323E14044DC9785C,0x35BD04024CC92062,0x323E13FE4B09086F,0x26BCC4044AC8386F,
        0x1C39640648C8386B,0x233C440A4B089867,0x2FBBB4104D89485B,0x313D74084F099057,
        0x32BC73F64C094857,0x30BCA3F44CC95056,0x29BCF3F04988E861,0x1FBBF3EA4808385D,
        0x1BB983F847481062,0x23B8D4004988B065,0x2ABB73F64C48C058,0x2FBAE3FE4CC9405F,
        0x30BB13F24D89185E,0x2D3B93E84B08B059,0x28BB23F04888285D,0x20BAD3E046881856,
        0x17B923F446C7786B,0x1FB913F445C82866,0x2738A40048887866,0x2BB984044A08A068,
        0x2C3983EE4B48B86B,0x273913EE4808285E,0x22B843EA46881060,0x1CB883FA43876857,
        0x0AB873EE4487E05E,0x1438C4044807305E,0x1AB924064488105E,0x1FB7D3FE4908505E,
        0x173A33F64808185E,0x1E3883E64648385E,0x193944084907385E,0x0FB7F3D84606C85E
    };

    private int Eval(Board board)
    {
        int eval = 0, mg = 0, eg = 0;
        foreach (PieceList list in board.GetAllPieceLists())
        {
            foreach (Piece piece in list)
            {
                int square = piece.Square.Index ^ (piece.IsWhite ? 0x38 : 0),
                    type   = (int)piece.PieceType - 1,
                    mul    = piece.IsWhite ? 1 : -1;
                mg += mul * (int)(pst[square]      >> type * 11 & 0b11111111111);
                eg += mul * (int)(pst[square + 64] >> type * 11 & 0b11111111111);
                eval += 0x00042110 >> type * 4 & 0x0F;
            }
        }
        eval = eval < 24 ? eval : 24;
        return (mg * eval + eg * (24 - eval)) / 24 * (board.IsWhiteToMove ? 1 : -1);
    }
Full disclosure: I had a peek at Tyrant's bot, but I only pilfered the 7-token phase calculation; the compression is completely my own.

Unfortunately, there seems to be a bug somewhere, as the updated bot keeps getting checkmated. Can you help me find it?

Edit: Fixed the leftover cast to byte, hopefully that was the only problem.
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Tiny Chess Bot Coding Challenge

Post by leanchess »

I really liked Tyrant's decimal hack, but I didn't want lossy compression, so I came up with this:

Code: Select all

    decimal[] pst = {
          99927791398865075190759459m, 24314683367267918830413565475m, 34837249629793683262117283107m, 34849310663390464552575071779m,
       39182072503367623906333746211m, 55255950127465035742388962851m, 48425481169968618540411033635m, 35451260678817054809130286115m,
       38456707530455026827686600325m, 56496317649007913065297247913m, 54668422214349720662940118880m, 56547073349239246023297780610m,
       56588044932385270063932948071m, 69506682539092976179863020961m, 60234269058436263684080184901m, 52734045678935993945128605208m,
       52066756997727870820085430301m, 56462410909201772785358005034m, 60183484879280964088826088509m, 55328419861272029980093900866m,
       58418424773856887482467679076m, 73863595226693287053074442331m, 73205920469283690360481968188m, 53993690379423086792788726543m,
       40980878713682317329691352597m, 59595909483536162875868362800m, 60838779785476139251885849129m, 62746351281349685991308844088m,
       62156405110576176637311634490m, 66448082177110258344098982959m, 62156376369545486680561203508m, 47869319328771662366204017932m,
       34740394077340695515186633224m, 43517214750113898764879964961m, 58969733281143699909044516638m, 60894305629046621532465968175m,
       62712444615779940718132904756m, 60243808758146147145737878057m, 51590298371329725870233926701m, 39172183795101996281592848138m,
       34126193426122030512471314441m, 44003155484788803597555113503m, 52770238710938073607507718943m, 58938216096485590039020089625m,
       60183353132610763023263513126m, 55869858214687930706248251430m, 50282240485202276033248149572m, 40366555059565344469189957399m,
       29159907194525697882423331328m, 39061009511179431354550088226m, 48328691919291885783305460495m, 53933291130212894698237109260m,
       54552157442477465878928729620m, 48345531803659977346320873787m, 42743350444523370375870323017m, 35325456728994128988731773965m,
       13040061650476996578563472931m, 24812685688870557613442372131m, 32873811984302596560087706915m, 39012700182032922986141091363m,
       28582050283387819886333564451m, 37182272748296300014049463075m, 31021747735523208216270246947m, 19210315360566417197790564387m
    };

    int Eval(Board board)
    {
        long eval = 0, mg = 0, eg = 0;
        foreach (PieceList list in board.GetAllPieceLists())
        {
            foreach (Piece piece in list)
            {
                byte[] bytes = new byte[16];
                int type  = (int)piece.PieceType - 1,
                    mul   = piece.IsWhite ? 1 : -1,
                    shift = (byte)(0x292119110800 >> type * 8);
                new System.Numerics.BigInteger(pst[piece.Square.Index ^ (piece.IsWhite ? 0x38 : 0)]).TryWriteBytes(bytes, out _);
                long mask  = 0b0001111111_0011111111_0011111111_0011111111_0111111111_0011111111 >> type * 10 & 0b0111111111,
                     min   = 0x94648EA4A723 >> shift & mask;
                mg += mul * (BitConverter.ToInt64(bytes)      >> shift & mask - min);
                eg += mul * (BitConverter.ToInt64(bytes[6..]) >> shift & mask - min);
                eval += 0x00042110 >> type * 4 & 0x0F;
            }
        }
        eval = eval < 24 ? eval : 24;
        return (int)(mg * eval + eg * (24 - eval)) / 24 * (board.IsWhiteToMove ? 1 : -1);
    }

Thanks to some serious golfing, this is 10 tokens slimmer than my previous PeSTO implementation with zero loss of precision.

However, the performance is probably terrible due to multiple object allocations. The unpacking obviously needs to be extracted into the constructor, which is going to cost a few tokens. Nevertheless, it's been a fun exercise.
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Tiny Chess Bot Coding Challenge

Post by Mike Sherwin »

leanchess wrote: Sat Sep 02, 2023 2:53 pm I really liked Tyrant's decimal hack, but I didn't want lossy compression, so I came up with this:

Code: Select all

    decimal[] pst = {
          99927791398865075190759459m, 24314683367267918830413565475m, 34837249629793683262117283107m, 34849310663390464552575071779m,
       39182072503367623906333746211m, 55255950127465035742388962851m, 48425481169968618540411033635m, 35451260678817054809130286115m,
       38456707530455026827686600325m, 56496317649007913065297247913m, 54668422214349720662940118880m, 56547073349239246023297780610m,
       56588044932385270063932948071m, 69506682539092976179863020961m, 60234269058436263684080184901m, 52734045678935993945128605208m,
       52066756997727870820085430301m, 56462410909201772785358005034m, 60183484879280964088826088509m, 55328419861272029980093900866m,
       58418424773856887482467679076m, 73863595226693287053074442331m, 73205920469283690360481968188m, 53993690379423086792788726543m,
       40980878713682317329691352597m, 59595909483536162875868362800m, 60838779785476139251885849129m, 62746351281349685991308844088m,
       62156405110576176637311634490m, 66448082177110258344098982959m, 62156376369545486680561203508m, 47869319328771662366204017932m,
       34740394077340695515186633224m, 43517214750113898764879964961m, 58969733281143699909044516638m, 60894305629046621532465968175m,
       62712444615779940718132904756m, 60243808758146147145737878057m, 51590298371329725870233926701m, 39172183795101996281592848138m,
       34126193426122030512471314441m, 44003155484788803597555113503m, 52770238710938073607507718943m, 58938216096485590039020089625m,
       60183353132610763023263513126m, 55869858214687930706248251430m, 50282240485202276033248149572m, 40366555059565344469189957399m,
       29159907194525697882423331328m, 39061009511179431354550088226m, 48328691919291885783305460495m, 53933291130212894698237109260m,
       54552157442477465878928729620m, 48345531803659977346320873787m, 42743350444523370375870323017m, 35325456728994128988731773965m,
       13040061650476996578563472931m, 24812685688870557613442372131m, 32873811984302596560087706915m, 39012700182032922986141091363m,
       28582050283387819886333564451m, 37182272748296300014049463075m, 31021747735523208216270246947m, 19210315360566417197790564387m
    };

    int Eval(Board board)
    {
        long eval = 0, mg = 0, eg = 0;
        foreach (PieceList list in board.GetAllPieceLists())
        {
            foreach (Piece piece in list)
            {
                byte[] bytes = new byte[16];
                int type  = (int)piece.PieceType - 1,
                    mul   = piece.IsWhite ? 1 : -1,
                    shift = (byte)(0x292119110800 >> type * 8);
                new System.Numerics.BigInteger(pst[piece.Square.Index ^ (piece.IsWhite ? 0x38 : 0)]).TryWriteBytes(bytes, out _);
                long mask  = 0b0001111111_0011111111_0011111111_0011111111_0111111111_0011111111 >> type * 10 & 0b0111111111,
                     min   = 0x94648EA4A723 >> shift & mask;
                mg += mul * (BitConverter.ToInt64(bytes)      >> shift & mask - min);
                eg += mul * (BitConverter.ToInt64(bytes[6..]) >> shift & mask - min);
                eval += 0x00042110 >> type * 4 & 0x0F;
            }
        }
        eval = eval < 24 ? eval : 24;
        return (int)(mg * eval + eg * (24 - eval)) / 24 * (board.IsWhiteToMove ? 1 : -1);
    }

Thanks to some serious golfing, this is 10 tokens slimmer than my previous PeSTO implementation with zero loss of precision.

However, the performance is probably terrible due to multiple object allocations. The unpacking obviously needs to be extracted into the constructor, which is going to cost a few tokens. Nevertheless, it's been a fun exercise.
It is not clear if this is a recommendation, a try it and see or just a fun exercise. I'll try it and see. If PeSTO works it should raise the elo by several hundred points. I deleted TalkChess and TalkChess02 from the competition and entered a new version named iPlayChess. After 20 games it is 1177 elo. The next version iPlayChess02 smashes iPlayChess but I forget the score. I also did not enter 02 because 03 smashes 02 by an even greater margin. With only two people contributing from TalkChess I don't think it deserves TalkChess as its name. The code got all messed up at one point so I had to revert to an older code base before going forward again.

Edit: This code I'm moving to Evil Bot on my machine.
Edit2: 21 games just checkmated Ace v3 a 1418 rated opponent! iPlayChess now 1186 elo.

Code: Select all

using ChessChallenge.API;

public class MyBot : IChessBot
{
    int[] PieceValues = { 0, 100, 320, 330, 500, 900, 10000 };
    int CheckmateScore = 9999;
    int Depth;

    ulong[] pst = {
        0xE6F4B06438321400,0xEAF6B2643A341400,0xEAF2B2643A361400,0xEAF0B3653A361400,
        0xEAF0B3653A361400,0xEAF2B2643A361400,0xEAF6B2643A341400,0xE6F4B06438321400,
        0xEAF4B2633A341500,0xEAF4B4643D381600,0xF0F0B5643C3C1600,0xF0F0B4643C3D1000,
        0xF0F0B4643C3D1000,0xF0F0B4643C3C1600,0xEAF4B4643D381600,0xEAF4B2633A341500,
        0xEAEEB2633A361500,0xEEECB5643E3D1300,0xF4ECB5643E3E1200,0xF6ECB5643E3F1400,
        0xF6ECB5643E3F1400,0xF4ECB5643E3E1200,0xEEECB4643E3D1300,0xEAEEB2633A361500,
        0xEAECB4633A361400,0xEEEAB4643C3C1400,0xF6EAB5643E3F1400,0xF8E8B5643E401800,
        0xF8E8B5643E401800,0xF6EAB5643E3F1400,0xEEEAB4643C3C1400,0xEAECB3633A361400,
        0xEAEAB3633A361500,0xEEE8B4643D3D1500,0xF6E8B5643D3F1600,0xF8E6B5643E401900,
        0xF8E6B5643E401900,0xF6E8B5643D3F1600,0xEEE8B4643D3D1500,0xEAEAB3633A361500,
        0xEAEAB2633A361600,0xEEE8B4643C3C1600,0xF4E8B5643D3E1800,0xF6E6B5643E3F1A00,
        0xF6E6B5643E3F1A00,0xF4E8B5643D3E1800,0xEEE8B4643C3C1600,0xEAEAB2633A361600,
        0xEAEAB2653A341E00,0xECE8B4663C381E00,0xEEE8B4663C3C1E00,0xF0E6B4663C3C1E00,
        0xF0E6B4663C3C1E00,0xEEE8B4663C3C1E00,0xECE8B4663C381E00,0xEAEAB2653A341E00,
        0xE6EAB06438321400,0xE8E8B2643A341400,0xEAE8B2643A361400,0xECE6B3643A361400,
        0xECE6B3643A361400,0xEAE8B2643A361400,0xE8E8B2643A341400,0xE6EAB06438321400,
    };

    public Move Think(Board board, Timer timer)
    {
        Move bestMove = default;
        int alpha;
        int beta = CheckmateScore;
        int score;
        Move[] move = board.GetLegalMoves();
        for (Depth = 1; Depth < 99; Depth++)
        {
            alpha = -CheckmateScore;
            bestMove = default;
            for (int i = 0; i < move.Length; i++)
            {
                board.MakeMove(move[i]);
                if (board.IsInCheckmate())
                {
                    board.UndoMove(move[i]);
                    return move[i];
                }
                if (board.IsDraw())
                {
                    score = 0;
                }
                else score = -NegaMax(-beta, -alpha, Depth, board);
                board.UndoMove(move[i]);

                if (score > alpha)
                {
                    bestMove = move[i];
                    move[i] = move[0];
                    move[0] = bestMove;
                    alpha = score;
                }
            }
            if (timer.MillisecondsElapsedThisTurn > timer.MillisecondsRemaining / 100) break;
        }
        return bestMove;
    }

    private int NegaQ(int alpha, int beta, Board board)
    {
        int score;
        int eval = Eval(board);
        if (eval >= beta) return beta;
        if (eval > alpha) alpha = eval;
        Move[] move = board.GetLegalMoves(true);
        for (int i = 0; i < move.Length; i++)
        {
            Move tempMove;
            Piece capturedPiece1 = board.GetPiece(move[i].TargetSquare);
            int capturedPieceValue1 = PieceValues[(int)capturedPiece1.PieceType];
            for (int j = i + 1; j < move.Length; j++)
            {
                Piece capturedPiece2 = board.GetPiece(move[j].TargetSquare);
                int capturedPieceValue2 = PieceValues[(int)capturedPiece2.PieceType];
                if (capturedPieceValue2 > capturedPieceValue1)
                {
                    tempMove = move[i];
                    move[i] = move[j];
                    move[j] = tempMove;
                }
            }

            board.MakeMove(move[i]);
            if (board.IsInCheckmate())
            {
                board.UndoMove(move[i]);
                return CheckmateScore - board.PlyCount;
            }
            score = -NegaQ(-beta, -alpha, board);
            board.UndoMove(move[i]);

            if (score > alpha)
            {
                alpha = score;
                if (score >= beta)
                    return beta;
            }
        }
        return alpha;
    }

    private int NegaMax(int alpha, int beta, int depth, Board board)
    {
        int score;
        if (depth <= 0)
            return NegaQ(alpha, beta, board);
        int eval = Eval(board);
        int bestScore = -CheckmateScore;
        if (depth > 1 && eval - 10 >= beta && board.TrySkipTurn())
        {
            if (-NegaMax(-beta, -beta + 1, depth - 3 - depth / 4, board) >= beta)
            {
                board.UndoSkipTurn();
                return beta;
            }
            board.UndoSkipTurn();
        }
        Move[] move = board.GetLegalMoves();
        for (int i = 0; i < move.Length; i++)
        {
            Move tempMove;
            Piece capturedPiece1 = board.GetPiece(move[i].TargetSquare);
            int capturedPieceValue1 = PieceValues[(int)capturedPiece1.PieceType];
            for (int j = i + 1; j < move.Length; j++)
            {
                Piece capturedPiece2 = board.GetPiece(move[j].TargetSquare);
                int capturedPieceValue2 = PieceValues[(int)capturedPiece2.PieceType];
                if (capturedPieceValue2 > capturedPieceValue1)
                {
                    tempMove = move[i];
                    move[i] = move[j];
                    move[j] = tempMove;
                }
            }

            board.MakeMove(move[i]);
            if (board.IsInCheckmate())
            {
                board.UndoMove(move[i]);
                return CheckmateScore - board.PlyCount;
            }
            if (board.IsDraw())
                score = 0;
            else
                if (beta - alpha > 1)
            {
                score = -NegaMax(-alpha - 1, -alpha, depth - 2, board);
                if (score > alpha)
                    score = -NegaMax(-beta, -alpha, depth - 1, board);
            }
            else
            {
                score = -NegaMax(-beta, -alpha, depth - 1, board);
            }
            board.UndoMove(move[i]);

            if (score > alpha)
            {
                alpha = score;
                if (score >= beta)
                    return beta;
            }
        }
        return alpha;
    }

    int Eval(Board board)
    {
        int eval = 0, value;
        foreach (PieceList list in board.GetAllPieceLists())
            foreach (Piece piece in list)
            {
                value = (byte)(pst[piece.Square.Index ^ (piece.IsWhite ? 0 : 0x38)] >>
                    ((int)piece.PieceType << 3));
                eval -= (board.IsWhiteToMove ^ piece.IsWhite) ? value : -value;
            }
        return eval;
    }
}
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Tiny Chess Bot Coding Challenge

Post by leanchess »

Mike Sherwin wrote: Sat Sep 02, 2023 3:31 pm It is not clear if this is a recommendation, a try it and see or just a fun exercise. I'll try it and see. If PeSTO works it should raise the elo by several hundred points.

Look at my previous post. That's a recommendation.

I deleted TalkChess and TalkChess02 from the competition and entered a new version named iPlayChess. After 20 games it is 1177 elo. The next version iPlayChess02 smashes iPlayChess but I forget the score. I also did not enter 02 because 03 smashes 02 by an even greater margin.

I wouldn't trust the live ELO too much. My version using PeSTO is 1091 after 21 games.

With only two people contributing from TalkChess I don't think it deserves TalkChess as its name. The code got all messed up at one point so I had to revert to an older code base before going forward again.

Do you still want to collaborate? If you do, let's set up a repo and do it together. You seem to have a lot of chess expertise, which I lack, while I might help saving a few tokens (my current version stands at 648).
Koistinen
Posts: 29
Joined: Sun May 23, 2021 10:05 pm
Location: Stockholm, Sweden
Full name: Urban Koistinen

Re: Tiny Chess Bot Coding Challenge

Post by Koistinen »

The rules make a big thing about being allowed arbitrarily large identifiers.
Did anyone exploit the 511 length identifier limit through C-sharps reflection mechanism?
That way you would get 2*26+10+1 = 67 values would be equivalent to about 511*6 = 3066 bits.
One idea would be to write a suitable tiny Forth and then execute the identifiers.
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Tiny Chess Bot Coding Challenge

Post by leanchess »

Koistinen wrote: Sat Sep 02, 2023 4:37 pm The rules make a big thing about being allowed arbitrarily large identifiers.
Did anyone exploit the 511 length identifier limit through C-sharps reflection mechanism?
That way you would get 2*26+10+1 = 67 values would be equivalent to about 511*6 = 3066 bits.
One idea would be to write a suitable tiny Forth and then execute the identifiers.

Yeah, well, the organiser took that into account.
SebLague wrote: Only the following namespaces are allowed:
  • ChessChallenge.API
  • System
  • System.Numerics
  • System.Collections.Generic
  • System.Linq
    • You may not use the AsParallel() function
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Tiny Chess Bot Coding Challenge

Post by Mike Sherwin »

leanchess wrote: Sat Sep 02, 2023 3:54 pm
Mike Sherwin wrote: Sat Sep 02, 2023 3:31 pm It is not clear if this is a recommendation, a try it and see or just a fun exercise. I'll try it and see. If PeSTO works it should raise the elo by several hundred points.

Look at my previous post. That's a recommendation.

I deleted TalkChess and TalkChess02 from the competition and entered a new version named iPlayChess. After 20 games it is 1177 elo. The next version iPlayChess02 smashes iPlayChess but I forget the score. I also did not enter 02 because 03 smashes 02 by an even greater margin.

I wouldn't trust the live ELO too much. My version using PeSTO is 1091 after 21 games.

With only two people contributing from TalkChess I don't think it deserves TalkChess as its name. The code got all messed up at one point so I had to revert to an older code base before going forward again.

Do you still want to collaborate? If you do, let's set up a repo and do it together. You seem to have a lot of chess expertise, which I lack, while I might help saving a few tokens (my current version stands at 648).
I can't set up a repo because I don't have a cell phone and can't receive text messages. This is a collaborative effort. Or at least it is supposed to be. I didn't even want to be the lead on this. I just wanted to get the ball rolling and contribute what I can. I'm amazed that no one else has lifted a finger to help. And Ras don't blame it on C# as there are 238 authors and 727 bots competing and all are in C#! The problem is with the TalkChess membership. A decade and a half ago there were dozens of members willing to lend a hand. Today it is like wandering in a desert trying to get a drink of water from someone and there isn't anyone around despite there being 1285 views. This project could have been spectacular with the talent that reads here. Anyway, without your contribution we would not even be this far. PeSTO is cleaning house so far, +19 =0 -3 over Evil Bot (iPayChess03)!!! :D
You take the lead and I will help where I can?
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Tiny Chess Bot Coding Challenge

Post by Mike Sherwin »

Just a quick update. The PeSTO version iPlayChess v2 is now entered into the live play. It is rising quickly. So far +51 =3 -6 against the best non PeSTO version. 8-)
User avatar
leanchess
Posts: 181
Joined: Sun Dec 08, 2019 8:16 pm
Full name: Dmitry Shechtman

Re: Tiny Chess Bot Coding Challenge

Post by leanchess »

I'm looking at Tyrant's implementation, and can't wrap my head around the evaluation.

Code: Select all

        int Evaluate()
        {
            int middlegame = 0, endgame = 0, gamephase = 0, sideToMove = 2, piece, square;
            for (; --sideToMove >= 0; middlegame = -middlegame, endgame = -endgame)
                for (piece = -1; ++piece < 6;)
                    for (ulong mask = board.GetPieceBitboard((PieceType)piece + 1, sideToMove > 0); mask != 0;)
                    {
                        gamephase += 0x00042110 >> piece * 4 & 0x0F;
                        square = BitboardHelper.ClearAndGetIndexOfLSB(ref mask) ^ 56 * sideToMove;
                        middlegame += UnpackedPestoTables[square][piece];
                        endgame += UnpackedPestoTables[square][piece + 6];
                    }
            // Tempo bonus to help with aspiration windows
            return (middlegame * gamephase + endgame * (24 - gamephase)) / 24 * (board.IsWhiteToMove ? 1 : -1) + gamephase / 2;
        }

It is similar to mine (barring performance), with one key difference: the PST values are added directly to the accumulators regardless of their colour. Shouldn't they be negated for black?


Edit: I was looking at a buggy version. Here's the fixed one from V5 branch:

Code: Select all

    private int Evaluate()
    {
        int middlegame = 0, endgame = 0, gamephase = 0, sideToMove = 2;
        for (; --sideToMove >= 0;)
        {
            for (int piece = -1, square; ++piece < 6;)
                for (ulong mask = board.GetPieceBitboard((PieceType)piece + 1, sideToMove > 0); mask != 0;)
                {
                    gamephase += GamePhaseIncrement[piece];
                    square = BitboardHelper.ClearAndGetIndexOfLSB(ref mask) ^ 56 * sideToMove;
                    middlegame += UnpackedPestoTables[square][piece];
                    endgame += UnpackedPestoTables[square][piece + 6];
                }
            middlegame = -middlegame;
            endgame = -endgame;
        }
        return (middlegame * gamephase + endgame * (24 - gamephase)) / 24 * (board.IsWhiteToMove ? 1 : -1);
    }

Edit 2: I'm an idiot. The master version has the same negations inside the first for statement.
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Tiny Chess Bot Coding Challenge

Post by Mike Sherwin »

leanchess wrote: Sat Sep 02, 2023 6:02 pm I'm looking at Tyrant's implementation, and can't wrap my head around the evaluation.

Code: Select all

        int Evaluate()
        {
            int middlegame = 0, endgame = 0, gamephase = 0, sideToMove = 2, piece, square;
            for (; --sideToMove >= 0; middlegame = -middlegame, endgame = -endgame)
                for (piece = -1; ++piece < 6;)
                    for (ulong mask = board.GetPieceBitboard((PieceType)piece + 1, sideToMove > 0); mask != 0;)
                    {
                        gamephase += 0x00042110 >> piece * 4 & 0x0F;
                        square = BitboardHelper.ClearAndGetIndexOfLSB(ref mask) ^ 56 * sideToMove;
                        middlegame += UnpackedPestoTables[square][piece];
                        endgame += UnpackedPestoTables[square][piece + 6];
                    }
            // Tempo bonus to help with aspiration windows
            return (middlegame * gamephase + endgame * (24 - gamephase)) / 24 * (board.IsWhiteToMove ? 1 : -1) + gamephase / 2;
        }

It is similar to mine (barring performance), with one key difference: the PST values are added directly to the accumulators regardless of their colour. Shouldn't they be negated for black?


Edit: I was looking at a buggy version. Here's the fixed one from V5 branch:

Code: Select all

    private int Evaluate()
    {
        int middlegame = 0, endgame = 0, gamephase = 0, sideToMove = 2;
        for (; --sideToMove >= 0;)
        {
            for (int piece = -1, square; ++piece < 6;)
                for (ulong mask = board.GetPieceBitboard((PieceType)piece + 1, sideToMove > 0); mask != 0;)
                {
                    gamephase += GamePhaseIncrement[piece];
                    square = BitboardHelper.ClearAndGetIndexOfLSB(ref mask) ^ 56 * sideToMove;
                    middlegame += UnpackedPestoTables[square][piece];
                    endgame += UnpackedPestoTables[square][piece + 6];
                }
            middlegame = -middlegame;
            endgame = -endgame;
        }
        return (middlegame * gamephase + endgame * (24 - gamephase)) / 24 * (board.IsWhiteToMove ? 1 : -1);
    }

Edit 2: I'm an idiot. The master version has the same negations inside the first for statement.
iPlayChess v2 is testing +310 elo against iPlayChess03 and 03 tested +200 elo better than 02 and 02 tested +200 elo better than iPlayChess and iPlayChess is at 1187 elo after only 22 games in live play. So it is looking good! :D

Do you want me to try the new code above?