GithubHelp home page GithubHelp logo

thomasahle / sunfish Goto Github PK

View Code? Open in Web Editor NEW
2.9K 84.0 536.0 1.75 MB

Sunfish: a Python Chess Engine in 111 lines of code

Home Page: https://www.chessprogramming.org/Sunfish

License: Other

Python 97.00% Shell 3.00%
sunfish python chess-engine chess-ai ai chess

sunfish's Introduction

Sunfish logo

Introduction

Sunfish is a simple, but strong chess engine, written in Python. With its simple UCI interface, and removing comments and whitespace, it takes up just 131 lines of code! (build/clean.sh sunfish.py | wc -l). Yet it plays at ratings above 2000 at Lichess.

Because Sunfish is small and strives to be simple, the code provides a great platform for experimenting. People have used it for testing parallel search algorithms, experimenting with evaluation functions, and developing deep learning chess programs. Fork it today and see what you can do!

Play against sunfish!

The simplest way to run sufish is through the "fancy" terminal interface:

$ tools/fancy.py -cmd ./sunfish.py
Playing against sunfish 2023.
Do you want to be white or black? black
  1 ♖ ♘ ♗ ♔ ♕ ♗ ♘ ♖
  2 ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
  3
  4
  5
  6
  7 ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
  8 ♜ ♞ ♝ ♚ ♛ ♝ ♞ ♜
    h g f e d c b a

Score: 23, nodes: 11752, nps: 13812, time: 0.9
 My move: d4
  1 ♖ ♘ ♗ ♔ ♕ ♗ ♘ ♖
  2 ♙ ♙ ♙ ♙   ♙ ♙ ♙
  3
  4         ♙
  5
  6
  7 ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
  8 ♜ ♞ ♝ ♚ ♛ ♝ ♞ ♜
    h g f e d c b a

Your move (e.g. c6 or g8h6): Nf6

Note this requires the python-chess package. For a true minimalist experience, first we can "pack" sunfish into a compressed executable (less than 3KB!) and run it directly:

$ build/pack.sh sunfish.py packed.sh
Total length: 2953
$ ./packed.sh
go wtime 1000 btime 1000 winc 1000 binc 1000
info depth 1 score cp 0 pv d2d4
bestmove d2d4

(See the UCI specification for the full set of commands.)

Playing with a graphical interface

It is also possible to run Sunfish with a graphical interface, such as PyChess or Arena.

Finally you can play sunfish now on Lichess or play against Recursing's Rust port, also on Lichess, which is about 100 ELO stronger.

NNUE version

There is an experimental version using an Efficiently updatable neural network. You can test it using the fancy terminal interface as above:

$ tools/fancy.py -cmd "./sunfish_nnue.py nnue/models/tanh.pickle"
...

In contrast to the large NNUE in say, Stockfish, this network is only 1207 bytes! That makes sure sunfish NNUE can still be packed into less than 4KB. Using NNUE, sunfish will play better positionally, but worse tactically, since the implementation is still not fast enough.

Features

  1. Built around the simple, but efficient MTD-bi search algorithm, also known as C*.
  2. Filled with classic "chess engine tricks" for simpler and faster code.
  3. Efficiently updatedable evaluation function through Piece Square Tables.
  4. Uses standard Python collections and data structures for clarity and efficiency.

Limitations

Sunfish supports all chess rules, except the 50 moves draw rule.

There are many ways in which you may try to make Sunfish stronger. First you could change from a board representation to a mutable array and add a fast way to enumerate pieces. Then you could implement dedicated capture generation, check detection and check evasions. You could also move everything to bitboards, implement parts of the code in C or experiment with parallel search!

The other way to make Sunfish stronger is to give it more knowledge of chess. The current evaluation function only uses piece square tables - it doesn't even distinguish between midgame and endgame. You can also experiment with more pruning - currently only null move is done - and extensions - currently none are used. Finally Sunfish might benefit from a more advanced move ordering, MVV/LVA and SEE perhaps?

An easy way to get a strong Sunfish is to run with with the PyPy Just-In-Time intepreter. In particular the python2.7 version of pypy gives a 250 ELO boost compared to the cpython (2 or 3) intepreters at fast time controls:

