SebLague / Chess-Challenge

Create your own tiny chess bot!
https://www.youtube.com/watch?v=Ne40a5LkK6A
MIT License
1.77k stars 1.06k forks source link

is there any way to program certain openings? #343

Closed iwantramen closed 1 year ago

iwantramen commented 1 year ago

Newbie to C sharp here, normally program in python and/or html:

is there a way to program openings in response to certain moves eg. play the caro kann in response to if white plays E4? Say in some sort of c sharp equivalent of defining a 'caro kann' function as one would in python, and tell the computer to do said caro kann function if e4 is played?

tom-anders commented 1 year ago

Sure, you could for example have a dictionary that map the position where white played e4 to your hardcoded response and so on.

The problem is, I'm not sure if this is worth it, since the challenge does not specify that in the tournament we'll always start from the standard starting position.

EikeSchwass commented 1 year ago

Sure, you could for example have a dictionary that map the position where white played e4 to your hardcoded response and so on.

The problem is, I'm not sure if this is worth it, since the challenge does not specify that in the tournament we'll always start from the standard starting position.

And also that only works well with a lot of openings and that uses a lot of tokens

SebLague commented 1 year ago

You can create a dictionary of opening moves indexed by Zobrist keys (a 64bit hash of the chess position). @tom-anders Thanks for bringing up the point about tournament games starting pos. I've added the following line to the readme: The final tournament games will be played from the standard starting position. If tiebreak games are required, custom positions will be used.

rowburt commented 1 year ago

You can create a dictionary of opening moves indexed by Zobrist keys (a 64bit hash of the chess position). @tom-anders Thanks for bringing up the point about tournament games starting pos. I've added the following line to the readme: The final tournament games will be played from the standard starting position. If tiebreak games are required, custom positions will be used.

The bots being created are deterministic (unless they use rng). If the tournament games all start from the startpos then you will end a match with 2 unique games each played 500 times. Both bots will make the same decision in the same position every time leading to the same game.

SebLague commented 1 year ago

@R0b3rt1337 That's a fair point -- the idea I'm toying with at the moment is to actually have two tournaments. The first would be a giant swiss so that all entries are able to receive a ranking (without taking forever to run), and these games would be played from the standard starting position (since no bot would play the same opponent twice). The top x percent from this tournament would then be promoted to an 'elite' tournament, which would involve a greater number of games per bot and a variety of different starting positions.

This is all up in the air though as it depends somewhat on the number of entries I end up receiving, and so on. At any rate, I just wanted to clarify that it's not a total waste of time to try make your bot play well out of the opening. If you have suggestions or want to discuss this further, please open a separate discussion :)

goosehub commented 1 year ago

I've had success with just giving general bonuses in the evaluation. For a really simple and probably bad example, board.PlyCount < 10 && (piece.IsKnight || piece.IsBishop) && (piece.Square.Rank == 0 || piece.Square.Rank == 7), then make that piece is worth a little less, because it's a minor piece not developed. That said, I'm finding once it has decent depth, it plays pretty good openings all by itself. I would be surprised if using precious tokens on openings would be worth it at all when that same space can be used to add perhaps more useful positioning or end game knowledge, or just better depth search. Of course the competition isn't just about making the best bot, but also interesting bots, so I am curious how far some will take programming the openings.

Pds314 commented 1 year ago

You could create a Dictionary<ulong, int> which you fill with up to a few hundred or so ZobristKeys and evaluations. If a board's Zobrist is in the dictionary, you apply the book evaluation instead of using your evaluation function.

An alternative option would be to compute the Zobrists during your 5 second loading time and store the opening choices in much more compact form, such as foregoing evaluation entirely and just storing book moves, with some way to tell the machine whether to undo 0, 1, or 2 times after any given move.

So given there are 3 possible answers, we can take our byte and % 85 it to get a move index. And / 3 to get how many times to undo.

Since there are 8 bytes in a ulong or 12 accessible bytes in a decimal, this means we can easily store 8 positions and the required opcodes as book moves per token consumed, at least as long as the board mobility does not exceed 85, which seems pretty high. Thus, we can memorize up to several thousand opening positions if we are willing to devote some tokens to it.

One slightly crazy optimization you could add would be to figure out how many moves are available, and then multiply by 3 to get the size of the input each time. This will be slower (though by no means exceeding the 5 second limit) but it will have the benefit that in a position with under 42 mobility, you can get away with using 7 bits, and in a position with under 21 mobility (such as the opening), 6 bits. If we assume that most principled opening positions have between 21 and 42 moves, that could increase the packing density, and if combined with decimal, means that if half your tokens were the opening book, you could in principle store about 7000 positions. Whether you would save anything though with the extra code vs just using fixed-width bytes out of a ulong is.. debatable. Keep in mind that the end result is still a dictionary of Zobrists, but you get more of them by just remembering a move than by remembering a Zobrist.

Pds314 commented 1 year ago

"The bots are deterministic unless they use RNG." Mine are not totally deterministic even though they don't use RNG. They use the timer to decide when to stop their search.

SebLague commented 1 year ago

Closing this now, feel free to reopen if you still have questions about it @iwantramen

jongdetim commented 1 year ago

zobrist keys are based on randomly generated numbers during initialization though, so there's no way to use hardcoded zobrist keys to create a dictionary before runtime.

rowburt commented 1 year ago

zorbist keys are based on randomly generated numbers during initialization though, so there's no way to use hardcoded zobrist keys to create a dictionary before runtime.

These numbers are generated using the fixed seed 29426028 (found in Zobrist.cs), meaning the hashes will be the same every time. So you could hardcode openings with them if you want to spend the tokens on it.