andygrant / ethereal Goto Github PK
View Code? Open in Web Editor NEWEthereal, a UCI Chess Engine by Andrew Grant
License: GNU General Public License v3.0
Ethereal, a UCI Chess Engine by Andrew Grant
License: GNU General Public License v3.0
When using Ethereal with CuteChess in a tournament, the engine (v11.75) exceeds the clock time limit -- I tested 5 minutes for 40 moves -- and so it looses the game ?!
I don't know how CuteChess does instruct an engine to limit 40 moves in 5 min, because the UCI protocol only has "fixed depth" / "time per move" / "infinite" when calculating any FEN, but other engines do not seem to have this problem.
Going to be adding King-Safety soon. An Eval Cache will more valuable when the Evaluation process takes longer.
Can we modify makefile to be the same as stockfish' makefile but few ones tell/notify users this is building Ethereal binary...
texel.c
is unclear, may suggest something other than intended.ENABLE_
, collapse with macro magic into the headerHi,
I'm reading some of your code to improve my engine Tunguska:
https://github.com/fernandotenorio/Tunguska
I noticed at masks.c, in the connectedPawn mask initialization:
for (int i = 8 ; i < 54; i++){ ... }
Shouldn't it be i < 56?
Hi Andy. Are you going to do support in syzygy in Ethereal?
1R1Q4/2r3qk/3p2p1/3Pbp1p/8/p3N1PP/P4PK1/8 w - - 2 60
Ethereal plays Nxf5??
https://www.chess.com/computer-chess-championship#event=ccc10-quarterfinals&game=55
Nxf5 is throwing away a piece. Ethereal did not expect gxf5 after Nxf5. The evaluation appeared to be 0.0 then immediately dropped to -6 after gxf5 was played, black would gain +2 material directly from it. Not sure why really, could it be a hashing issue?
It would be useful to find out more easily what Ethereal is thinking of multiple moves without having to manually check each one.
Hi
Ran some mini-tournaments with 5 engines under CuteChess. Picking up some issue with Ethereal, so not sure if it's my setup, or something with CuteChess, or something with Ethereal. Don't have these issues with the other engines in the tests, but on the other hand, playing games between engines under PyChess does not produce same problems ... so I don't know.
Or maybe stockfish is somehow interfering with Ethereal?
Samples follow. Other games ended normally.
White "Ethereal"]
[Black "stockfish"]
[Result "0-1"]
[FEN "1rbqkbr1/1nppppn1/2pppp2/8/8/2PPPP2/1NPPPPN1/1RBQKBR1 w - - 0 1"]
[GameDuration "00:04:58"]
[GameEndTime "2019-11-05T11:33:20.066 SAST"]
[GameStartTime "2019-11-05T11:28:22.064 SAST"]
[PlyCount "8"]
[SetUp "1"]
[Termination "time forfeit"]
[TimeControl "40/240+5"]
[White "stockfish"]
[Black "Ethereal"]
[Result "1-0"]
[FEN "1rbqkbr1/1nppppn1/2pppp2/8/8/2PPPP2/1NPPPPN1/1RBQKBR1 w - - 0 1"]
[GameDuration "00:07:02"]
[GameEndTime "2019-11-05T11:40:33.065 SAST"]
[GameStartTime "2019-11-05T11:33:30.068 SAST"]
[PlyCount "27"]
[SetUp "1"]
[Termination "time forfeit"]
[TimeControl "40/240+5"]
d4 {+0.47/27 28s} e5 {-0.08/25 18s} 2. e4 {+0.51/27 2.0s} Ne6 {-0.19/25 8.2s}
e3 {+0.29/26 0.41s} Ra8 {-0.28/25 18s} 4. Nd3 {+0.48/28 9.2s}
c5 {-0.27/26 14s} 5. d5 {+0.75/22 4.1s} Ng7 {-0.35/24 22s} 6. c4 {+1.27/22 7.6s}
Na5 {-0.30/23 3.2s} 7. Nb2 {+1.46/24 4.7s} e6 {-0.53/22 7.9s}
Ra1 {+1.50/26 28s} c6 {-0.28/24 39s} 9. d3 {+1.76/20 4.0s} Bb7 {-0.58/23 21s}
dxe6 {+1.37/24 14s} Nxe6 {-0.61/23 6.2s} 11. Bd2 {+1.56/23 0s}
d5 {-0.79/24 22s} 12. Rh1 {+1.58/21 8.3s} Qb6 {-0.90/24 9.3s}
Qc1 {+1.96/23 7.0s} Qd8 {-0.81/23 22s}
Nh4 {+1.80/27 0s, Black loses on time} 1-0
==========================================
[White "komodo-10-linux"]
[Black "Ethereal"]
[Result "1-0"]
[FEN "1rbqkbr1/1nppppn1/2pppp2/8/8/2PPPP2/1NPPPPN1/1RBQKBR1 w - - 0 1"]
[GameDuration "00:26:01"]
[GameEndTime "2019-11-05T14:54:11.068 SAST"]
[GameStartTime "2019-11-05T14:28:09.071 SAST"]
[PlyCount "153"]
[SetUp "1"]
[Termination "time forfeit"]
[TimeControl "40/240+5"]
d4 {+0.20/22 11s} e5 {-0.08/25 19s} 2. Rh1 {0s} d5 {0.00/24 22s}
Nd3 {+0.21/24 15s} e4 {-0.05/25 21s} 4. fxe4 {+0.31/22 13s}
dxe4 {-0.16/26 16s} 5. Nc5 {0s} d5 {0.00/25 12s} 6. c4 {+0.57/23 1.1s}
e5 {-0.10/24 14s} 7. Nxb7 {0s} Bxb7 {-0.01/25 13s} 8. Bb2 {+0.41/22 3.4s}
Qd6 {0.00/24 16s} 9. c5 {+0.81/21 12s} Qe6 {-0.61/23 7.8s}
Bc3 {+0.87/22 1.9s} Qf5 {-1.23/25 33s} 11. d3 {+1.15/20 9.3s}
Ne6 {-0.76/24 21s} 12. Rb4 {+1.24/19 8.9s} Ng5 {-1.13/25 17s}
Qb1 {+1.42/22 15s} Qc8 {-1.15/27 2.5s} 14. Qb2 {+1.40/22 18s}
f5 {-1.51/25 20s} 15. Rh5 {0.001s} Be7 {-1.97/24 20s} 16. dxe5 {0.002s}
Bxc5 {-2.00/24 16s} 17. Rb3 {0.003s} Bb6 {-1.76/24 16s} 18. Nf4 {+1.75/22 12s}
Ne6 {-1.51/24 5.1s} 19. Rxf5 {+1.90/21 4.5s} c5 {-1.52/23 12s}
Nh5 {+1.24/19 19s} Rg1 {-1.35/22 16s} 21. Nf6+ {+0.74/21 31s}
Ke7 {-0.87/22 8.6s} 22. dxe4 {+0.50/21 7.1s} Ng7 {0.00/25 11s}
Rf3 {+0.40/23 3.7s} dxe4 {0.00/27 8.0s} 24. Rg3 {+0.28/22 6.1s} Rxg3 {2.5s}
fxg3 {+0.28/22 5.1s} Bc6 {0.00/29 2.8s} 26. g4 {0.00/23 20s} Qh8
Bg2 {+0.25/22 13s} Ne6 28. Nh5 {-0.86/21 15s} Qh6 {+2.01/26 12s}
Qc1 {-0.82/23 8.9s} Rg8 {+1.69/28 9.9s} 30. Nf6 {-1.57/26 30s} Rh8
Nh5 {-2.07/24 13s} Qg5 {+3.47/27 9.2s} 32. Kf1 {-2.09/26 3.1s}
Qxg4 {+3.49/27 4.0s} 33. Nf6 {-2.48/27 36s} Qf5+ 34. Kg1 {-2.07/24 4.4s}
Qg5 {+3.69/31 1.9s} 35. Qe1 {-2.08/26 12s} Ba7 {+4.90/28 13s}
Kf1 {-3.08/22 21s} c4 {+5.33/29 10.0s} 37. Bb4+ {-2.76/23 9.9s} Kd8
Ra3 {-3.06/24 10s} Nf4 {+5.50/29 1.8s} 39. Qf2 {-3.13/26 13s}
Bxe3 {+5.62/31 3.4s} 40. Nh7 {-3.30/26 9.4s} Qxg2+ {+5.59/30 7.0s} 41. Qxg2 {0s}
Nxg2 {+5.71/31 13s} 42. Kxg2 {0.002s} Bd2 {+5.92/31 39s} 43. Ra6 {-3.14/27 11s}
Bxb4 {+5.96/30 4.8s} 44. Rxc6 {-3.22/29 11s} Rxh7 {+5.98/30 10s}
Rxc4 {0.001s} Ba5 {+6.00/29 35s} 46. Rxe4 {0.002s} Ke7 {+6.01/28 11s}
Kg3 {-3.43/26 10s} Ke6 {+6.13/26 18s} 48. Re3 {-3.50/27 9.9s}
Bb6 {+6.29/28 36s} 49. Rd3 {0.001s} Rh5 {+6.24/27 10s} 50. c4 {-3.83/26 15s}
Rh1 {+6.47/25 11s} 51. Rf3 {-3.76/24 14s} Rg1+ {+7.03/26 9.2s}
Kf4 {-4.04/27 0.28s} Rc1 {+7.16/26 17s} 53. Kg3 {-4.01/26 8.8s}
Rxc4 {+7.48/26 5.5s} 54. Rf6+ {-4.33/26 2.8s} Kxe5 {+7.73/25 7.8s}
Rxf7 {-3.28/22 4.8s} Re4 {+7.93/25 8.6s} 56. Rf8 {-3.99/24 13s}
Kd5 {+10.03/25 31s} 57. Rd8+ {-4.23/26 8.4s} Kc4 {+11.19/24 15s} 58. Rd7 {0s}
Rxe2 {+11.66/27 16s} 59. Kf3 {-11.87/27 15s} Re1 {+12.37/24 15s}
Kg4 {-16.58/32 2.2s} c5 {+14.38/23 11s} 61. Rb7 {-17.03/34 12s}
Kb5 {+22.73/23 11s} 62. Rb8 {-250.00/33 14s} c4 {1.1s} 63. Rc8 {-250.00/31 45s}
Re3 64. Ra8 {-250.00/29 11s} c3 {+34.32/21 14s} 65. Ra2 {26s} Re1
Kf5 {-250.00/24 9.3s} Kb4 {+31.10/23 15s} 67. Kg6 {-250.00/26 15s}
Kb3 {+M35/25 15s} 68. Ra8 {23s} c2 {+M29/23 10s} 69. Rc8 {0.001s}
Be3 {+M33/20 8.7s} 70. Kf5 {-M28/20 1.00s} c1=Q {+M23/9 5.0s} 71. Rxc1 {0s}
Bxc1 {+M23/18 5.0s} 72. Kg6 {0.001s} Rf1 {+M17/18 5.0s} 73. Kh5 {-M16/30 1.7s}
Rg1 {3.3s} 74. Kh4 {0.002s} Kc4 {+M13/19 6.7s} 75. Kh3 {0s} Kd3 {+M11/32 5.0s}
Kh2 {-M10/99 1.8s} Be3 {3.2s} 77. Kh3 {0s, Black loses on time} 1-0
==================================================
[White "Ethereal"]
[Black "xiphos-sse"]
[Result "0-1"]
[FEN "1rbqkbr1/2nppn2/1pppppp1/8/8/1PPPPPP1/2NPPN2/1RBQKB1R b - - 1 1"]
[GameDuration "00:29:21"]
[GameEndTime "2019-11-05T01:08:02.075 SAST"]
[GameStartTime "2019-11-05T00:38:40.885 SAST"]
[PlyCount "209"]
[SetUp "1"]
[Termination "stalled connection"]
[TimeControl "40/300"]
1... Bb7 {-0.14/21 9.1s} 2. Bb2 {+0.21/20 7.9s} Bg7 {-0.21/22 12s}
3. e4 {+0.14/20 6.7s} e5 {-0.17/22 20s} 4. Bg2 {+0.11/20 8.8s} f5 {-0.17/25 13s}
5. Ra1 {+0.09/22 8.0s} Ne6 {-0.05/23 0.95s} 6. Bh3 {+0.32/21 7.2s}
f4 {-0.20/24 12s} 7. Bxe6 {+0.39/22 6.0s} dxe6 {-0.17/23 7.1s}
8. gxf4 {+0.41/23 0.63s} exf4 {-0.16/22 5.6s} 9. d4 {+0.58/23 3.7s}
Rh8 {-0.25/23 13s} 10. Rxh8+ {+0.69/22 9.5s} Bxh8 {-0.30/25 2.7s}
11. e3 {+0.47/24 5.8s} fxe3 {-0.14/24 1.8s} 12. Nxe3 {+0.43/23 5.6s}
Ra8 {-0.15/26 0.65s} 13. Ke2 {+0.44/25 5.8s} Rxa1 {-0.16/28 5.0s}
14. Qxa1 {+0.53/26 13s} Qa8 {-0.20/28 1.8s} 15. Qxa8+ {+0.61/26 4.5s}
Bxa8 {-0.20/26 3.3s} 16. Nd3 {+0.37/26 2.9s} g5 {-0.24/27 2.9s}
17. Nc4 {+0.35/25 7.6s} b5 {-0.14/26 9.7s} 18. Nb6 {+0.58/27 11s}
Bb7 {-0.05/24 5.4s} 19. c4 {+0.58/26 1.2s} bxc4 {-0.02/28 6.7s}
20. bxc4 {+0.44/27 0.35s} Kd8 {-0.10/28 17s} 21. Bc3 {+0.41/29 6.9s}
Kc7 {-0.20/23 0.72s} 22. Na4 {+0.63/29 8.6s} Bg7 {-0.17/24 0.22s}
23. Kf2 {+0.61/24 9.5s} Ba6 {-0.22/27 2.2s} 24. Nab2 {+0.49/26 10s}
Bc8 {-0.21/27 4.2s} 25. Nd1 {+0.58/25 7.7s} Nh6 {-0.20/25 4.1s}
26. Ba5+ {+0.62/24 11s} Kd7 {0.00/35 7.3s} 27. Bc3 {+0.63/25 0.47s}
Kc7 {0.00/42 6.1s} 28. Nb4 {+0.48/26 7.8s} Bd7 {-0.32/23 6.5s}
29. Ne3 {+0.47/25 2.5s} Kb6 {-0.23/25 7.1s} 30. Nd3 {+0.47/24 11s}
Be8 {-0.25/27 9.0s} 31. Nc5 {+0.52/27 2.4s} Bf7 {-0.22/27 7.7s}
32. Kg3 {+0.45/28 19s} Kc7 {-0.29/30 9.6s} 33. Na6+ {+0.44/25 16s}
Kb6 {-0.21/26 6.8s} 34. Nb4 {+0.44/26 0.59s} Bf6 {-0.31/28 7.4s}
35. Nd3 {+0.44/27 2.5s} Bh5 {-0.41/28 16s} 36. Nb4 {+0.44/26 14s}
Bf7 {0.00/42 7.3s} 37. Nd3 {+0.53/26 8.4s} Bh5 {0.00/50 8.4s}
38. Bb2 {+0.43/25 7.2s} Bg6 {-0.03/26 13s} 39. Ba1 {+0.40/24 5.0s}
Ka5 {-0.01/25 13s} 40. Bc3+ {+0.71/25 6.9s} Ka4 {-0.23/28 6.6s}
41. Kh2 {+0.52/24 5.5s} Kb3 {0.00/28 19s} 42. Nc1+ {+0.48/29 7.0s}
Ka4 {0.00/31 9.4s} 43. Kh3 {+0.39/27 16s} Bh5 {0.00/30 15s}
44. Kg3 {+0.29/29 23s} Bg7 {-0.06/33 46s} 45. Ne2 {+0.40/24 13s}
Kb3 {0.00/31 0.58s} 46. Nc1+ {+0.40/26 11s} Ka4 {0.00/66 5.4s}
47. Nc2 {+0.40/25 16s} Ng8 {0.00/28 9.6s} 48. Nd3 {+0.33/25 14s}
Nh6 {0.00/30 2.5s} 49. Nc1 {+0.20/26 15s} Ng8 {0.00/38 5.1s}
50. d3 {+0.22/25 3.6s} Nh6 {0.00/28 5.8s} 51. Kf2 {0.00/24 0.45s}
Be8 {+0.19/25 8.8s} 52. Bd2 {0.00/27 12s} Nf7 {+0.09/27 3.5s}
53. Ne2 {0.00/27 2.1s} Bd7 {+0.15/25 2.4s} 54. Ke1 {0.00/28 9.5s}
e5 {+0.22/27 12s} 55. d5 {0.00/28 7.0s} cxd5 {+0.22/27 14s}
56. cxd5 {0.00/28 7.9s} g4 {+0.33/25 3.9s} 57. fxg4 {0.00/30 1.5s}
Bxg4 {+0.25/24 2.4s} 58. Ne3 {0.00/31 5.6s} Bh3 {+0.35/25 1.6s}
59. Kd1 {0.00/26 7.9s} Ng5 {+0.43/27 11s} 60. Nc4 {-0.13/26 14s}
Bf6 {+0.40/28 5.1s} 61. Kc2 {-0.14/26 5.2s} Kb5 {+0.43/26 2.7s}
62. Nc3+ {-0.15/27 2.7s} Ka6 {+0.53/24 4.9s} 63. Be3 {-0.19/26 0.55s}
Nf3 {+0.38/24 10s} 64. Na2 {-0.20/28 0.64s} Nd4+ {+0.52/26 3.5s}
65. Kc3 {-0.15/27 1.2s} Bg4 {+0.42/26 5.2s} 66. Nb4+ {-0.13/28 8.5s}
Kb5 {+0.37/30 2.6s} 67. Bf2 {0.00/29 2.8s} Bg5 {+0.45/26 15s}
68. Nc2 {0.00/31 6.2s} Ne2+ {+0.51/27 3.6s} 69. Kb3 {0.00/33 3.8s}
Bf3 {+0.47/24 0.30s} 70. Nb4 {0.00/29 5.1s} Nd4+ {+0.52/24 3.7s}
71. Bxd4 {0.00/34 3.4s} Bd1+ {0.00/34 4.7s} 72. Nc2 {0.00/37 5.7s}
exd4 {0.00/40 3.2s} 73. Nb2 {0.00/39 3.7s} Bxc2+ {0.00/42 4.8s}
74. Kxc2 {0.00/39 0.25s} Kb4 {0.00/42 5.1s} 75. Nc4 {0.00/41 27s}
Kb5 {0.00/53 0.002s} 76. Kb3 {0.00/40 35s} Bf6 {0.00/54 8.3s}
77. Na3+ {+0.19/30 2.0s} Ka5 {0.00/53 7.1s} 78. Nc2 {6.5s} Kb5 {0.00/65 13s}
79. Nb4 Bg7 {0.00/51 9.7s} 80. Nc6 {+0.34/33 1.4s} e5 {0.00/59 16s} 81. Nd8
Bf8 {0.00/55 10s} 82. Ka2 {+0.34/29 23s} Kb4 {0.00/35 9.3s}
83. Kb2 {+0.34/28 59s} Bh6 {0.00/71 35s} 84. Ne6 {13s} Bd2 {0.00/50 6.6s}
85. Kc2 {+0.34/22 46s} Be3 {0.00/56 16s} 86. Nf8 {21s} Kb5 {0.00/47 6.1s}
87. Kb2 {27s} Kb4 {0.00/82 72s} 88. Kc2 {+0.34/21 3.9s} Bg5 {0.00/85 0.099s}
89. Ne6 {+0.34/26 28s} Be3 90. Ng7 {+0.34/18 3.7s} Bg5 {0.00/63 14s}
91. Kb2 {+0.34/18 3.7s} Bf4 {0.00/56 4.1s} 92. Kc2 {+0.34/30 3.4s}
Bg5 {0.00/99 0.050s} 93. Kb2 {+0.34/31 20s} Bf4 {0.00/71 8.4s}
94. Nf5 {+0.34/31 2.4s} Kc5 {0.00/42 5.6s} 95. Kb3 {9.8s} Bg5 {0.00/49 3.8s}
96. Ng7 {+0.34/27 13s} Bf6 {0.00/59 4.5s} 97. Ne6+ {+0.34/33 9.8s}
Kb5 {0.00/72 8.8s} 98. Nc7+ Kc5 {0.00/72 15s} 99. Ka4 Bh4 {0.00/46 2.6s}
100. Ne8 {5.0s} Bd8 {0.00/62 26s} 101. Ng7 {+0.34/36 0.74s} Kb6 {0.00/42 2.4s}
102. Kb4 {+0.34/32 0.67s} Be7 {0.00/63 1.8s} 103. Ne6 {+0.34/36 0.65s}
Bh4 {0.00/71 2.2s} 104. Nf8 {+0.34/37 5.4s} Be7 {0.00/69 2.9s} 105. Ne6 {1.5s}
Bh4 {White's connection stalls} 0-1
=========================================================
[White "Ethereal"]
[Black "stockfish"]
[Result "0-1"]
[FEN "1rbqkbr1/2nppn2/1pppppp1/8/8/1PPPPPP1/2NPPN2/1RBQKB1R b - - 1 1"]
[GameDuration "00:02:23"]
[GameEndTime "2019-11-05T02:26:01.063 SAST"]
[GameStartTime "2019-11-05T02:23:37.139 SAST"]
[PlyCount "15"]
[SetUp "1"]
[Termination "stalled connection"]
[TimeControl "40/300"]
1... Bg7 {-0.14/24 15s} 2. Ra1 {+0.20/21 8.4s} d5 {0.00/24 5.7s}
3. Bb2 {+0.32/20 6.7s} Nd6 {+0.46/22 2.0s} 4. e4 {+0.06/19 7.1s}
Kf7 {+0.56/23 6.9s} 5. f4 {+0.19/22 33s} Rh8 {+0.80/23 6.0s}
6. Rxh8 {0.00/21 6.0s} Qxh8 {+1.00/24 2.7s} 7. exd5 {+0.12/22 3.2s}
exd5 {+0.68/27 19s} 8. e4 {-0.10/23 8.1s}
c5 {+0.71/25 0s, White's connection stalls} 0-1
=====================================================
[White "stockfish"]
[Black "Ethereal"]
[Result "1-0"]
[FEN "1rbqkbr1/2nppn2/1pppppp1/8/8/1PPPPPP1/2NPPN2/1RBQKB1R b - - 1 1"]
[GameDuration "00:07:24"]
[GameEndTime "2019-11-05T02:33:31.063 SAST"]
[GameStartTime "2019-11-05T02:26:06.067 SAST"]
[PlyCount "32"]
[SetUp "1"]
[Termination "time forfeit"]
[TimeControl "40/300"]
1... Bg7 {-0.24/20 15s} 2. e4 {+0.73/25 24s} Ra8 {-0.20/19 11s}
3. Bg2 {+0.71/22 6.2s} Bb7 {-0.24/22 4.9s} 4. Bb2 {+0.49/22 14s}
e5 {-0.22/24 5.8s} 5. Kf1 {+0.46/20 1.1s} Ra2 {0.00/22 7.1s}
6. d4 {+0.77/22 4.3s} exd4 {+0.27/21 6.5s} 7. cxd4 {+0.48/22 0.50s}
f5 {+0.21/19 5.4s} 8. Qc1 {+0.24/25 36s} Nb5 {+0.23/22 17s}
9. Kg1 {+0.55/20 6.1s} e6 {+0.15/22 9.9s} 10. e3 {+0.07/23 18s}
Ra8 {+0.24/23 5.1s} 11. Nb4 {+0.31/23 15s} Qe7 {+0.42/21 8.6s}
12. Nbd3 {+0.28/23 2.2s} Rh8 {0.00/22 8.8s} 13. Rxh8+ {+0.40/20 2.1s}
Bxh8 {0.00/24 7.7s} 14. Bf1 {+0.60/24 5.9s} Ng5 {0.00/23 13s}
15. Kg2 {+0.70/23 8.4s} fxe4 {0.00/24 15s} 16. Nxe4 {+0.17/26 1.8s}
Nxe4 {-0.20/23 4.9s} 17. fxe4 {+0.09/24 0s, Black loses on time} 1-0
=============================================
[White "Ethereal"]
[Black "stockfish"]
[Result "0-1"]
[FEN "1rbqkbr1/1pnppnp1/2pppp2/8/8/2PPPP2/1PNPPNP1/1RBQKBR1 w - - 0 1"]
[GameDuration "00:16:12"]
[GameEndTime "2019-11-04T22:50:56.069 SAST"]
[GameStartTime "2019-11-04T22:34:43.124 SAST"]
[PlyCount "98"]
[SetUp "1"]
[Termination "time forfeit"]
[TimeControl "40/300"]
===============================================
[White "stockfish"]
[Black "Ethereal"]
[Result "1-0"]
[FEN "1rbqkbr1/1pnppnp1/2pppp2/8/8/2PPPP2/1PNPPNP1/1RBQKBR1 w - - 0 1"]
[GameDuration "00:01:03"]
[GameEndTime "2019-11-04T22:52:00.064 SAST"]
[GameStartTime "2019-11-04T22:50:56.079 SAST"]
[PlyCount "7"]
[SetUp "1"]
[Termination "stalled connection"]
[TimeControl "40/300"]
==============================================
8/2n5/2B5/8/5p1p/5P1P/5kP1/7K w - - 2 2
should be lost for white.
Forcing boardIsDrawn()
to return 0
fixes it.
int boardIsDrawn(Board *board, int height) {
// Drawn if any of the three possible cases
return drawnByFiftyMoveRule(board)
|| drawnByRepetition(board, height)
|| drawnByInsufficientMaterial(board);
}
Forcing drawnByFiftyMoveRule()
to return 0
does not fix it
Forcing drawnByRepetition()
to return 0
DOES fix it
Forcing drawnByInsufficientMaterial
to return 0
does not fix it
Is this a bug or intentional?
#define TB_PAWN_ATTACKS(square, color) (pawnAttacks((square), ~0ull, (!color)))
I don't understand. WHen I look at the definition of pawnAttacks() it looks correct (no colour inversion).
[X] attacks.c [X] attacks.h [X] bitboards.c
[X] bitboards.h [X] board.c [X] board.h
[X] evaluate.c [X] evaluate.h [X] history.c
[X] history.h [X] masks.c [X] masks.h
[X] move.c [X] move.h [X] movegen.c
[X] movegen.h [X] movepicker.c [X] movepicker.h
[X] psqt.c [X] psqt.h [X] search.c
[X] search.h [X] syzygy.c [X] syzygy.h
[X] texel.c [X] texel.h [X] thread.c
[X] thread.h [X] time.c [X] time.h
[X] transposition.c [X] transposition.h [X] types.h
[X] uci.c [X] uci.h [X] windows.c
[X] windows.h [X] zobrist.c [X] zobrist.h
search.c, line 296
I'm not sure, but maybe that's
if (value >= beta)
Should SEE Pruning only be applied to movePicker.stage > STAGE_GOOD_NOISY? Is it trying to prune table move?
at the end of the following engine-vs-engine game, Ethereal 11.57 evaluates the position as winning by +9, but it doesn't know how to mate with only knight and bishop .. it lets the opponent king go to the wrong corner .. the game ends with a stalemate .. in this theme game Black should be able to win :
[Event "engine vs engine - theme game"]
[Site "Hengelo, Holland - https://lichess.org/eSUK0nC1"]
[Date "2019.11.24"]
[White "asmFish 190518"]
[Black "Ethereal 11.57"]
[Result "1/2-1/2"]
[PlyCount "159"]
[SetUp "1"]
[TimeControl "40/300"]
[FEN "rnbqkbnr/ppp1ppp1/8/3p3p/3P1B2/4P3/PPP2PPP/RN1QKBNR b KQkq - 0 1"]
1...e5 2. Bxe5 f6 3. Bf4 g5 4. Be2 gxf4 5. Bxh5+ Ke7 6. exf4 c6 7. Qd3 Qd6 8. Bf3 Qxf4 9. Ne2 Qd6 10. h3 f5 11. c4 Nf6 12. cxd5 cxd5 13. O-O Nc6 14. Nbc3 a6 15. Rfe1 Kd8 16. Rad1 Ne4 17. Qc2 Bd7 18. Qb3 Ne7 19. g3 Bh6 20. Bg2 Rc8 21. Qxb7 Rb8 22. Qa7 Nc8 23. Nxe4 fxe4 24. Qc5 Rxb2 25. Qa5+ Ke8 26. Nc3 Rf8 27. Qxd5 Rfxf2 28. Qg8+ Qf8 29. Rxe4+ Ne7 30. Qxf8+ Kxf8 31. Rf1 Rxf1+ 32. Bxf1 Bd2 33. Ne2 Rxa2 34. Re5 a5 35. Nf4 a4 36. Ne6+ Bxe6 37. Rxe6 Bc3 38. Rf6+ Kg7 39. Rf7+ Kxf7 40. Bc4+ Kf6 41. Bxa2 Bxd4+ 42. Kg2 Nc6 43. Kf3 Nb4 44. Bc4 a3 45. Ke4 Bf2 46. g4 a2 47. g5+ Kxg5 48. Bxa2 Nxa2 49. Kd3 Kh4 50. Kc4 Kxh3 51. Kb3 Nc1+ 52. Kc2 Be3 53. Kc3 Kg4 54. Kc4 Kg5 55. Kd5 Kf5 56. Kd6 Bf4+ 57. Kd5 Be3 58. Kd6 Bf4+ 59. Kd5 Nb3 60. Kc4 Nd2+ 61. Kd4 Ke6 62. Kd3 Kd5 63. Ke2 Ke4 64. Kf2 Nb3 65. Kf1 Kf3 66. Kg1 Nd4 67. Kh1 Bg3 68. Kg1 Nf5 69. Kh1 Bf2 70. Kh2 Nd4 71. Kh1 Bg3 72. Kg1 Bf2+ 73. Kh2 Ne2 74. Kh1 Be3 75. Kh2 Bf2 76. Kh1 Be3 77. Kh2 Bf4+ 78. Kh1 Nd4 79. Kg1 Ne2+ 80. Kh1 Bg3 1/2-1/2
Hi Andy,
do y plan to support this?
go movetime 100 searchmoves f2f3 a2a3
bestmove e2e4 ponder c7c5
I use this for "alternative move" at picochess, which is a great feature in my eyes.
Jürgen
Hi Andy. I made my version of Ethereal-8.76 for android.For the arm7 version, I applied not only LTO, but also PGO optimization, which gave an increase in speed compared to the original by 30%! The version for arm64v8 is faster than the original arm7 version by 80% ! You can download here:
https://app.box.com/s/wp1wkv7ao0dj45yksjjkxz572a31ivhy
Need to create special PSQT table for KNB v K endgame, and then apply it when this endgame is reached. I have no idea what % of games I draw when I could have won as a result of not having this, but I imagine it is a guaranteed ELO gain to implement it.
An issue while working on lucasarts/zinc made me realize that my program does not work properly when it receives a position fen command which has two spaces between 'fen' and the fen string. Additionally, UCI.c was kinda sloppy.
Hi.
Have a look at this:
uci
id name Ethereal 11.53
id author Andrew Grant & Laldon
option name Hash type spin default 16 min 1 max 65536
option name Threads type spin default 1 min 1 max 2048
option name MoveOverhead type spin default 100 min 0 max 10000
option name SyzygyPath type string default
option name SyzygyProbeDepth type spin default 0 min 0 max 127
option name Ponder type check default false
option name UCI_Chess960 type check default false
uciok
position fen 8/8/8/4B3/8/2N2K2/8/6k1 w - - 22 12
go depth 30
info depth 1 seldepth 1 score cp 900 time 0 nodes 6 nps 6000 tbhits 0 hashfull 0 pv f3f4
info depth 2 seldepth 2 score cp 915 time 0 nodes 25 nps 25000 tbhits 0 hashfull 0 pv f3e4 g1g2
info depth 3 seldepth 3 score cp 893 time 0 nodes 77 nps 77000 tbhits 0 hashfull 0 pv f3g3 g1f1 g3f4
info depth 4 seldepth 4 score cp 898 time 0 nodes 112 nps 112000 tbhits 0 hashfull 0 pv f3g3 g1f1 g3f4 f1g2
info depth 5 seldepth 6 score cp 901 time 0 nodes 357 nps 357000 tbhits 0 hashfull 0 pv f3e4 g1f1 e4d4 f1f2 d4d5
info depth 6 seldepth 7 score cp 949 time 0 nodes 952 nps 952000 tbhits 0 hashfull 0 pv f3e4 g1h1 e4d4 h1g1 c3d5 g1g2
info depth 7 seldepth 8 score cp 983 time 16 nodes 2525 nps 148000 tbhits 0 hashfull 0 pv e5g3 g1h1 c3d1 h1g1 d1e3 g1h1 f3e4
info depth 8 seldepth 11 score cp 959 time 16 nodes 3588 nps 211000 tbhits 0 hashfull 0 pv e5g3 g1h1 c3d1 h1g1 d1f2 g1f1 f2e4 f1g1
info depth 9 seldepth 10 score cp 994 time 16 nodes 5529 nps 325000 tbhits 0 hashfull 1 pv c3d1 g1f1 d1e3 f1g1 e5b8 g1h1 f3g3 h1g1 b8f4 g1h1
info depth 10 seldepth 13 score cp 976 time 31 nodes 12238 nps 382000 tbhits 0 hashfull 3 pv c3d1 g1f1 d1e3 f1g1 e5f4 g1h1 f3e2 h1g1 f4b8 g1h1 b8c7
info depth 11 seldepth 16 score cp 983 time 31 nodes 20418 nps 638000 tbhits 0 hashfull 3 pv c3d1 g1f1 d1e3 f1g1 e5f4 g1h1 f3e2 h1g1 f4b8 g1h1 e2e1 h1g1 b8f4 g1h1
info depth 12 seldepth 18 score cp 970 time 47 nodes 36195 nps 754000 tbhits 0 hashfull 5 pv e5g3 g1f1 c3d1 f1g1 d1e3 g1h1 f3e4 h1g1 e4f4 g1h1 f4f3 h1g1 f3e2 g1h1 e2f1
info depth 13 seldepth 23 score cp 967 time 62 nodes 56402 nps 895000 tbhits 0 hashfull 8 pv e5g3 g1f1 c3d1 f1g1 d1e3 g1h1 f3e4 h1g1 e4f4 g1h1 f4f3 h1g1 f3e2 g1h1 e2d3 h1g1 d3e4 g1h1 e4d5 h1g1 d5e6
info depth 14 seldepth 22 score cp 975 time 94 nodes 92657 nps 975000 tbhits 0 hashfull 13 pv e5g3 g1f1 c3d1 f1g1 d1e3 g1h1 g3f2 h1h2 e3d5 h2h3 d5f4 h3h2 f3e4 h2h1 e4d5 h1h2 d5e6 h2h1 f2a7 h1h2
info depth 15 seldepth 24 score cp 993 time 141 nodes 160610 nps 1131000 tbhits 0 hashfull 20 pv e5g3 g1f1 c3d1 f1g1 d1e3 g1h1 g3f2 h1h2 e3d5 h2h3 d5f4 h3h2 f3e4 h2h1 e4d5 h1h2 d5e6 h2h1 e6f7 h1h2 f7g7 h2h1 f2a7
info depth 16 seldepth 32 score cp 981 time 359 nodes 455951 nps 1266000 tbhits 0 hashfull 53 pv e5g3 g1f1 c3d1 f1g1 d1e3 g1h1 g3f2 h1h2 e3d5 h2h3 d5f4 h3h2 f3e4 h2h1 e4d5 h1h2 d5e6 h2h1 e6f7 h1h2 f7e7 h2h1 e7d6 h1h2 d6c7 h2h1 c7d7 h1h2
Then... nothing. Output just stops at depth 16. Ethereal process still at max cpu but it seems stuck. Same with go infinite.
I was trying to run your perft.py script, to do some speed measures on #47. But it crashed. So I tried master, it also crashed. Here's the minimal reproduction with master:
ucinewgame
position fen 1r1qk2r/5ppp/Q2p4/6R1/4P1bq/2N5/P1P5/4K1N1 b k - 0 23
print
|---|---|---|---|---|---|---|---|
8 | . | r | . | q | k | . | . | r |
|---|---|---|---|---|---|---|---|
7 | . | . | . | . | . | p | p | p |
|---|---|---|---|---|---|---|---|
6 | Q | . | . | p | . | . | . | . |
|---|---|---|---|---|---|---|---|
5 | . | . | . | . | . | . | R | . |
|---|---|---|---|---|---|---|---|
4 | . | . | . | . | P | . | b | q |
|---|---|---|---|---|---|---|---|
3 | . | . | N | . | . | . | . | . |
|---|---|---|---|---|---|---|---|
2 | P | . | P | . | . | . | . | . |
|---|---|---|---|---|---|---|---|
1 | . | . | . | . | K | . | N | . |
|---|---|---|---|---|---|---|---|
A B C D E F G H
fen: 1r1qk2r/5ppp/Q2p4/6R1/4P1bq/2N5/P1P5/4K1N1 b k - 0
perft 1
Segmentation fault (core dumped)
compile with Windows msys2 (gcc 8.2):
$ make
gcc -DNDEBUG -O3 -std=gnu11 -Wall -Wextra -Wshadow -march=native -flto *.c fathom/tbprobe.c -lpthread -lm -DUSE_POPCNT -msse3 -mpopcnt -o Ethereal
windows.c: In function 'bestGroup':
windows.c:39:25: warning: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'void (*)()' [-Wcast-function-type]
fun1_t fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
^
windows.c:39:17: warning: cast between incompatible function types from 'void (*)()' to 'int (*)(LOGICAL_PROCESSOR_RELATIONSHIP, struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *, DWORD *)' {aka 'int (* )(enum _LOGICAL_PROCESSOR_RELATIONSHIP, struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *, long unsigned int *)'} [-Wcast-function-type]
fun1_t fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx");
^
windows.c: In function 'bindThisThread':
windows.c:103:25: warning: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'void (*)()' [-Wcast-function-type]
fun2_t fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
^
windows.c:103:17: warning: cast between incompatible function types from 'void (*)()' to 'int (*)(USHORT, struct _GROUP_AFFINITY *)' {aka 'int (*)(short unsigned int, struct _GROUP_AFFINITY *)'} [-Wcas t-function-type]
fun2_t fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx");
^
windows.c:104:25: warning: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'void (*)()' [-Wcast-function-type]
fun3_t fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
^
windows.c:104:17: warning: cast between incompatible function types from 'void (*)()' to 'int (*)(void *, const GROUP_AFFINITY *, struct _GROUP_AFFINITY *)' {aka 'int (*)(void *, const struct _GROUP_AFFI NITY *, struct _GROUP_AFFINITY *)'} [-Wcast-function-type]
fun3_t fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity");
^
functionality seems ok: 100% cpu is used with numa branch when all threads (80) are used,
with master windows show max cpu-load for ethereal 50,7%
// If the root position can be found in the DTZ tablebases,
// then we simply return the move recommended by Syzygy/Fathom.
The current code ensure that draws stay draws and wins stay wins, but it's pretty sad to see Ethereal make a mate announcement with 7 or 8 pieces on the board, then take 15 more moves to mate because DTZ is followed in 6-men syzygy positions.
As of now, the method of leaving the search routines due to the final allocated time margin being passed will return -Mate scores. This is annoying, and problematic.
Can you use noise move picker on ProbCut? Seems like you could save a static exchange evaluation call since it is already called on MovePicker with a threshold. Something like this:
initNoiseMovePicker(&movePicker, thread, rBeta - eval);
or if rBeta - eval can be negative:
initNoiseMovePicker(&movePicker, thread, MAX(0, rBeta - eval));
and remove the SEE inside ProbCut loop.
Add back spacing with next patch
Assertion is here
This line is NOT in Ronald's tb/master branch. I've reached out to him to ask if the assertion was placed there in error.
Steps to reproduce:
With a debug compile...
setoption name SyzygyPath value <path>
position fen 1R6/4k3/7P/P2p4/1PK3p1/8/8/r7 w - - 0 53
go infinite
Also, it appears that if I cap TB_LARGEST at 5, the assertion is never hit. Which would give evidence to this being an artifact from a time where Fathom could only probe 5 piece positions. (I'm not sure if Fathom was ever in that state, however ....)
Hello Mr.,
I found Ethereal 11.11 on the internet, and when I create an engine match with time control 40 Moves in 30 Minutes reapiting, for first 40 moves Ethereal doesn't have this problem, but in second intermediar time (moves from 41 to 80) I saw that Ethereal remains with less than 10 seconds for I think 14 or 15 moves.
This situation happened more than once.
Thanks.
and unreset it while unmaking null move.
this is likely the source of transposition table issue You mentioned on TalkChess
Using several function instead of popcount should give a small speed improvement.
evaluateMoves & getNextMove are the next step in terms of raw performance. Cutting that down to a staged move generation of sorts would likely be faster.
The heuristic for move values is also pretty awful. Likely can find a better way of doing things, in addition to a speed up.
Hi
Is this Windows-only?
Thanks, Ian
No real issue but maybe worth to investigate:
I compared the see pruning margings that are used for quiet and tacticle moves in different engines (to get an idea what is worth testing in my engine):
Laser:
SF:
Ethereal:
Xiphos:
Yours is the only that uses squared depth for tacticle moves instead of quiet moves. Have you tested the other way round?
board->pieceBitBoards ---> board->pieces
board->colourBitBoards ---> board->colours
remove all magic nums in index pieceBitBoards
actually keep track of the 50 move rule.....
among other things.
How do we build it in definitive way on Mingw/Msys?
Stockfish's basic graph for Depth/Movecount : https://imgur.com/a/18hJXuy
Ethereal's basic graph for Depth/Movecount : https://imgur.com/a/1YMbIWD
Most testing is likely too low a time control to see the real negative effects of Ethereal's formula.
Should not be any issues with the Transposition Table cutting off PV-lines, due to a Fruit trick to not use Tables for cut-offs in PV-Nodes (Costs a few Elo points). Should be simple to save the PV.
Engine is prone to losses on time when making the 40th, 80th, ect... move of a game
This isn't the case at the moment.
It is a real to compile Ethereal with Windows "native" Clang, MSVC or Intel Compiler
But it is a one problem - posix threads
If You have "windows.c" and "windows.h", could it possible to implement more portable solution for threads?
I never used threads into Pure C, but there is portable example for C++ below which works on Windows32/64, Linux, FreeBSD and Solaris as well:
thread.h:
#ifndef _EXT_THREAD_H
#define _EXT_THREAD_H
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <signal.h>
#endif
namespace ext {
#ifdef WIN32
typedef HANDLE ThreadType;
#else
typedef pthread_t ThreadType;
#endif
class Thread {
public:
Thread() {}
virtual ~Thread();
void Start();
virtual void Execute() = 0;
void Join();
void Kill();
private:
ThreadType __handle;
Thread(const Thread&);
void operator=(const Thread&);
};
} // ext
#endif
thread.cpp:
#include "thread.h"
namespace ext {
static void ThreadCallback(Thread* who) {
#ifndef WIN32
int old_thread_type;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_thread_type);
#endif
who->Execute();
}
#ifdef WIN32
Thread::~Thread() {
CloseHandle(__handle);
}
void Thread::Start() {
__handle = CreateThread(
0, 0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(ThreadCallback), this,
0, 0
);
}
void Thread::Join() {
WaitForSingleObject(__handle, INFINITE);
}
void Thread::Kill() {
TerminateThread(__handle, 0);
}
#else
Thread::~Thread() {
}
extern "C"
typedef void *(*pthread_callback)(void *);
void Thread::Start() {
pthread_create(
&__handle, 0,
reinterpret_cast<pthread_callback>(ThreadCallback),
this
);
}
void Thread::Join() {
pthread_join(__handle, 0);
}
void Thread::Kill() {
pthread_cancel(__handle);
}
#endif
} // ext
Example for one thread:
#include <iostream>
#include "thread.h"
class MyThread: public ext::Thread {
public:
MyThread() : __done(false) {}
virtual void Execute() {
__done = true;
}
bool done() const { return __done; }
private:
bool __done;
};
int main(int argc, char* argv[]) {
MyThread thread;
std::cout << "Thread status before: " << thread.done() << std::endl;
thread.Start();
thread.Join();
std::cout << "Thread status after: " << thread.done() << std::endl;
}
Example for 10 threads:
#include <vector>
#include <iostream>
#include "thread.h"
class MyThread: public ext::Thread {
public:
MyThread(int id) : __id(id), __done(false) {}
virtual void Execute() {
if (__id != 3)
__done = true;
}
bool done() const { return __done; }
private:
int __id;
bool __done;
};
typedef std::vector<MyThread*> Threads;
int main(int argc, char* argv[]) {
std::vector<MyThread*> threads;
for (int i = 0; i < 10; i++)
threads.push_back(new MyThread(i));
for (Threads::iterator i = threads.begin(); i != threads.end(); i++)
(*i)->Start();
for (Threads::iterator i = threads.begin(); i != threads.end(); i++)
(*i)->Join();
for (Threads::iterator i = threads.begin(); i != threads.end(); i++)
std::cout << (*i)->done() << " ";
std::cout << std::endl;
for (Threads::iterator i = threads.begin(); i != threads.end(); i++)
delete *i;
}
Ethereal is wrong -- if mate has been delivered, there is no draw by fifty move rule.
we already have the inCheck
flag. We can use genAllLegalMoves()
as a quick hack ... At some point we should have a moveIsLegal
function ...
I made an experiment and matched "EtherealTrueRandom" vs "Teki Random Mover" (see https://github.com/Mk-Chan/Teki/tree/v0.1) and expected them to be very evenly matched, they are both random movers after all. Instead, I got the following:
Score of EtherealTrueRandom (8.97) vs Teki: 1265 - 638 - 8097 [0.531] 10000
Elo difference: 21.81 +/- 2.95
Finished match
So, as per your advice, I contacted Manik and asked him to look at your code and compare it to Ethereal. Here's what he has to say:
It seems Andrew is using movelist[rand() % size] to get a random move. The problem is that this is not truly random. My random function uses c++11s standard library uniform integer random distribution which has been shown to be much closer to a real uniformly random distribution. Source: https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
Technical explanation:
Because size is not always a multiple of the range of rand() [which by itself is a bad rng by virtue of being linear congruential in glibc], rand() % size does not resolve to an integral number of sets of [0, size). The last set(for the [RANDMAX - size + 1, RANDMAX] will have less of a range and thus reduced randomness. This slightly favors moves in the earlier part of the movelist, which, judging by ethereal random's movegen are pawn moves. My suspicion is that ethereal moves pawns and queens a lot more than Teki.Regards,
Manik
I also made another experiment, I matched EtherealTrueRandom against itself for 100k games and looked at the ECO openings distribution, here's the result:
Games = 100000 ( no result = 0, FEN tags = 0 )
Players = 1 ( clusters = 1 )
Date Range: 2018.03.09 - 2018.03.09Games with: WhiteElo = 0 BlackElo = 0 BothElos = 0
White Wins = 7789 ( 7.79 % )
Draws = 84413 ( 84.41 % )
Black Wins = 7798 ( 7.8 % )
White Pct = 50.0 %
Black Pct = 50.0 %ECO: Total = 100000 A: 94732 B: 4477 C: 504 D: 287 E: 0
PlyCount: Total = 100000 Range: 4-865 Average = 340.21 StdDev = 112.12finished: be sure to rename/copy outSummary
There's very little variation. Then I did the same with Teki and there's little variation too, but it's a bit better:
Games = 100000 ( no result = 0, FEN tags = 0 )
Players = 1 ( clusters = 1 )
Date Range: 2018.03.09 - 2018.03.09Games with: WhiteElo = 0 BlackElo = 0 BothElos = 0
White Wins = 8973 ( 8.97 % )
Draws = 82274 ( 82.27 % )
Black Wins = 8753 ( 8.75 % )
White Pct = 50.11 %
Black Pct = 49.89 %ECO: Total = 100000 A: 90834 B: 781 C: 4178 D: 4207 E: 0
PlyCount: Total = 100000 Range: 6-901 Average = 357.18 StdDev = 154.9finished: be sure to rename/copy outSummary
I don't know if you're using random generation for anything in the "real" version of Ethereal, but if you are, maybe this will help you make it better :)
Based on discussion of http://talkchess.com/forum/viewtopic.php?t=61533
Add Zorbist Keys for Enpass Square and Castling Rights
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.