Rank Name                    Elo     +/-   Games   Score   Draws
   1 pypy2.7 (7.1)           166      38     300   72.2%   19.7%
   2 pypy3.6 (7.1)            47      35     300   56.7%   21.3%
   3 python3.7               -97      36     300   36.3%   20.7%
   4 python2.7              -109      35     300   34.8%   24.3%

Why Sunfish?

The name Sunfish actually refers to the Pygmy Sunfish, which is among the very few fish to start with the letters 'Py'. The use of a fish is in the spirit of great engines such as Stockfish, Zappa and Rybka.

In terms of Heritage, Sunfish borrows much more from Micro-Max by Geert Muller and PyChess.

License

GNU GPL v3

sunfish's People

Contributors

adilosa avatar aujicini avatar bakerwho avatar boarpig avatar bobtie avatar ddugovic avatar illagrenan avatar jthemphill avatar michaelmior avatar nimishbongale avatar recursing avatar ryanhs avatar tahle avatar thomasahle avatar timgates42 avatar ugoertz avatar verhovsky avatar willpapper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sunfish's Issues

Tempo

Sunfish currently doesn't do 'tempo'. A mate in 6 is considered the same as a mate in 1.

How to Run Sunfish...

I was told by someone else here on GitHub that "python chess programs" could be run by just downloading and using PYPY (I don't need to install Python). So I grabbed PyPy 3.8 (https://www.pypy.org/download.html) for Windows 64-bit.

I have PyPy 3.8, and I have your Sunfish.zip, and I have the Python Chess 1.7.0.zip. I have PyPy 3.8 unzipped to C:\PYPY on my hard drive. Now what do I do?

Shawn

Remove player suicide move from the pos.gen_moves()

As chess rule only has checkmate, never kill the king, so player move causes king die is illegal. Removing the player move that lets AI check king from the possible move list will be easy to judge the game is checkmate or drawn.

Piece Table Value Selection

Hi,

For a school project, I am working to optimize the piece table values for sunfish using particle swarm simulation to find the best results. For my research, I'm interested to know how the values currently used in the engine were selected. Were they just found through human testing through trial and error or were they found using an existing algorithm? I wonder how close they are to optimal.

If somebody could help me with the reasoning that would be appreciated.

Additionally, if the creator would be willing to answer a few interview questions via email it would be HUGELY appreciated - project specs say there needs to be an interview somewhere in there ¯_(ツ)_/¯

Thanks.

Stalemate search broken

The current build manages nearly none of the tests when running python3 test.py quickdraw tests/stalemate2.fen".

Mate bug

Hi,

The computer said that I was mated when I was not (see screencapture).
I was playing white.

capture du 2017-01-23 14-13-51

Add better time management

Since the xboard code is not trying to be small in the same way as the main module, we might as well add a few lines for trying to figure out how many nodes to search.

Small bug - castling and pawns

Currently, if a king is in check from a pawn, say on d7 for example, the black king can still castle kingside. The tuple on line 148 of sunfish.py should also include self.kp + 1 and self.kp - 1

Probably unnecessary code

sunfish.py
145 # Pawn move, double move and capture
146 if p == 'P' and d in (N, N+N) and q != '.': break

Line 146 is probably unnecessary - may comment it out or delete it to make the program shorter

Bug - false mate announcement

image

I don't have a list of game moves for this - maybe making a list of them would aid debugging for things like this.

Using PyPy.

Matthew:out

Castle through check

Sunfish is a lot of fun! After a few games I however found out that I could castle through check, and then another bug appears which makes me checkmate.

Note that the colours got swapped when I saved the terminal output, black in the bottom here is actually white

My move: h4h3

  8 ♖ · ♗ · · ♖ ♔ ·
  7 ♙ ♙ ♙ ♙ · ♙ ♙ ♙
  6 · · · · · · · ·
  5 · · · · · · · ·
  4 · · · · · ♟ · ·
  3 · · · · ♟ · ♟ ♕
  2 · · · ♛ · · · ♟
  1 · ♞ · · ♚ · · ♜
    a b c d e f g h 


Your move: e1g1

  8 ♖ · ♗ · · ♖ ♔ ·
  7 ♙ ♙ ♙ ♙ · ♙ ♙ ♙
  6 · · · · · · · ·
  5 · · · · · · · ·
  4 · · · · · ♟ · ·
  3 · · · · ♟ · ♟ ♕
  2 · · · ♛ · · · ♟
  1 · ♞ · · · ♜ ♚ ·
    a b c d e f g h 


Checkmate!
My move: h3f1

  8 ♖ · ♗ · · ♖ ♔ ·
  7 ♙ ♙ ♙ ♙ · ♙ ♙ ♙
  6 · · · · · · · ·
  5 · · · · · · · ·
  4 · · · · · ♟ · ·
  3 · · · · ♟ · ♟ ·
  2 · · · ♛ · · · ♟
  1 · ♞ · · · ♕ ♚ ·
    a b c d e f g h 

Ansi Board?

Cool! Love the Unicode pieces. Any chance of adding ansi codes for background colors to make the board look as good as the pieces? Would be killer if the chessboard was checkered. Looks great, but that would really top it off (also easier to play-- I have trouble tracking the dots diagonally).

Another idea, use the "alternate screen" (application mode) and add ansi support for mouse clicks and arrow keys, at least for xterm compatible terminals. On mobile terms with touch support, it would make a really cool mini-app.

Anyway, like what you did here.

print_pos with pieces with opposite colours

Hello everyone,

Just cloned the Git repo and try to use it, I got the opposite when printing the board with print_pos, rank 1 is black and rank 8 is white. To see correct results on console, I swapped the letters in uni_pieces, especially since it reflects now how FEN notation is written, capital letters for white and small letters for black.

Hope that helps

sunfish can't play white?

I tried a couple times by rotating board before it started searching, but still gives weird evals and errors meaning its still playing black

how to run with xboard

os: ubuntu 18.04
after installing xboard it seems xboard has some internal engines of its own. i tried to run pypy3 -u xboard.py in one window and xboard in the other window but it doesn't seem that xboard is using sunfish.

Sunfish loses for time when it will perform a mate on the contrary

sunfish.zip
[Event "Arena Tournament 1311"]
[Site "DESKTOP-AMD"]
[Date "2019.06.25"]
[Round "7"]
[White "Pyotr 0.6 AM"]
[Black "Sunfish 2019.06.02"]
[Result "1-0"]
[WhiteElo "868"]
[BlackElo "2200"]
[WhiteType "program"]
[BlackType "program"]
[ECO "A40"]
[Opening "Queen's Pawn"]
[Variation "1...e6 2.c4"]
[TimeControl "40/180:40/180:40/180"]
[Time "07:46:35"]
[Termination "time forfeit"]
[PlyCount "95"]

  1. d4 e6 2. c4 c6 3. e4 d5 4. e5 dxc4 5. Bxc4 c5 6. dxc5 Qxd1+ { (6. ...
    Dxd1+ 7.Rxd1 Axc5 8.Ae3 Axe3 9.fxe3 Cc6) -0.09/7 5 } 7. Kxd1 Bxc5 { (7. ...
    Axc5 8.Ae3 Axe3 9.fxe3 Cc6 10.Cf3 Cge7) -0.26/7 6 } 8. Be3 Nd7 { (8. ...
    Cd7 9.Cf3 Ce7 10.Axc5 Cxc5) -0.10/7 8 } 9. Bxc5 Nxc5 { (9. ... Cxc5 10.Cc3
    Ad7 11.b4 Ca4 12.Cxa4 Axa4+) -0.24/7 4 } 10. Kc1 Bd7 { (10. ... Ad7 11.Cf3
    0-0-0 12.Td1) -0.08/6 3 } 11. Nc3 O-O-O { (11. ... 0-0-0 12.Cf3 Rb8 13.Td1)
    -0.10/6 3 } 12. b4 Bc6 { (12. ... Ac6 13.Cf3 Cd3+ 14.Axd3 Txd3 15.Rc2 Td8)
    +0.37/7 7 } 13. bxc5 Bxg2 { (13. ... Axg2 14.Cb5 Axh1 15.Cd6+ Rb8 16.Cxf7
    Td4) +1.20/7 3 } 14. Nb5 Kb8 { (14. ... Rb8 15.Cd6 Ch6 16.Cxb7 Td4 17.Axe6
    Axh1) +0.66/6 4 } 15. Nd6 Nh6 { (15. ... Ch6 16.f3 Axh1 17.Tb1 Ra8 18.Tb5)
    +1.18/6 3 } 16. Nxb7 Kxb7 { (16. ... Rxb7 17.Tb1+ Rc8 18.Aa6+ Rc7 19.Ab7
    Axb7) +3.40/7 4 } 17. Rb1+ Ka8 { (17. ... Ra8) +4.16/7 4 } 18. a4 Bxh1 {
    (18. ... Axh1 19.f3 Cf5 20.Ab5 a6 21.Axa6 Ag2) +4.80/7 7 } 19. a5 Ng4 {
    (19. ... Cg4 20.f4 Ce3 21.Aa2 Ad5 22.Ab3 Axb3 23.Txb3) +5.54/6 2 } 20. Ne2
    Nxf2 { (20. ... Cxf2 21.a6 Ae4 22.Tb5 Td1+) +6.56/5 2 } 21. Nc3 Rd4 { (21.
    ... Td4 22.Ab5 Ag2 23.a6) +6.48/6 3 } 22. Bxe6 fxe6 { (22. ... fxe6 23.Cb5
    Td1+ 24.Rb2 Td2+ 25.Ra1) +8.41/6 2 } 23. Kc2 Bc6 { (23. ... Ac6 24.Tg1 Tg8
    25.Tf1 Tf8 26.a6) +8.88/6 8 } 24. Rg1 g6 { (24. ... g6 25.Te1 Te8) +9.37/5
    1 } 25. Kc1 Rc4 { (25. ... Tc4 26.Rb2 Tb8+ 27.Rc2 Txc5 28.Te1) +9.58/6 6 }
  2. Rg3 Rxc5 { (26. ... Txc5) +10.52/6 1 } 27. a6 Rxe5 { (27. ... Txe5)
    +10.82/6 2 } 28. Rg1 Ra5 { (28. ... Ta5) +11.48/5 1 } 29. Kc2 Rh5 { (29.
    ... Th5 30.Te1 Te8 31.Cd1 Txh2 32.Cxf2 Txf2+) +11.52/5 1 } 30. Re1 Re8 {
    (30. ... Te8 31.h4 Txh4 32.Rb1 Th2 33.Te5 Rb8) +11.66/6 2 } 31. Kd2 Rxh2 {
    (31. ... Txh2 32.Rc2 Rb8 33.Rb1 e5) +12.34/6 2 } 32. Re2 Kb8 { (32. ... Rb8
    33.Re1 Cd3+ 34.Rf1) +12.35/4 1 } 33. Kc2 e5 { (33. ... e5 34.Rb1 Th1+
    35.Rb2 Th2 36.Rb1) +12.58/6 2 } 34. Rd2 h6 { (34. ... h6 35.Rb1 Th1+ 36.Rb2
    Th2) +12.86/5 1 } 35. Re2 e4 { (35. ... e4 36.Te1 e3 37.Rb1) +12.81/6 2 }
  3. Kd2 Rf8 { (36. ... Tf8 37.Rc1 Tf3 38.Tb2+ Ra8) +13.18/5 1 } 37. Kc2 Rf3
    { (37. ... Tf3 38.Td2) +12.80/6 6 } 38. Rd2 Rd3 { (38. ... Td3 39.Txd3
    exd3+ 40.Rc1) +12.94/5 1 } 39. Rxd3 exd3+ { (39. ... exd3+ 40.Rb2 Ce4+
    41.Ra1 d2 42.Cd1) +13.11/6 0 } 40. Kc1 Rh1+ { (40. ... Th1+ 41.Rd2)
    +13.20/6 0 } 41. Kd2 Ne4+ { (41. ... Ce4+ 42.Rxd3 Th3+ 43.Rc2 Txc3+ 44.Rb2)
    +13.56/8 5 } 42. Nxe4 Bxe4 { (42. ... Axe4 43.Re3 Th2 44.Rxe4 d2 45.Re5 d1D
    46.Rf6) +16.85/8 4 } 43. Ke3 Rh2 { (43. ... Th2 44.Rxe4 d2 45.Re5 d1D
    46.Rf6 Db1) +17.10/7 4 } 44. Kxe4 d2 { (44. ... d2 45.Re5 Tf2 46.Rd6 d1D+
    47.Rc5 Dd3 48.Rb4) +17.66/8 4 } 45. Kd5 d1=Q+ { (45. ... d1D+ 46.Re5 Tf2
    47.Re4 Dd2 48.Re5 Dd3 49.Re6) +17.92/8 15 } 46. Ke6 Rf2 { (46. ... Tf2
    47.Re5) +18.00/7 12 } 47. Ke7 Kc7 { (47. ... Rc7 48.Re8) +M355/9 3 } 48.
    Ke8 { Negras pierden por tiempo } 1-0

Add `#!/usr/bin/env pypy3` to top of fancy.py

sunfish.py has a shebang line, but fancy.py doesn't.

To make fancy.py run out-of-the-box,
add #!/usr/bin/env pypy3 to top of fancy.py.`

(fancy.py doesn't work with Python2 pypy, so requires pypy3. sunfish.pydoes run under Python2pypy`)

illegal move and a potential solution

Sunfish claims that Qf2 is the best move in this position, although it is illegal.

r3n3/7Q/4pkp1/3p2P1/1p1P4/1P3PK1/r3q3/8 b - - 0 63

I therefore thought about changing the can_kill_king function to

def can_kill_king(pos): # If we just checked for opponent moves capturing the king, we would miss # captures in case of illegal castling. return any(pos.value(m) >= sunfish.MATE_LOWER for m in pos.gen_moves()) or any(pos.board[b]=='k' for a,b in pos.gen_moves())

As far as I can see the function works as intended, but the pv function doesn't return any moves in some cases. So, it might be preferable if we also check the returned pv; if it's empty, we can use the prior pv (assuming it will return a pv at depth 1)

Crashes

I tried this with python 2, python 3, from command line and within ipython and all get approximately the same thing. Maybe user error. (No pypy though.)

Your move: e6
Traceback (most recent call last):
  File "chess.py", line 388, in <module>
    main()
  File "chess.py", line 365, in main
    move = parse(crdn[0:2]), parse(crdn[2:4])
  File "chess.py", line 345, in parse
    fil, rank = ord(c[0]) - ord('a'), int(c[1]) - 1
IndexError: string index out of range

Error: pop takes two arguments (line 195)

This code seems fishy:

    # We save the found move together with the score, so we can retrieve it in
    # the play loop. We also trim the transposition table in FILO order.
    # We prefer fail-high moves, as they are the ones we can build our pv from.
    if entry is None or depth >= entry.depth and best >= gamma:
        tp[pos] = Entry(depth, best, gamma, bmove)
        if len(tp) > TABLE_SIZE:
            tp.pop()
    return best

tp is an ordereddict, so it does have an additional method popitem() which will pop the last item from the dict. Otherwise, the pop method requires two arguments: the key and a default value to pop if the function can't find the key in the dictionary. This is raising errors for me.

List Attacking pieces?

Currently, the way to find attacking pieces is to check one by one. Is there a better way to do this?

fix for UCI play

I wrote some fixes for the uci.py code - providing actual ability to play as UCI engine in something like HIARCS Chess Explorer.

Interest in Sunfish...

I hate to ask, but I really like Sunfish, and I was wondering if you would ever consider porting a version to Java. Just wondering ~ I collect tons of chess programs.

Shawn Weber

FICS broken

Hi,
trying to connect Sunfish to my local FICS (free internet chess server) via xboard:
xboard -size Medium -zp -fd ~/chess/sunfish -ics -icshost $FICS_LOCAL_IP -icsport 5000 -icshelper ~/bin/timeseal -icslogon ~/chess/sunfish.ini -fcp "python -m xboard"

(sunfish folder is a symlink to the git repo)

Just after my first move (Sunfish playing as Black) I get several
xboard: Error writing to first chess program: Broken pipe and xboard exits

Tried with pypy -u, python xboard.py and other flavours (e.g. shell scripts) with no luck.

xboard 4.8.0
FICS server 2.2.x-DEVEL

`python3 test.py findbest tests/mate1.fen` raises IndexError

python3 test.py findbest tests/mate1.fen returns

Calibrating search speed...
Running benchmark with 3897.0 nodes per second...
------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 392, in <module>
    main()
  File "test.py", line 385, in main
    args, unknown = parser.parse_known_args()
  File "/usr/lib/python3.4/argparse.py", line 1758, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.4/argparse.py", line 1967, in _parse_known_args
    stop_index = consume_positionals(start_index)
  File "/usr/lib/python3.4/argparse.py", line 1923, in consume_positionals
    take_action(action, args)
  File "/usr/lib/python3.4/argparse.py", line 1832, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib/python3.4/argparse.py", line 1134, in __call__
    namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
  File "/usr/lib/python3.4/argparse.py", line 1758, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.4/argparse.py", line 1967, in _parse_known_args
    stop_index = consume_positionals(start_index)
  File "/usr/lib/python3.4/argparse.py", line 1923, in consume_positionals
    take_action(action, args)
  File "/usr/lib/python3.4/argparse.py", line 1832, in take_action
    action(self, namespace, argument_values, option_string)
  File "test.py", line 321, in __call__
    f(namespace)
  File "test.py", line 383, in <lambda>
    add_action(p, lambda n: findbest(n.file, n.times))
  File "test.py", line 291, in findbest
    fen, opts = parseEPD(line)
  File "test.py", line 275, in parseEPD
    opts = dict(p.split(maxsplit=1) for p in parts[6].split(';'))
IndexError: list index out of range

Add more features to UCI.py

Hello, I encountered this issue with Sunfish:

  • Start position r2qkbnr/p1pnP1p1/8/5p1p/3P2b1/2p2N2/PPPB1PPP/R2QKB1R w KQkq - 0 1
    with Sunfish set to play Black

When White plays e7d8q in cutechess, Sunfish does not play at all.

  • With the same FEN and Sunfish is set to play white, Sunfish plays exd8=Q+ , but then when the cutechess uci command sends

position fen r2qkbnr/p1pnP1p1/8/5p1p/3P2b1/2p2N2/PPPB1PPP/R2QKB1R w KQkq - 0 1 moves e7d8q e8d8

Sunfish disconnects.

Hope that reporting this issue will help improve the Sunfish engine

Sunfish hangs before making final move

In the following mate-in-one, sunfish does the first 17 plies very fast, and then has a very long think before ply 18. This makes it run out of time and makes cutechess think its connection has sttalled.

setboard 8/8/1Q4B1/8/5P2/P1k2P1P/6P1/6K1 w - - 1 43
post
go
  1     1822        0            43 	b6e6
  2    69290        1           141 	b6b4
  3    69290        1           162 	b6b4
  4    69290        1           181 	b6b4
  5    69290        1           200 	b6b4
  6    69290        2           283 	b6b4
  7    69290        2           402 	b6b4
  8    69290        3           509 	b6b4
  9    69290        3           616 	b6b4
 10    69290        4           872 	b6b4
 11    69290        5          1172 	b6b4
 12    69290        6          1462 	b6b4
 13    69290        7          1752 	b6b4
 14    69290        8          2260 	b6b4
 15    69290       10          2848 	b6b4
 16    69290       12          3416 	b6b4
 17    69290       14          3984 	b6b4
 18    69290     6236       1855272 	b6b4
move b6b4

Sunfish doesn't use tempo in search.

My move: b5a5

  8 ♖ · ♗ · ♔ ♖ · ·
  7 ♙ ♙ · · · · ♜ ♜
  6 · · · · · · · ·
  5 ♕ · ♙ · · ♙ ♝ ·
  4 · · ♙ · · · · ·
  3 · · ♟ · · ♞ · ·
  2 ♟ · ♛ · · ♘ ♟ ·
  1 ♚ · · · · · · ·
    a b c d e f g h 


Your move: g7e7

  8 ♖ · ♗ · ♔ ♖ · ·
  7 ♙ ♙ · · ♜ · · ♜
  6 · · · · · · · ·
  5 ♕ · ♙ · · ♙ ♝ ·
  4 · · ♙ · · · · ·
  3 · · ♟ · · ♞ · ·
  2 ♟ · ♛ · · ♘ ♟ ·
  1 ♚ · · · · · · ·
    a b c d e f g h 


You won

There is no checkmate? Did sunfish give up because the evaluation was to low?

how to setup Sunfish with CuteChess ?

i'm not a beginner with python and chess engines .. i see the file uci.py but how to use it ? :: which command should be entered in the CuteChess GUI ? i prefer the UCI protocol. I'm using Xubuntu 20.04

Increase performance by saving the result of pos.value(move) instead of computing it multiple times

pos.value(move) gets called with the same arguments three times on lines 274, 276 and 278
By just making making pos.gen_moves() return a list of tuples of the form (value, move) and making pos.move take move_value as an argument I think I obtained roughly a 35% speed improvement (with NODES_SEARCHED = 1e5, on pypy on my computer it goes from 2m24.644s to 1m35.306s for 4 moves)

I don't think this is the best way to do it, but the current implementation seems very inefficient.

Also, are there plans to make the position mutable, or do you think it would increase complexity too much?

I understand that the main focus of this project is to keep it simple and short, but it looks like it would play reasonably well with just a ~10x performance improvement, that seems reachable (at least, I think so)

Unreadable variable names

Is there a reason the code uses variable names like "pst" instead of "piece_square_tables", "i" instead of something like "from_index", "j" instead of something like "to_index", "wc" istead of "my_castling", "bc" instead of "opponent_castling" and so on?

I think it makes the codebase less readable without decreasing the line count, is it just something inherited from the golfed programs that inspired this?

Also, could we use black or autopep8 or similar formatters to make the source prettier and more consistent?

Check for stalemate

In line 286:

if depth > 0 and best <= -MATE_VALUE is None and nullscore > -MATE_VALUE:

I do not get what the "is None" is doing - it looks to me as if it should be omitted. Edit: In fact, the "is None" was necessary in the previously used check for stalemate, and should have been deleted in this commit.

Furthermore, there are stalemate positions without pseudo-legal moves, so maybe it would be better to additionally check whether pos.genMoves() is empty. Edit: Since best is initialized appropriately, this is unnecessary.

Thanks for your work, it is a pleasure to study the sunfish code.

Change promotion piece

on line 195 of the sunfish.py program, there's
board = put(board, j, 'Q')

I'm wondering if just changing the Q to R will force a promotion to a rook. I tried that but it still promoted to a queen.

King puts itself in check

When I ran selfplay() in test.py I noticed the game ended by king capture. See screenshot, where the black king moves g7-g8 and puts itself in check:

g7g8

It can also be reproduced by letting Sunfish search for black in this position:
pos = xboard.parseFEN('R7/6k1/8/8/8/8/8/7K b - - 0 1')
where g7-g8 is immediately found as best move, but it also puts the black king in check.

As Sunfish borrows from Micro-Max which states:
"Before we discuss castling, it is good to point out that micro-Max is a King-capture engine: At any level it generates all pseudo-legal moves, including those that put his own King in check. Since this is a condition that depends on which moves the opponent has, it seems more logical to test it on the next ply, when we generate the opponent's moves anyway. Usually all opponent's moves are generated before micro-Max starts to think about any of them, and if a King capture is found the branch is aborted and the caller is informed (by the move's score) that the move was an illegal one."

I think somewhere in the bound() or genMoves() code this branch abortion must be added for check cases.

Player is able to move into check

Here's a sample game where I play e4, then bring the king out to e2, e3 and then d4 where it is captured by the opponent's knight. I had a quick look through the code and couldn't find any check to prevent moving into check. Also, on the next move (after king being captured) the program ends with "You won."

(some output omitted for clarity)

gus@mint dev$ python sunfish.py 

Your move: e2e4
My move: b8c6
Your move: e1e2
My move: g8f6
Your move: e2e3
My move: d7d5

 r.bqkb.r 
 ppp.pppp 
 ..n..n.. 
 ...p.... 
 ....P... 
 ....K... 
 PPPP.PPP 
 RNBQ.BNR 

Your move: e3d4

(into check)

 r.bqkb.r 
 ppp.pppp 
 ..n..n.. 
 ...p.... 
 ...KP... 
 ........ 
 PPPP.PPP 
 RNBQ.BNR 


Searched 33 nodes. Depth 1. Score 20379
My move: c6d4
Visited 33 nodes.

 r.bqkb.r 
 ppp.pppp 
 .....n.. 
 ...p.... 
 ...nP... 
 ........ 
 PPPP.PPP 
 RNBQ.BNR 


Your move: e4d5

 r.bqkb.r 
 ppp.pppp 
 .....n.. 
 ...P.... 
 ...n.... 
 ........ 
 PPPP.PPP 
 RNBQ.BNR 


Searched 2 nodes. Depth 1. Score 20279
You won
gus@mint dev$ 

Add three-fold repetition draw

This draw comes up all the time when sunfish is winning, and it always jump straights in, giving away the victory.
Also the stalemate draw is still not well tested. Perhaps sunfish needs a draw_in_k test, just like the ones for mating.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.