1
0
Fork 0

python-chess on cartesi

master
server 2021-11-17 11:47:22 -07:00
commit d6f4b4f3ea
29 changed files with 18819 additions and 0 deletions

1
.gitignore vendored 100644
View File

@ -0,0 +1 @@
*.ext2

22
README.md 100644
View File

@ -0,0 +1,22 @@
# Cartesi python-chess
Crufty scripts to build disk images to run under the Cartesi
RISC-V machine emulator that verify a chess game. Similar
to the Cartesi example, but this is in python using python-chess,
not javascript.
# Upstream
## Python Chess
* https://python-chess.readthedocs.io/en/latest/
* https://github.com/niklasf/python-chess/
# # Cartesi
* https://cartesi.io/docs/intro
* https://github.com/cartesi/poker/tree/master/blockchain/verifier/chess
* https://medium.com/cartesi/how-cartesi-is-changing-the-game-showcasing-chess-9f4e39d5cea0

View File

@ -0,0 +1,5 @@
#!/bin/bash
# Make disk image with script
genext2fs -b 1024 -d cartesi-python-chess-cartesi-img cartesi-python-chess.ext2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -x
/mnt/cartesi-python-chess/python-chess-validate.py
exit

View File

@ -0,0 +1,47 @@
[Event "Grand Slam Final Masters"]
[Site "Bilbao ESP"]
[Date "2010.10.11"]
[Round "3"]
[White "Shirov, Alexei"]
[Black "Carlsen, Magnus"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2749"]
[BlackElo "2826"]
[ECO "C95"]
[Opening "Ruy Lopez"]
[Variation "closed, Breyer, Borisenko variation"]
[WhiteFideId "2209390"]
[BlackFideId "1503014"]
[EventDate "2010.10.09"]
[EventType "DRR"]
1. e4 e5 2. Nf3 Nc8 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3
O-O 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. a4 Bf8 14. Bd3 c6 15. b4
Nb6 16. axb5 cxb5 17. d5 Rc8 18. Bb2 Nh5 19. Bf1 f5 20. Nxe5 Rxe5 21. c4 Nf6 22.
Bxe5 dxe5 23. c5 fxe4 24. d6 Na4 25. Nc4 Nxc5 26. bxc5 Rxc5 27. Qb3 Bd5 28. Qb4
Rxc4 29. Bxc4 bxc4 30. Rxa6 Qc8 31. Qa5 c3 32. d7 Qxd7 33. Qxc3 Qb7 34. Rea1 Qb8
35. Ra7 h6 36. Rc7 Qb6 37. Qxe5 Bd6 38. Rc8+ Kf7 39. Qc3 Qb7 40. Rca8 Qxa8 41.
Rxa8 Bxa8 42. Qd4 Bd5 43. Qa7+ Be7 44. Qc7 h5 45. Qe5 g6 46. Kh2 Be6 47. Kg1 Bf5
48. Kf1 Ne8 49. Kg1 Ng7 50. Qd5+ Ne6 51. Qb7 h4 52. Kh2 Nf4 53. Kg1 Nd3 54. Kf1
Nc5 55. Qd5+ Be6 56. Qe5 Bf5 57. Qd5+ Ne6 58. Qb7 Kf8 59. Qa8+ Bd8 60. Qa7 Bf6
61. Qb7 Kg8 62. Qa7 Bg5 63. Ke2 Nf4+ 64. Kf1 Nh5 65. Ke2 Kf8 66. Kf1 Bf6 67. Qc7
Ng7 68. Qa7 Ne6 69. Qb7 Nd8 70. Qa7 Nf7 71. Kg1 Kg7 72. Kf1 Be5 73. Qe7 g5 74.
Kg1 Bf6 75. Qb7 Kg6 76. Qd5 Ne5 77. Qg8+ Bg7 78. Qe8+ Kh6 79. Qe7 Nd3 80. Kf1
Nf4 81. Qd6+ Bg6 82. Qe7 Nd5 83. Qe6 Nf6 84. Kg1 Be8 85. Qf5 Bd7 86. Qe5 Kg6 87.
Kf1 Bf8 88. Kg1 Ba3 89. Qc7 Bb4 90. Qe5 Bd2 91. Qd4 Bf4 92. Qb6 Be8 93. Kf1 Bf7
94. Kg1 Kf5 95. Qa7 Be6 96. Kf1 Kg6 97. Qb6 Bd7 98. Kg1 Ba4 99. Qe6 Bb5 100. Qb6
Bc4 101. Qd4 Be6 102. Kf1 Bf5 103. Kg1 g4 104. hxg4 Bxg4 105. Qc3 Bf5 106. Qb3
Bg5 107. Kf1 Kh6 108. Kg1 Kg6 109. Kf1 Bd7 110. Kg1 Be8 111. Qc3 Bf7 112. Qe5
Bd5 113. Qc3 Be6 114. Qe5 Bd7 115. Qc3 Bf5 116. Qb3 Nh5 117. Qg8+ Ng7 118. Qb3
Ne6 119. Kh2 Bf6 120. Kg1 Bg7 121. Kf1 Ng5 122. Qb6+ Bf6 123. Kg1 h3 124. gxh3
Bxh3 125. Qd6 Bf5 126. Kg2 Nf3 127. Qd5 Kg5 128. Qg8+ Bg6 129. Qd5+ Be5 130.
Qd8+ Kh5 131. Qd5 Bf5 132. Qf7+ Kg4 133. Qg8+ Ng5 134. Qc4 Bf4 135. Qg8 Be6 136.
Qg7 Bf7 137. Qd4 Kf5 138. Qc5+ Be5 139. Qf8 Kg6 140. Qc5 Bf6 141. Qd6 Bc4 142.
Qc6 Be6 143. Qd6 Bg4 144. Qd5 Bf3+ 145. Kf1 Nf7 146. Kg1 Ne5 147. Qg8+ Kf5 148.
Qc8+ Kg5 149. Qg8+ Ng6 150. Qd5+ Kh6 151. Qe6 Be5 152. Qf5 Bf4 153. Qf6 Bg5 154.
Qe6 Kg7 155. Qd7+ Ne7 156. Qe6 Bf6 157. Kf1 Kg6 158. Kg1 Nf5 159. Qg8+ Kh5 160.
Qf7+ Kg5 161. Qg8+ Kf4 162. Qb8+ Kg4 163. Qg8+ Bg5 164. Qc8 Bf6 165. Qg8+ Kf4
166. Qb8+ Be5 167. Qb4 Nd4 168. Qf8+ Kg5 169. Qg8+ Kh6 170. Qf8+ Bg7 171. Qd6+
Kh5 172. Qh2+ Kg5 173. Qg3+ Bg4 174. Qe3+ Kf5 1/2-1/2

View File

@ -0,0 +1,47 @@
[Event "Grand Slam Final Masters"]
[Site "Bilbao ESP"]
[Date "2010.10.11"]
[Round "3"]
[White "Shirov, Alexei"]
[Black "Carlsen, Magnus"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2749"]
[BlackElo "2826"]
[ECO "C95"]
[Opening "Ruy Lopez"]
[Variation "closed, Breyer, Borisenko variation"]
[WhiteFideId "2209390"]
[BlackFideId "1503014"]
[EventDate "2010.10.09"]
[EventType "DRR"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3
O-O 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. a4 Bf8 14. Bd3 c6 15. b4
Nb6 16. axb5 cxb5 17. d5 Rc8 18. Bb2 Nh5 19. Bf1 f5 20. Nxe5 Rxe5 21. c4 Nf6 22.
Bxe5 dxe5 23. c5 fxe4 24. d6 Na4 25. Nc4 Nxc5 26. bxc5 Rxc5 27. Qb3 Bd5 28. Qb4
Rxc4 29. Bxc4 bxc4 30. Rxa6 Qc8 31. Qa5 c3 32. d7 Qxd7 33. Qxc3 Qb7 34. Rea1 Qb8
35. Ra7 h6 36. Rc7 Qb6 37. Qxe5 Bd6 38. Rc8+ Kf7 39. Qc3 Qb7 40. Rca8 Qxa8 41.
Rxa8 Bxa8 42. Qd4 Bd5 43. Qa7+ Be7 44. Qc7 h5 45. Qe5 g6 46. Kh2 Be6 47. Kg1 Bf5
48. Kf1 Ne8 49. Kg1 Ng7 50. Qd5+ Ne6 51. Qb7 h4 52. Kh2 Nf4 53. Kg1 Nd3 54. Kf1
Nc5 55. Qd5+ Be6 56. Qe5 Bf5 57. Qd5+ Ne6 58. Qb7 Kf8 59. Qa8+ Bd8 60. Qa7 Bf6
61. Qb7 Kg8 62. Qa7 Bg5 63. Ke2 Nf4+ 64. Kf1 Nh5 65. Ke2 Kf8 66. Kf1 Bf6 67. Qc7
Ng7 68. Qa7 Ne6 69. Qb7 Nd8 70. Qa7 Nf7 71. Kg1 Kg7 72. Kf1 Be5 73. Qe7 g5 74.
Kg1 Bf6 75. Qb7 Kg6 76. Qd5 Ne5 77. Qg8+ Bg7 78. Qe8+ Kh6 79. Qe7 Nd3 80. Kf1
Nf4 81. Qd6+ Bg6 82. Qe7 Nd5 83. Qe6 Nf6 84. Kg1 Be8 85. Qf5 Bd7 86. Qe5 Kg6 87.
Kf1 Bf8 88. Kg1 Ba3 89. Qc7 Bb4 90. Qe5 Bd2 91. Qd4 Bf4 92. Qb6 Be8 93. Kf1 Bf7
94. Kg1 Kf5 95. Qa7 Be6 96. Kf1 Kg6 97. Qb6 Bd7 98. Kg1 Ba4 99. Qe6 Bb5 100. Qb6
Bc4 101. Qd4 Be6 102. Kf1 Bf5 103. Kg1 g4 104. hxg4 Bxg4 105. Qc3 Bf5 106. Qb3
Bg5 107. Kf1 Kh6 108. Kg1 Kg6 109. Kf1 Bd7 110. Kg1 Be8 111. Qc3 Bf7 112. Qe5
Bd5 113. Qc3 Be6 114. Qe5 Bd7 115. Qc3 Bf5 116. Qb3 Nh5 117. Qg8+ Ng7 118. Qb3
Ne6 119. Kh2 Bf6 120. Kg1 Bg7 121. Kf1 Ng5 122. Qb6+ Bf6 123. Kg1 h3 124. gxh3
Bxh3 125. Qd6 Bf5 126. Kg2 Nf3 127. Qd5 Kg5 128. Qg8+ Bg6 129. Qd5+ Be5 130.
Qd8+ Kh5 131. Qd5 Bf5 132. Qf7+ Kg4 133. Qg8+ Ng5 134. Qc4 Bf4 135. Qg8 Be6 136.
Qg7 Bf7 137. Qd4 Kf5 138. Qc5+ Be5 139. Qf8 Kg6 140. Qc5 Bf6 141. Qd6 Bc4 142.
Qc6 Be6 143. Qd6 Bg4 144. Qd5 Bf3+ 145. Kf1 Nf7 146. Kg1 Ne5 147. Qg8+ Kf5 148.
Qc8+ Kg5 149. Qg8+ Ng6 150. Qd5+ Kh6 151. Qe6 Be5 152. Qf5 Bf4 153. Qf6 Bg5 154.
Qe6 Kg7 155. Qd7+ Ne7 156. Qe6 Bf6 157. Kf1 Kg6 158. Kg1 Nf5 159. Qg8+ Kh5 160.
Qf7+ Kg5 161. Qg8+ Kf4 162. Qb8+ Kg4 163. Qg8+ Bg5 164. Qc8 Bf6 165. Qg8+ Kf4
166. Qb8+ Be5 167. Qb4 Nd4 168. Qf8+ Kg5 169. Qg8+ Kh6 170. Qf8+ Bg7 171. Qd6+
Kh5 172. Qh2+ Kg5 173. Qg3+ Bg4 174. Qe3+ Kf5 1/2-1/2

View File

@ -0,0 +1,28 @@
[Event "Grand Slam Final Masters"]
[Site "Bilbao ESP"]
[Date "2010.10.11"]
[Round "3"]
[White "Shirov, Alexei"]
[Black "Carlsen, Magnus"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2749"]
[BlackElo "2826"]
[ECO "C95"]
[Opening "Ruy Lopez"]
[Variation "closed, Breyer, Borisenko variation"]
[WhiteFideId "2209390"]
[BlackFideId "1503014"]
[EventDate "2010.10.09"]
[EventType "DRR"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3
O-O 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. a4 Bf8 14. Bd3 c6 15. b4
Nb6 16. axb5 cxb5 17. d5 Rc8 18. Bb2 Nh5 19. Bf1 f5 20. Nxe5 Rxe5 21. c4 Nf6 22.
Bxe5 dxe5 23. c5 fxe4 24. d6 Na4 25. Nc4 Nxc5 26. bxc5 Rxc5 27. Qb3 Bd5 28. Qb4
Rxc4 29. Bxc4 bxc4 30. Rxa6 Qc8 31. Qa5 c3 32. d7 Qxd7 33. Qxc3 Qb7 34. Rea1 Qb8
35. Ra7 h6 36. Rc7 Qb6 37. Qxe5 Bd6 38. Rc8+ Kf7 39. Qc3 Qb7 40. Rca8 Qxa8 41.
Rxa8 Bxa8 42. Qd4 Bd5 43. Qa7+ Be7 44. Qc7 h5 45. Qe5 g6 46. Kh2 Be6 47. Kg1 Bf5
48. Kf1 Ne8 49. Kg1 Ng7 50. Qd5+ Ne6 51. Qb7 h4 52. Kh2 Nf4 53. Kg1 Nd3 54. Kf1
Nc5 55. Qd5+ Be6 56. Qe5 Bf5 57. Qd5+ Ne6 58. Qb7 Kf8 59. Qa8+ Bd8 60. Qa7 Bf6

View File

@ -0,0 +1,47 @@
[Event "Grand Slam Final Masters"]
[Site "Bilbao ESP"]
[Date "2010.10.11"]
[Round "3"]
[White "Shirov, Alexei"]
[Black "Carlsen, Magnus"]
[Result "1/2-1/2"]
[WhiteTitle "GM"]
[BlackTitle "GM"]
[WhiteElo "2749"]
[BlackElo "2826"]
[ECO "C95"]
[Opening "Ruy Lopez"]
[Variation "closed, Breyer, Borisenko variation"]
[WhiteFideId "2209390"]
[BlackFideId "1503014"]
[EventDate "2010.10.09"]
[EventType "DRR"]
1. e4 e5 2. Nf3 Nc8 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3
O-O 9. h3 Nb8 10. d4 Nbd7 11. Nbd2 Bb7 12. Bc2 Re8 13. a4 Bf8 14. Bd3 c6 15. b4
Nb6 16. axb5 cxb5 17. d5 Rc8 18. Bb2 Nh5 19. Bf1 f5 20. Nxe5 Rxe5 21. c4 Nf6 22.
Bxe5 dxe5 23. c5 fxe4 24. d6 Na4 25. Nc4 Nxc5 26. bxc5 Rxc5 27. Qb3 Bd5 28. Qb4
Rxc4 29. Bxc4 bxc4 30. Rxa6 Qc8 31. Qa5 c3 32. d7 Qxd7 33. Qxc3 Qb7 34. Rea1 Qb8
35. Ra7 h6 36. Rc7 Qb6 37. Qxe5 Bd6 38. Rc8+ Kf7 39. Qc3 Qb7 40. Rca8 Qxa8 41.
Rxa8 Bxa8 42. Qd4 Bd5 43. Qa7+ Be7 44. Qc7 h5 45. Qe5 g6 46. Kh2 Be6 47. Kg1 Bf5
48. Kf1 Ne8 49. Kg1 Ng7 50. Qd5+ Ne6 51. Qb7 h4 52. Kh2 Nf4 53. Kg1 Nd3 54. Kf1
Nc5 55. Qd5+ Be6 56. Qe5 Bf5 57. Qd5+ Ne6 58. Qb7 Kf8 59. Qa8+ Bd8 60. Qa7 Bf6
61. Qb7 Kg8 62. Qa7 Bg5 63. Ke2 Nf4+ 64. Kf1 Nh5 65. Ke2 Kf8 66. Kf1 Bf6 67. Qc7
Ng7 68. Qa7 Ne6 69. Qb7 Nd8 70. Qa7 Nf7 71. Kg1 Kg7 72. Kf1 Be5 73. Qe7 g5 74.
Kg1 Bf6 75. Qb7 Kg6 76. Qd5 Ne5 77. Qg8+ Bg7 78. Qe8+ Kh6 79. Qe7 Nd3 80. Kf1
Nf4 81. Qd6+ Bg6 82. Qe7 Nd5 83. Qe6 Nf6 84. Kg1 Be8 85. Qf5 Bd7 86. Qe5 Kg6 87.
Kf1 Bf8 88. Kg1 Ba3 89. Qc7 Bb4 90. Qe5 Bd2 91. Qd4 Bf4 92. Qb6 Be8 93. Kf1 Bf7
94. Kg1 Kf5 95. Qa7 Be6 96. Kf1 Kg6 97. Qb6 Bd7 98. Kg1 Ba4 99. Qe6 Bb5 100. Qb6
Bc4 101. Qd4 Be6 102. Kf1 Bf5 103. Kg1 g4 104. hxg4 Bxg4 105. Qc3 Bf5 106. Qb3
Bg5 107. Kf1 Kh6 108. Kg1 Kg6 109. Kf1 Bd7 110. Kg1 Be8 111. Qc3 Bf7 112. Qe5
Bd5 113. Qc3 Be6 114. Qe5 Bd7 115. Qc3 Bf5 116. Qb3 Nh5 117. Qg8+ Ng7 118. Qb3
Ne6 119. Kh2 Bf6 120. Kg1 Bg7 121. Kf1 Ng5 122. Qb6+ Bf6 123. Kg1 h3 124. gxh3
Bxh3 125. Qd6 Bf5 126. Kg2 Nf3 127. Qd5 Kg5 128. Qg8+ Bg6 129. Qd5+ Be5 130.
Qd8+ Kh5 131. Qd5 Bf5 132. Qf7+ Kg4 133. Qg8+ Ng5 134. Qc4 Bf4 135. Qg8 Be6 136.
Qg7 Bf7 137. Qd4 Kf5 138. Qc5+ Be5 139. Qf8 Kg6 140. Qc5 Bf6 141. Qd6 Bc4 142.
Qc6 Be6 143. Qd6 Bg4 144. Qd5 Bf3+ 145. Kf1 Nf7 146. Kg1 Ne5 147. Qg8+ Kf5 148.
Qc8+ Kg5 149. Qg8+ Ng6 150. Qd5+ Kh6 151. Qe6 Be5 152. Qf5 Bf4 153. Qf6 Bg5 154.
Qe6 Kg7 155. Qd7+ Ne7 156. Qe6 Bf6 157. Kf1 Kg6 158. Kg1 Nf5 159. Qg8+ Kh5 160.
Qf7+ Kg5 161. Qg8+ Kf4 162. Qb8+ Kg4 163. Qg8+ Bg5 164. Qc8 Bf6 165. Qg8+ Kf4
166. Qb8+ Be5 167. Qb4 Nd4 168. Qf8+ Kg5 169. Qg8+ Kh6 170. Qf8+ Bg7 171. Qd6+
Kh5 172. Qh2+ Kg5 173. Qg3+ Bg4 174. Qe3+ Kf5 1/2-1/2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
# TODO: Fix typing in this file.
# mypy: ignore-errors
import chess.svg
class WidgetError(Exception):
"""
raised when ipywidgets is not installed
"""
class NotJupyter(Exception):
"""
raised when InteractiveViewer is instantiated from a non jupyter shell
"""
try:
from ipywidgets import Button, GridBox, Layout, HTML, Output, HBox, Select
from IPython.display import display, clear_output
except ModuleNotFoundError:
raise WidgetError("You need to have ipywidgets installed and running from Jupyter")
class InteractiveViewer:
def __new__(cls, game):
jupyter = True
try:
if get_ipython().__class__.__name__ != "ZMQInteractiveShell":
jupyter = False
except NameError:
jupyter = False
if not jupyter:
raise NotJupyter("The interactive viewer only runs in Jupyter shell")
return object.__new__(cls)
def __init__(self, game):
self.game = game
self.__board = game.board()
self.__moves = list(game.mainline_moves())
self.__white_moves = [str(move) for (i, move) in enumerate(self.__moves) if i % 2 == 0]
self.__black_moves = [str(move) for (i, move) in enumerate(self.__moves) if i % 2 == 1]
self.__move_list_len = len(self.__white_moves)
self.__num_moves = len(self.__moves)
self.__next_move = 0 if self.__moves else None
self.__out = Output()
def __next_click(self, _):
move = self.__moves[self.__next_move]
self.__next_move += 1
self.__board.push(move)
self.show()
def __prev_click(self, _):
self.__board.pop()
self.__next_move -= 1
self.show()
def __reset_click(self, _):
self.__board.reset()
self.__next_move = 0
self.show()
def __white_select_change(self, change):
new = change["new"]
if (isinstance(new, dict)) and ("index" in new):
target = new["index"] * 2
self.__seek(target)
self.show()
def __black_select_change(self, change):
new = change["new"]
if (isinstance(new, dict)) and ("index" in new):
target = new["index"] * 2 + 1
self.__seek(target)
self.show()
def __seek(self, target):
while self.__next_move <= target:
move = self.__moves[self.__next_move]
self.__next_move += 1
self.__board.push(move)
while self.__next_move > target + 1:
self.__board.pop()
self.__next_move -= 1
def show(self):
display(self.__out)
next_move = Button(
icon="step-forward",
layout=Layout(width="60px", grid_area="right"),
disabled=self.__next_move >= self.__num_moves,
)
prev_move = Button(
icon="step-backward",
layout=Layout(width="60px", grid_area="left"),
disabled=self.__next_move == 0,
)
reset = Button(
icon="stop",
layout=Layout(width="60px", grid_area="middle"),
disabled=self.__next_move == 0,
)
if self.__next_move == 0:
white_move = None
black_move = None
else:
white_move = (
self.__white_moves[self.__next_move // 2]
if (self.__next_move % 2) == 1
else None
)
black_move = (
self.__black_moves[self.__next_move // 2 - 1]
if (self.__next_move % 2) == 0
else None
)
white_move_list = Select(
options=self.__white_moves,
value=white_move,
rows=max(self.__move_list_len, 24),
disabled=False,
layout=Layout(width="80px"),
)
black_move_list = Select(
options=self.__black_moves,
value=black_move,
rows=max(self.__move_list_len, 24),
disabled=False,
layout=Layout(width="80px"),
)
white_move_list.observe(self.__white_select_change)
black_move_list.observe(self.__black_select_change)
move_number_width = 3 + len(str(self.__move_list_len)) * 10
move_number = Select(
options=range(1, self.__move_list_len + 1),
value=None,
disabled=True,
rows=max(self.__move_list_len, 24),
layout=Layout(width=f"{move_number_width}px"),
)
move_list = HBox(
[move_number, white_move_list, black_move_list],
layout=Layout(height="407px", grid_area="moves"),
)
next_move.on_click(self.__next_click)
prev_move.on_click(self.__prev_click)
reset.on_click(self.__reset_click)
with self.__out:
grid_box = GridBox(
children=[next_move, prev_move, reset, self.svg, move_list],
layout=Layout(
width=f"{390+move_number_width+160}px",
grid_template_rows="90% 10%",
grid_template_areas="""
"top top top top top moves"
". left middle right . moves"
""",
),
)
clear_output(wait=True)
display(grid_box)
@property
def svg(self) -> HTML:
svg = chess.svg.board(
board=self.__board,
size=390,
lastmove=self.__board.peek() if self.__board.move_stack else None,
check=self.__board.king(self.__board.turn)
if self.__board.is_check()
else None,
)
svg_widget = HTML(value=svg, layout=Layout(grid_area="top"))
return svg_widget

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,542 @@
# This file is part of the python-chess library.
# Copyright (C) 2012-2021 Niklas Fiekas <niklas.fiekas@backscattering.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import chess
import struct
import os
import mmap
import random
import typing
from types import TracebackType
from typing import Callable, Container, Iterator, List, NamedTuple, Optional, Type, Union
PathLike = Union[str, bytes, os.PathLike]
ENTRY_STRUCT = struct.Struct(">QHHI")
POLYGLOT_RANDOM_ARRAY = [
0x9D39247E33776D41, 0x2AF7398005AAA5C7, 0x44DB015024623547, 0x9C15F73E62A76AE2,
0x75834465489C0C89, 0x3290AC3A203001BF, 0x0FBBAD1F61042279, 0xE83A908FF2FB60CA,
0x0D7E765D58755C10, 0x1A083822CEAFE02D, 0x9605D5F0E25EC3B0, 0xD021FF5CD13A2ED5,
0x40BDF15D4A672E32, 0x011355146FD56395, 0x5DB4832046F3D9E5, 0x239F8B2D7FF719CC,
0x05D1A1AE85B49AA1, 0x679F848F6E8FC971, 0x7449BBFF801FED0B, 0x7D11CDB1C3B7ADF0,
0x82C7709E781EB7CC, 0xF3218F1C9510786C, 0x331478F3AF51BBE6, 0x4BB38DE5E7219443,
0xAA649C6EBCFD50FC, 0x8DBD98A352AFD40B, 0x87D2074B81D79217, 0x19F3C751D3E92AE1,
0xB4AB30F062B19ABF, 0x7B0500AC42047AC4, 0xC9452CA81A09D85D, 0x24AA6C514DA27500,
0x4C9F34427501B447, 0x14A68FD73C910841, 0xA71B9B83461CBD93, 0x03488B95B0F1850F,
0x637B2B34FF93C040, 0x09D1BC9A3DD90A94, 0x3575668334A1DD3B, 0x735E2B97A4C45A23,
0x18727070F1BD400B, 0x1FCBACD259BF02E7, 0xD310A7C2CE9B6555, 0xBF983FE0FE5D8244,
0x9F74D14F7454A824, 0x51EBDC4AB9BA3035, 0x5C82C505DB9AB0FA, 0xFCF7FE8A3430B241,
0x3253A729B9BA3DDE, 0x8C74C368081B3075, 0xB9BC6C87167C33E7, 0x7EF48F2B83024E20,
0x11D505D4C351BD7F, 0x6568FCA92C76A243, 0x4DE0B0F40F32A7B8, 0x96D693460CC37E5D,
0x42E240CB63689F2F, 0x6D2BDCDAE2919661, 0x42880B0236E4D951, 0x5F0F4A5898171BB6,
0x39F890F579F92F88, 0x93C5B5F47356388B, 0x63DC359D8D231B78, 0xEC16CA8AEA98AD76,
0x5355F900C2A82DC7, 0x07FB9F855A997142, 0x5093417AA8A7ED5E, 0x7BCBC38DA25A7F3C,
0x19FC8A768CF4B6D4, 0x637A7780DECFC0D9, 0x8249A47AEE0E41F7, 0x79AD695501E7D1E8,
0x14ACBAF4777D5776, 0xF145B6BECCDEA195, 0xDABF2AC8201752FC, 0x24C3C94DF9C8D3F6,
0xBB6E2924F03912EA, 0x0CE26C0B95C980D9, 0xA49CD132BFBF7CC4, 0xE99D662AF4243939,
0x27E6AD7891165C3F, 0x8535F040B9744FF1, 0x54B3F4FA5F40D873, 0x72B12C32127FED2B,
0xEE954D3C7B411F47, 0x9A85AC909A24EAA1, 0x70AC4CD9F04F21F5, 0xF9B89D3E99A075C2,
0x87B3E2B2B5C907B1, 0xA366E5B8C54F48B8, 0xAE4A9346CC3F7CF2, 0x1920C04D47267BBD,
0x87BF02C6B49E2AE9, 0x092237AC237F3859, 0xFF07F64EF8ED14D0, 0x8DE8DCA9F03CC54E,
0x9C1633264DB49C89, 0xB3F22C3D0B0B38ED, 0x390E5FB44D01144B, 0x5BFEA5B4712768E9,
0x1E1032911FA78984, 0x9A74ACB964E78CB3, 0x4F80F7A035DAFB04, 0x6304D09A0B3738C4,
0x2171E64683023A08, 0x5B9B63EB9CEFF80C, 0x506AACF489889342, 0x1881AFC9A3A701D6,
0x6503080440750644, 0xDFD395339CDBF4A7, 0xEF927DBCF00C20F2, 0x7B32F7D1E03680EC,
0xB9FD7620E7316243, 0x05A7E8A57DB91B77, 0xB5889C6E15630A75, 0x4A750A09CE9573F7,
0xCF464CEC899A2F8A, 0xF538639CE705B824, 0x3C79A0FF5580EF7F, 0xEDE6C87F8477609D,
0x799E81F05BC93F31, 0x86536B8CF3428A8C, 0x97D7374C60087B73, 0xA246637CFF328532,
0x043FCAE60CC0EBA0, 0x920E449535DD359E, 0x70EB093B15B290CC, 0x73A1921916591CBD,
0x56436C9FE1A1AA8D, 0xEFAC4B70633B8F81, 0xBB215798D45DF7AF, 0x45F20042F24F1768,
0x930F80F4E8EB7462, 0xFF6712FFCFD75EA1, 0xAE623FD67468AA70, 0xDD2C5BC84BC8D8FC,
0x7EED120D54CF2DD9, 0x22FE545401165F1C, 0xC91800E98FB99929, 0x808BD68E6AC10365,
0xDEC468145B7605F6, 0x1BEDE3A3AEF53302, 0x43539603D6C55602, 0xAA969B5C691CCB7A,
0xA87832D392EFEE56, 0x65942C7B3C7E11AE, 0xDED2D633CAD004F6, 0x21F08570F420E565,
0xB415938D7DA94E3C, 0x91B859E59ECB6350, 0x10CFF333E0ED804A, 0x28AED140BE0BB7DD,
0xC5CC1D89724FA456, 0x5648F680F11A2741, 0x2D255069F0B7DAB3, 0x9BC5A38EF729ABD4,
0xEF2F054308F6A2BC, 0xAF2042F5CC5C2858, 0x480412BAB7F5BE2A, 0xAEF3AF4A563DFE43,
0x19AFE59AE451497F, 0x52593803DFF1E840, 0xF4F076E65F2CE6F0, 0x11379625747D5AF3,
0xBCE5D2248682C115, 0x9DA4243DE836994F, 0x066F70B33FE09017, 0x4DC4DE189B671A1C,
0x51039AB7712457C3, 0xC07A3F80C31FB4B4, 0xB46EE9C5E64A6E7C, 0xB3819A42ABE61C87,
0x21A007933A522A20, 0x2DF16F761598AA4F, 0x763C4A1371B368FD, 0xF793C46702E086A0,
0xD7288E012AEB8D31, 0xDE336A2A4BC1C44B, 0x0BF692B38D079F23, 0x2C604A7A177326B3,
0x4850E73E03EB6064, 0xCFC447F1E53C8E1B, 0xB05CA3F564268D99, 0x9AE182C8BC9474E8,
0xA4FC4BD4FC5558CA, 0xE755178D58FC4E76, 0x69B97DB1A4C03DFE, 0xF9B5B7C4ACC67C96,
0xFC6A82D64B8655FB, 0x9C684CB6C4D24417, 0x8EC97D2917456ED0, 0x6703DF9D2924E97E,
0xC547F57E42A7444E, 0x78E37644E7CAD29E, 0xFE9A44E9362F05FA, 0x08BD35CC38336615,
0x9315E5EB3A129ACE, 0x94061B871E04DF75, 0xDF1D9F9D784BA010, 0x3BBA57B68871B59D,
0xD2B7ADEEDED1F73F, 0xF7A255D83BC373F8, 0xD7F4F2448C0CEB81, 0xD95BE88CD210FFA7,
0x336F52F8FF4728E7, 0xA74049DAC312AC71, 0xA2F61BB6E437FDB5, 0x4F2A5CB07F6A35B3,
0x87D380BDA5BF7859, 0x16B9F7E06C453A21, 0x7BA2484C8A0FD54E, 0xF3A678CAD9A2E38C,
0x39B0BF7DDE437BA2, 0xFCAF55C1BF8A4424, 0x18FCF680573FA594, 0x4C0563B89F495AC3,
0x40E087931A00930D, 0x8CFFA9412EB642C1, 0x68CA39053261169F, 0x7A1EE967D27579E2,
0x9D1D60E5076F5B6F, 0x3810E399B6F65BA2, 0x32095B6D4AB5F9B1, 0x35CAB62109DD038A,
0xA90B24499FCFAFB1, 0x77A225A07CC2C6BD, 0x513E5E634C70E331, 0x4361C0CA3F692F12,
0xD941ACA44B20A45B, 0x528F7C8602C5807B, 0x52AB92BEB9613989, 0x9D1DFA2EFC557F73,
0x722FF175F572C348, 0x1D1260A51107FE97, 0x7A249A57EC0C9BA2, 0x04208FE9E8F7F2D6,
0x5A110C6058B920A0, 0x0CD9A497658A5698, 0x56FD23C8F9715A4C, 0x284C847B9D887AAE,
0x04FEABFBBDB619CB, 0x742E1E651C60BA83, 0x9A9632E65904AD3C, 0x881B82A13B51B9E2,
0x506E6744CD974924, 0xB0183DB56FFC6A79, 0x0ED9B915C66ED37E, 0x5E11E86D5873D484,
0xF678647E3519AC6E, 0x1B85D488D0F20CC5, 0xDAB9FE6525D89021, 0x0D151D86ADB73615,
0xA865A54EDCC0F019, 0x93C42566AEF98FFB, 0x99E7AFEABE000731, 0x48CBFF086DDF285A,
0x7F9B6AF1EBF78BAF, 0x58627E1A149BBA21, 0x2CD16E2ABD791E33, 0xD363EFF5F0977996,
0x0CE2A38C344A6EED, 0x1A804AADB9CFA741, 0x907F30421D78C5DE, 0x501F65EDB3034D07,
0x37624AE5A48FA6E9, 0x957BAF61700CFF4E, 0x3A6C27934E31188A, 0xD49503536ABCA345,
0x088E049589C432E0, 0xF943AEE7FEBF21B8, 0x6C3B8E3E336139D3, 0x364F6FFA464EE52E,
0xD60F6DCEDC314222, 0x56963B0DCA418FC0, 0x16F50EDF91E513AF, 0xEF1955914B609F93,
0x565601C0364E3228, 0xECB53939887E8175, 0xBAC7A9A18531294B, 0xB344C470397BBA52,
0x65D34954DAF3CEBD, 0xB4B81B3FA97511E2, 0xB422061193D6F6A7, 0x071582401C38434D,
0x7A13F18BBEDC4FF5, 0xBC4097B116C524D2, 0x59B97885E2F2EA28, 0x99170A5DC3115544,
0x6F423357E7C6A9F9, 0x325928EE6E6F8794, 0xD0E4366228B03343, 0x565C31F7DE89EA27,
0x30F5611484119414, 0xD873DB391292ED4F, 0x7BD94E1D8E17DEBC, 0xC7D9F16864A76E94,
0x947AE053EE56E63C, 0xC8C93882F9475F5F, 0x3A9BF55BA91F81CA, 0xD9A11FBB3D9808E4,
0x0FD22063EDC29FCA, 0xB3F256D8ACA0B0B9, 0xB03031A8B4516E84, 0x35DD37D5871448AF,
0xE9F6082B05542E4E, 0xEBFAFA33D7254B59, 0x9255ABB50D532280, 0xB9AB4CE57F2D34F3,
0x693501D628297551, 0xC62C58F97DD949BF, 0xCD454F8F19C5126A, 0xBBE83F4ECC2BDECB,
0xDC842B7E2819E230, 0xBA89142E007503B8, 0xA3BC941D0A5061CB, 0xE9F6760E32CD8021,
0x09C7E552BC76492F, 0x852F54934DA55CC9, 0x8107FCCF064FCF56, 0x098954D51FFF6580,
0x23B70EDB1955C4BF, 0xC330DE426430F69D, 0x4715ED43E8A45C0A, 0xA8D7E4DAB780A08D,
0x0572B974F03CE0BB, 0xB57D2E985E1419C7, 0xE8D9ECBE2CF3D73F, 0x2FE4B17170E59750,
0x11317BA87905E790, 0x7FBF21EC8A1F45EC, 0x1725CABFCB045B00, 0x964E915CD5E2B207,
0x3E2B8BCBF016D66D, 0xBE7444E39328A0AC, 0xF85B2B4FBCDE44B7, 0x49353FEA39BA63B1,
0x1DD01AAFCD53486A, 0x1FCA8A92FD719F85, 0xFC7C95D827357AFA, 0x18A6A990C8B35EBD,
0xCCCB7005C6B9C28D, 0x3BDBB92C43B17F26, 0xAA70B5B4F89695A2, 0xE94C39A54A98307F,
0xB7A0B174CFF6F36E, 0xD4DBA84729AF48AD, 0x2E18BC1AD9704A68, 0x2DE0966DAF2F8B1C,
0xB9C11D5B1E43A07E, 0x64972D68DEE33360, 0x94628D38D0C20584, 0xDBC0D2B6AB90A559,
0xD2733C4335C6A72F, 0x7E75D99D94A70F4D, 0x6CED1983376FA72B, 0x97FCAACBF030BC24,
0x7B77497B32503B12, 0x8547EDDFB81CCB94, 0x79999CDFF70902CB, 0xCFFE1939438E9B24,
0x829626E3892D95D7, 0x92FAE24291F2B3F1, 0x63E22C147B9C3403, 0xC678B6D860284A1C,
0x5873888850659AE7, 0x0981DCD296A8736D, 0x9F65789A6509A440, 0x9FF38FED72E9052F,
0xE479EE5B9930578C, 0xE7F28ECD2D49EECD, 0x56C074A581EA17FE, 0x5544F7D774B14AEF,
0x7B3F0195FC6F290F, 0x12153635B2C0CF57, 0x7F5126DBBA5E0CA7, 0x7A76956C3EAFB413,
0x3D5774A11D31AB39, 0x8A1B083821F40CB4, 0x7B4A38E32537DF62, 0x950113646D1D6E03,
0x4DA8979A0041E8A9, 0x3BC36E078F7515D7, 0x5D0A12F27AD310D1, 0x7F9D1A2E1EBE1327,
0xDA3A361B1C5157B1, 0xDCDD7D20903D0C25, 0x36833336D068F707, 0xCE68341F79893389,
0xAB9090168DD05F34, 0x43954B3252DC25E5, 0xB438C2B67F98E5E9, 0x10DCD78E3851A492,
0xDBC27AB5447822BF, 0x9B3CDB65F82CA382, 0xB67B7896167B4C84, 0xBFCED1B0048EAC50,
0xA9119B60369FFEBD, 0x1FFF7AC80904BF45, 0xAC12FB171817EEE7, 0xAF08DA9177DDA93D,
0x1B0CAB936E65C744, 0xB559EB1D04E5E932, 0xC37B45B3F8D6F2BA, 0xC3A9DC228CAAC9E9,
0xF3B8B6675A6507FF, 0x9FC477DE4ED681DA, 0x67378D8ECCEF96CB, 0x6DD856D94D259236,
0xA319CE15B0B4DB31, 0x073973751F12DD5E, 0x8A8E849EB32781A5, 0xE1925C71285279F5,
0x74C04BF1790C0EFE, 0x4DDA48153C94938A, 0x9D266D6A1CC0542C, 0x7440FB816508C4FE,
0x13328503DF48229F, 0xD6BF7BAEE43CAC40, 0x4838D65F6EF6748F, 0x1E152328F3318DEA,
0x8F8419A348F296BF, 0x72C8834A5957B511, 0xD7A023A73260B45C, 0x94EBC8ABCFB56DAE,
0x9FC10D0F989993E0, 0xDE68A2355B93CAE6, 0xA44CFE79AE538BBE, 0x9D1D84FCCE371425,
0x51D2B1AB2DDFB636, 0x2FD7E4B9E72CD38C, 0x65CA5B96B7552210, 0xDD69A0D8AB3B546D,
0x604D51B25FBF70E2, 0x73AA8A564FB7AC9E, 0x1A8C1E992B941148, 0xAAC40A2703D9BEA0,
0x764DBEAE7FA4F3A6, 0x1E99B96E70A9BE8B, 0x2C5E9DEB57EF4743, 0x3A938FEE32D29981,
0x26E6DB8FFDF5ADFE, 0x469356C504EC9F9D, 0xC8763C5B08D1908C, 0x3F6C6AF859D80055,
0x7F7CC39420A3A545, 0x9BFB227EBDF4C5CE, 0x89039D79D6FC5C5C, 0x8FE88B57305E2AB6,
0xA09E8C8C35AB96DE, 0xFA7E393983325753, 0xD6B6D0ECC617C699, 0xDFEA21EA9E7557E3,
0xB67C1FA481680AF8, 0xCA1E3785A9E724E5, 0x1CFC8BED0D681639, 0xD18D8549D140CAEA,
0x4ED0FE7E9DC91335, 0xE4DBF0634473F5D2, 0x1761F93A44D5AEFE, 0x53898E4C3910DA55,
0x734DE8181F6EC39A, 0x2680B122BAA28D97, 0x298AF231C85BAFAB, 0x7983EED3740847D5,
0x66C1A2A1A60CD889, 0x9E17E49642A3E4C1, 0xEDB454E7BADC0805, 0x50B704CAB602C329,
0x4CC317FB9CDDD023, 0x66B4835D9EAFEA22, 0x219B97E26FFC81BD, 0x261E4E4C0A333A9D,
0x1FE2CCA76517DB90, 0xD7504DFA8816EDBB, 0xB9571FA04DC089C8, 0x1DDC0325259B27DE,
0xCF3F4688801EB9AA, 0xF4F5D05C10CAB243, 0x38B6525C21A42B0E, 0x36F60E2BA4FA6800,
0xEB3593803173E0CE, 0x9C4CD6257C5A3603, 0xAF0C317D32ADAA8A, 0x258E5A80C7204C4B,
0x8B889D624D44885D, 0xF4D14597E660F855, 0xD4347F66EC8941C3, 0xE699ED85B0DFB40D,
0x2472F6207C2D0484, 0xC2A1E7B5B459AEB5, 0xAB4F6451CC1D45EC, 0x63767572AE3D6174,
0xA59E0BD101731A28, 0x116D0016CB948F09, 0x2CF9C8CA052F6E9F, 0x0B090A7560A968E3,
0xABEEDDB2DDE06FF1, 0x58EFC10B06A2068D, 0xC6E57A78FBD986E0, 0x2EAB8CA63CE802D7,
0x14A195640116F336, 0x7C0828DD624EC390, 0xD74BBE77E6116AC7, 0x804456AF10F5FB53,
0xEBE9EA2ADF4321C7, 0x03219A39EE587A30, 0x49787FEF17AF9924, 0xA1E9300CD8520548,
0x5B45E522E4B1B4EF, 0xB49C3B3995091A36, 0xD4490AD526F14431, 0x12A8F216AF9418C2,
0x001F837CC7350524, 0x1877B51E57A764D5, 0xA2853B80F17F58EE, 0x993E1DE72D36D310,
0xB3598080CE64A656, 0x252F59CF0D9F04BB, 0xD23C8E176D113600, 0x1BDA0492E7E4586E,
0x21E0BD5026C619BF, 0x3B097ADAF088F94E, 0x8D14DEDB30BE846E, 0xF95CFFA23AF5F6F4,
0x3871700761B3F743, 0xCA672B91E9E4FA16, 0x64C8E531BFF53B55, 0x241260ED4AD1E87D,
0x106C09B972D2E822, 0x7FBA195410E5CA30, 0x7884D9BC6CB569D8, 0x0647DFEDCD894A29,
0x63573FF03E224774, 0x4FC8E9560F91B123, 0x1DB956E450275779, 0xB8D91274B9E9D4FB,
0xA2EBEE47E2FBFCE1, 0xD9F1F30CCD97FB09, 0xEFED53D75FD64E6B, 0x2E6D02C36017F67F,
0xA9AA4D20DB084E9B, 0xB64BE8D8B25396C1, 0x70CB6AF7C2D5BCF0, 0x98F076A4F7A2322E,
0xBF84470805E69B5F, 0x94C3251F06F90CF3, 0x3E003E616A6591E9, 0xB925A6CD0421AFF3,
0x61BDD1307C66E300, 0xBF8D5108E27E0D48, 0x240AB57A8B888B20, 0xFC87614BAF287E07,
0xEF02CDD06FFDB432, 0xA1082C0466DF6C0A, 0x8215E577001332C8, 0xD39BB9C3A48DB6CF,
0x2738259634305C14, 0x61CF4F94C97DF93D, 0x1B6BACA2AE4E125B, 0x758F450C88572E0B,
0x959F587D507A8359, 0xB063E962E045F54D, 0x60E8ED72C0DFF5D1, 0x7B64978555326F9F,
0xFD080D236DA814BA, 0x8C90FD9B083F4558, 0x106F72FE81E2C590, 0x7976033A39F7D952,
0xA4EC0132764CA04B, 0x733EA705FAE4FA77, 0xB4D8F77BC3E56167, 0x9E21F4F903B33FD9,
0x9D765E419FB69F6D, 0xD30C088BA61EA5EF, 0x5D94337FBFAF7F5B, 0x1A4E4822EB4D7A59,
0x6FFE73E81B637FB3, 0xDDF957BC36D8B9CA, 0x64D0E29EEA8838B3, 0x08DD9BDFD96B9F63,
0x087E79E5A57D1D13, 0xE328E230E3E2B3FB, 0x1C2559E30F0946BE, 0x720BF5F26F4D2EAA,
0xB0774D261CC609DB, 0x443F64EC5A371195, 0x4112CF68649A260E, 0xD813F2FAB7F5C5CA,
0x660D3257380841EE, 0x59AC2C7873F910A3, 0xE846963877671A17, 0x93B633ABFA3469F8,
0xC0C0F5A60EF4CDCF, 0xCAF21ECD4377B28C, 0x57277707199B8175, 0x506C11B9D90E8B1D,
0xD83CC2687A19255F, 0x4A29C6465A314CD1, 0xED2DF21216235097, 0xB5635C95FF7296E2,
0x22AF003AB672E811, 0x52E762596BF68235, 0x9AEBA33AC6ECC6B0, 0x944F6DE09134DFB6,
0x6C47BEC883A7DE39, 0x6AD047C430A12104, 0xA5B1CFDBA0AB4067, 0x7C45D833AFF07862,
0x5092EF950A16DA0B, 0x9338E69C052B8E7B, 0x455A4B4CFE30E3F5, 0x6B02E63195AD0CF8,
0x6B17B224BAD6BF27, 0xD1E0CCD25BB9C169, 0xDE0C89A556B9AE70, 0x50065E535A213CF6,
0x9C1169FA2777B874, 0x78EDEFD694AF1EED, 0x6DC93D9526A50E68, 0xEE97F453F06791ED,
0x32AB0EDB696703D3, 0x3A6853C7E70757A7, 0x31865CED6120F37D, 0x67FEF95D92607890,
0x1F2B1D1F15F6DC9C, 0xB69E38A8965C6B65, 0xAA9119FF184CCCF4, 0xF43C732873F24C13,
0xFB4A3D794A9A80D2, 0x3550C2321FD6109C, 0x371F77E76BB8417E, 0x6BFA9AAE5EC05779,
0xCD04F3FF001A4778, 0xE3273522064480CA, 0x9F91508BFFCFC14A, 0x049A7F41061A9E60,
0xFCB6BE43A9F2FE9B, 0x08DE8A1C7797DA9B, 0x8F9887E6078735A1, 0xB5B4071DBFC73A66,
0x230E343DFBA08D33, 0x43ED7F5A0FAE657D, 0x3A88A0FBBCB05C63, 0x21874B8B4D2DBC4F,
0x1BDEA12E35F6A8C9, 0x53C065C6C8E63528, 0xE34A1D250E7A8D6B, 0xD6B04D3B7651DD7E,
0x5E90277E7CB39E2D, 0x2C046F22062DC67D, 0xB10BB459132D0A26, 0x3FA9DDFB67E2F199,
0x0E09B88E1914F7AF, 0x10E8B35AF3EEAB37, 0x9EEDECA8E272B933, 0xD4C718BC4AE8AE5F,
0x81536D601170FC20, 0x91B534F885818A06, 0xEC8177F83F900978, 0x190E714FADA5156E,
0xB592BF39B0364963, 0x89C350C893AE7DC1, 0xAC042E70F8B383F2, 0xB49B52E587A1EE60,
0xFB152FE3FF26DA89, 0x3E666E6F69AE2C15, 0x3B544EBE544C19F9, 0xE805A1E290CF2456,
0x24B33C9D7ED25117, 0xE74733427B72F0C1, 0x0A804D18B7097475, 0x57E3306D881EDB4F,
0x4AE7D6A36EB5DBCB, 0x2D8D5432157064C8, 0xD1E649DE1E7F268B, 0x8A328A1CEDFE552C,
0x07A3AEC79624C7DA, 0x84547DDC3E203C94, 0x990A98FD5071D263, 0x1A4FF12616EEFC89,
0xF6F7FD1431714200, 0x30C05B1BA332F41C, 0x8D2636B81555A786, 0x46C9FEB55D120902,
0xCCEC0A73B49C9921, 0x4E9D2827355FC492, 0x19EBB029435DCB0F, 0x4659D2B743848A2C,
0x963EF2C96B33BE31, 0x74F85198B05A2E7D, 0x5A0F544DD2B1FB18, 0x03727073C2E134B1,
0xC7F6AA2DE59AEA61, 0x352787BAA0D7C22F, 0x9853EAB63B5E0B35, 0xABBDCDD7ED5C0860,
0xCF05DAF5AC8D77B0, 0x49CAD48CEBF4A71E, 0x7A4C10EC2158C4A6, 0xD9E92AA246BF719E,
0x13AE978D09FE5557, 0x730499AF921549FF, 0x4E4B705B92903BA4, 0xFF577222C14F0A3A,
0x55B6344CF97AAFAE, 0xB862225B055B6960, 0xCAC09AFBDDD2CDB4, 0xDAF8E9829FE96B5F,
0xB5FDFC5D3132C498, 0x310CB380DB6F7503, 0xE87FBB46217A360E, 0x2102AE466EBB1148,
0xF8549E1A3AA5E00D, 0x07A69AFDCC42261A, 0xC4C118BFE78FEAAE, 0xF9F4892ED96BD438,
0x1AF3DBE25D8F45DA, 0xF5B4B0B0D2DEEEB4, 0x962ACEEFA82E1C84, 0x046E3ECAAF453CE9,
0xF05D129681949A4C, 0x964781CE734B3C84, 0x9C2ED44081CE5FBD, 0x522E23F3925E319E,
0x177E00F9FC32F791, 0x2BC60A63A6F3B3F2, 0x222BBFAE61725606, 0x486289DDCC3D6780,
0x7DC7785B8EFDFC80, 0x8AF38731C02BA980, 0x1FAB64EA29A2DDF7, 0xE4D9429322CD065A,
0x9DA058C67844F20C, 0x24C0E332B70019B0, 0x233003B5A6CFE6AD, 0xD586BD01C5C217F6,
0x5E5637885F29BC2B, 0x7EBA726D8C94094B, 0x0A56A5F0BFE39272, 0xD79476A84EE20D06,
0x9E4C1269BAA4BF37, 0x17EFEE45B0DEE640, 0x1D95B0A5FCF90BC6, 0x93CBE0B699C2585D,
0x65FA4F227A2B6D79, 0xD5F9E858292504D5, 0xC2B5A03F71471A6F, 0x59300222B4561E00,
0xCE2F8642CA0712DC, 0x7CA9723FBB2E8988, 0x2785338347F2BA08, 0xC61BB3A141E50E8C,
0x150F361DAB9DEC26, 0x9F6A419D382595F4, 0x64A53DC924FE7AC9, 0x142DE49FFF7A7C3D,
0x0C335248857FA9E7, 0x0A9C32D5EAE45305, 0xE6C42178C4BBB92E, 0x71F1CE2490D20B07,
0xF1BCC3D275AFE51A, 0xE728E8C83C334074, 0x96FBF83A12884624, 0x81A1549FD6573DA5,
0x5FA7867CAF35E149, 0x56986E2EF3ED091B, 0x917F1DD5F8886C61, 0xD20D8C88C8FFE65F,
0x31D71DCE64B2C310, 0xF165B587DF898190, 0xA57E6339DD2CF3A0, 0x1EF6E6DBB1961EC9,
0x70CC73D90BC26E24, 0xE21A6B35DF0C3AD7, 0x003A93D8B2806962, 0x1C99DED33CB890A1,
0xCF3145DE0ADD4289, 0xD0E4427A5514FB72, 0x77C621CC9FB3A483, 0x67A34DAC4356550B,
0xF8D626AAAF278509
]
class ZobristHasher:
def __init__(self, array: List[int]) -> None:
assert len(array) >= 781
self.array = array
def hash_board(self, board: chess.BaseBoard) -> int:
zobrist_hash = 0
for pivot, squares in enumerate(board.occupied_co):
for square in chess.scan_reversed(squares):
piece_index = (typing.cast(chess.PieceType, board.piece_type_at(square)) - 1) * 2 + pivot
zobrist_hash ^= self.array[64 * piece_index + square]
return zobrist_hash
def hash_castling(self, board: chess.Board) -> int:
zobrist_hash = 0
# Hash in the castling flags.
if board.has_kingside_castling_rights(chess.WHITE):
zobrist_hash ^= self.array[768]
if board.has_queenside_castling_rights(chess.WHITE):
zobrist_hash ^= self.array[768 + 1]
if board.has_kingside_castling_rights(chess.BLACK):
zobrist_hash ^= self.array[768 + 2]
if board.has_queenside_castling_rights(chess.BLACK):
zobrist_hash ^= self.array[768 + 3]
return zobrist_hash
def hash_ep_square(self, board: chess.Board) -> int:
# Hash in the en passant file.
if board.ep_square:
# But only if there's actually a pawn ready to capture it. Legality
# of the potential capture is irrelevant.
if board.turn == chess.WHITE:
ep_mask = chess.shift_down(chess.BB_SQUARES[board.ep_square])
else:
ep_mask = chess.shift_up(chess.BB_SQUARES[board.ep_square])
ep_mask = chess.shift_left(ep_mask) | chess.shift_right(ep_mask)
if ep_mask & board.pawns & board.occupied_co[board.turn]:
return self.array[772 + chess.square_file(board.ep_square)]
return 0
def hash_turn(self, board: chess.Board) -> int:
# Hash in the turn.
return self.array[780] if board.turn == chess.WHITE else 0
def __call__(self, board: chess.Board) -> int:
return (self.hash_board(board) ^ self.hash_castling(board) ^
self.hash_ep_square(board) ^ self.hash_turn(board))
def zobrist_hash(board: chess.Board, *, _hasher: Callable[[chess.Board], int] = ZobristHasher(POLYGLOT_RANDOM_ARRAY)) -> int:
"""
Calculates the Polyglot Zobrist hash of the position.
A Zobrist hash is an XOR of pseudo-random values picked from
an array. Which values are picked is decided by features of the
position, such as piece positions, castling rights and en passant
squares.
"""
return _hasher(board)
class Entry(NamedTuple):
"""An entry from a Polyglot opening book."""
key: int
"""The Zobrist hash of the position."""
raw_move: int
"""
The raw binary representation of the move. Use
:data:`~chess.polyglot.Entry.move` instead.
"""
weight: int
"""An integer value that can be used as the weight for this entry."""
learn: int
"""Another integer value that can be used for extra information."""
move: chess.Move
"""The :class:`~chess.Move`."""
class _EmptyMmap(bytearray):
def size(self) -> int:
return 0
def close(self) -> None:
pass
def _randint(rng: Optional[random.Random], a: int, b: int) -> int:
return random.randint(a, b) if rng is None else rng.randint(a, b)
class MemoryMappedReader:
"""Maps a Polyglot opening book to memory."""
def __init__(self, filename: PathLike) -> None:
self.fd = os.open(filename, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY)
try:
self.mmap: Union[mmap.mmap, _EmptyMmap] = mmap.mmap(self.fd, 0, access=mmap.ACCESS_READ)
except (ValueError, OSError):
self.mmap = _EmptyMmap() # Workaround for empty opening books.
if self.mmap.size() % ENTRY_STRUCT.size != 0:
raise IOError(f"invalid file size: ensure {filename!r} is a valid polyglot opening book")
try:
# Python 3.8
self.mmap.madvise(mmap.MADV_RANDOM) # type: ignore
except AttributeError:
pass
def __enter__(self) -> MemoryMappedReader:
return self
def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[TracebackType]) -> None:
return self.close()
def __len__(self) -> int:
return self.mmap.size() // ENTRY_STRUCT.size
def __getitem__(self, index: int) -> Entry:
if index < 0:
index = len(self) + index
try:
key, raw_move, weight, learn = ENTRY_STRUCT.unpack_from(self.mmap, index * ENTRY_STRUCT.size)
except struct.error:
raise IndexError()
# Extract source and target square.
to_square = raw_move & 0x3f
from_square = (raw_move >> 6) & 0x3f
# Extract the promotion type.
promotion_part = (raw_move >> 12) & 0x7
promotion = promotion_part + 1 if promotion_part else None
# Piece drop.
if from_square == to_square:
promotion, drop = None, promotion
else:
drop = None
# Entry with move (not normalized).
move = chess.Move(from_square, to_square, promotion, drop)
return Entry(key, raw_move, weight, learn, move)
def __iter__(self) -> Iterator[Entry]:
i = 0
size = len(self)
while i < size:
yield self[i]
i += 1
def bisect_key_left(self, key: int) -> int:
lo = 0
hi = len(self)
while lo < hi:
mid = (lo + hi) // 2
mid_key, _, _, _ = ENTRY_STRUCT.unpack_from(self.mmap, mid * ENTRY_STRUCT.size)
if mid_key < key:
lo = mid + 1
else:
hi = mid
return lo
def __contains__(self, entry: Entry) -> bool:
return any(current == entry for current in self.find_all(entry.key, minimum_weight=entry.weight))
def find_all(self, board: Union[chess.Board, int], *, minimum_weight: int = 1, exclude_moves: Container[chess.Move] = []) -> Iterator[Entry]:
"""Seeks a specific position and yields corresponding entries."""
try:
key = int(board) # type: ignore
context: Optional[chess.Board] = None
except (TypeError, ValueError):
context = typing.cast(chess.Board, board)
key = zobrist_hash(context)
i = self.bisect_key_left(key)
size = len(self)
while i < size:
entry = self[i]
i += 1
if entry.key != key:
break
if entry.weight < minimum_weight:
continue
if context:
move = context._from_chess960(context.chess960, entry.move.from_square, entry.move.to_square, entry.move.promotion, entry.move.drop)
entry = Entry(entry.key, entry.raw_move, entry.weight, entry.learn, move)
if exclude_moves and entry.move in exclude_moves:
continue
if context and not context.is_legal(entry.move):
continue
yield entry
def find(self, board: Union[chess.Board, int], *, minimum_weight: int = 1, exclude_moves: Container[chess.Move] = []) -> Entry:
"""
Finds the main entry for the given position or Zobrist hash.
The main entry is the (first) entry with the highest weight.
By default, entries with weight ``0`` are excluded. This is a common
way to delete entries from an opening book without compacting it. Pass
*minimum_weight* ``0`` to select all entries.
:raises: :exc:`IndexError` if no entries are found. Use
:func:`~chess.polyglot.MemoryMappedReader.get()` if you prefer to
get ``None`` instead of an exception.
"""
try:
return max(self.find_all(board, minimum_weight=minimum_weight, exclude_moves=exclude_moves), key=lambda entry: entry.weight)
except ValueError:
raise IndexError()
def get(self, board: Union[chess.Board, int], default: Optional[Entry] = None, *, minimum_weight: int = 1, exclude_moves: Container[chess.Move] = []) -> Optional[Entry]:
try:
return self.find(board, minimum_weight=minimum_weight, exclude_moves=exclude_moves)
except IndexError:
return default
def choice(self, board: Union[chess.Board, int], *, minimum_weight: int = 1, exclude_moves: Container[chess.Move] = [], random: Optional[random.Random] = None) -> Entry:
"""
Uniformly selects a random entry for the given position.
:raises: :exc:`IndexError` if no entries are found.
"""
chosen_entry = None
for i, entry in enumerate(self.find_all(board, minimum_weight=minimum_weight, exclude_moves=exclude_moves)):
if chosen_entry is None or _randint(random, 0, i) == i:
chosen_entry = entry
if chosen_entry is None:
raise IndexError()
return chosen_entry
def weighted_choice(self, board: Union[chess.Board, int], *, exclude_moves: Container[chess.Move] = [], random: Optional[random.Random] = None) -> Entry:
"""
Selects a random entry for the given position, distributed by the
weights of the entries.
:raises: :exc:`IndexError` if no entries are found.
"""
total_weights = sum(entry.weight for entry in self.find_all(board, exclude_moves=exclude_moves))
if not total_weights:
raise IndexError()
choice = _randint(random, 0, total_weights - 1)
current_sum = 0
for entry in self.find_all(board, exclude_moves=exclude_moves):
current_sum += entry.weight
if current_sum > choice:
return entry
assert False
def close(self) -> None:
"""Closes the reader."""
self.mmap.close()
try:
os.close(self.fd)
except OSError:
pass
def open_reader(path: PathLike) -> MemoryMappedReader:
"""
Creates a reader for the file at the given path.
The following example opens a book to find all entries for the start
position:
>>> import chess
>>> import chess.polyglot
>>>
>>> board = chess.Board()
>>>
>>> with chess.polyglot.open_reader("data/polyglot/performance.bin") as reader:
... for entry in reader.find_all(board):
... print(entry.move, entry.weight, entry.learn)
e2e4 1 0
d2d4 1 0
c2c4 1 0
"""
return MemoryMappedReader(path)

View File

@ -0,0 +1,466 @@
# This file is part of the python-chess library.
# Copyright (C) 2016-2021 Niklas Fiekas <niklas.fiekas@backscattering.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Piece vector graphics are copyright (C) Colin M.L. Burnett
# <https://en.wikipedia.org/wiki/User:Cburnett> and also licensed under the
# GNU General Public License.
from __future__ import annotations
import math
import xml.etree.ElementTree as ET
import chess
from typing import Dict, Iterable, Optional, Tuple, Union
from chess import Color, IntoSquareSet, Square
SQUARE_SIZE = 45
MARGIN = 20
PIECES = {
"b": """<g id="black-bishop" class="black bishop" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2zm6-4c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2zM25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z" fill="#000" stroke-linecap="butt"/><path d="M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5" stroke="#fff" stroke-linejoin="miter"/></g>""", # noqa: E501
"k": """<g id="black-king" class="black king" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22.5 11.63V6" stroke-linejoin="miter"/><path d="M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5" fill="#000" stroke-linecap="butt" stroke-linejoin="miter"/><path d="M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z" fill="#000"/><path d="M20 8h5" stroke-linejoin="miter"/><path d="M32 29.5s8.5-4 6.03-9.65C34.15 14 25 18 22.5 24.5l.01 2.1-.01-2.1C20 18 9.906 14 6.997 19.85c-2.497 5.65 4.853 9 4.853 9M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0" stroke="#fff"/></g>""", # noqa: E501
"n": """<g id="black-knight" class="black knight" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18" style="fill:#000000; stroke:#000000;"/><path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10" style="fill:#000000; stroke:#000000;"/><path d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z" style="fill:#ececec; stroke:#ececec;"/><path d="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z" transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)" style="fill:#ececec; stroke:#ececec;"/><path d="M 24.55,10.4 L 24.1,11.85 L 24.6,12 C 27.75,13 30.25,14.49 32.5,18.75 C 34.75,23.01 35.75,29.06 35.25,39 L 35.2,39.5 L 37.45,39.5 L 37.5,39 C 38,28.94 36.62,22.15 34.25,17.66 C 31.88,13.17 28.46,11.02 25.06,10.5 L 24.55,10.4 z " style="fill:#ececec; stroke:none;"/></g>""", # noqa: E501
"p": """<g id="black-pawn" class="black pawn"><path d="M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z" stroke="#000" stroke-width="1.5" stroke-linecap="round"/></g>""", # noqa: E501
"q": """<g id="black-queen" class="black queen" fill="#000" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><g fill="#000" stroke="none"><circle cx="6" cy="12" r="2.75"/><circle cx="14" cy="9" r="2.75"/><circle cx="22.5" cy="8" r="2.75"/><circle cx="31" cy="9" r="2.75"/><circle cx="39" cy="12" r="2.75"/></g><path d="M9 26c8.5-1.5 21-1.5 27 0l2.5-12.5L31 25l-.3-14.1-5.2 13.6-3-14.5-3 14.5-5.2-13.6L14 25 6.5 13.5 9 26zM9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z" stroke-linecap="butt"/><path d="M11 38.5a35 35 1 0 0 23 0" fill="none" stroke-linecap="butt"/><path d="M11 29a35 35 1 0 1 23 0M12.5 31.5h20M11.5 34.5a35 35 1 0 0 22 0M10.5 37.5a35 35 1 0 0 24 0" fill="none" stroke="#fff"/></g>""", # noqa: E501
"r": """<g id="black-rook" class="black rook" fill="#000" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 39h27v-3H9v3zM12.5 32l1.5-2.5h17l1.5 2.5h-20zM12 36v-4h21v4H12z" stroke-linecap="butt"/><path d="M14 29.5v-13h17v13H14z" stroke-linecap="butt" stroke-linejoin="miter"/><path d="M14 16.5L11 14h23l-3 2.5H14zM11 14V9h4v2h5V9h5v2h5V9h4v5H11z" stroke-linecap="butt"/><path d="M12 35.5h21M13 31.5h19M14 29.5h17M14 16.5h17M11 14h23" fill="none" stroke="#fff" stroke-width="1" stroke-linejoin="miter"/></g>""", # noqa: E501
"B": """<g id="white-bishop" class="white bishop" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><g fill="#fff" stroke-linecap="butt"><path d="M9 36c3.39-.97 10.11.43 13.5-2 3.39 2.43 10.11 1.03 13.5 2 0 0 1.65.54 3 2-.68.97-1.65.99-3 .5-3.39-.97-10.11.46-13.5-1-3.39 1.46-10.11.03-13.5 1-1.354.49-2.323.47-3-.5 1.354-1.94 3-2 3-2zM15 32c2.5 2.5 12.5 2.5 15 0 .5-1.5 0-2 0-2 0-2.5-2.5-4-2.5-4 5.5-1.5 6-11.5-5-15.5-11 4-10.5 14-5 15.5 0 0-2.5 1.5-2.5 4 0 0-.5.5 0 2zM25 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 1 1 5 0z"/></g><path d="M17.5 26h10M15 30h15m-7.5-14.5v5M20 18h5" stroke-linejoin="miter"/></g>""", # noqa: E501
"K": """<g id="white-king" class="white king" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22.5 11.63V6M20 8h5" stroke-linejoin="miter"/><path d="M22.5 25s4.5-7.5 3-10.5c0 0-1-2.5-3-2.5s-3 2.5-3 2.5c-1.5 3 3 10.5 3 10.5" fill="#fff" stroke-linecap="butt" stroke-linejoin="miter"/><path d="M11.5 37c5.5 3.5 15.5 3.5 21 0v-7s9-4.5 6-10.5c-4-6.5-13.5-3.5-16 4V27v-3.5c-3.5-7.5-13-10.5-16-4-3 6 5 10 5 10V37z" fill="#fff"/><path d="M11.5 30c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0m-21 3.5c5.5-3 15.5-3 21 0"/></g>""", # noqa: E501
"N": """<g id="white-knight" class="white knight" fill="none" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18" style="fill:#ffffff; stroke:#000000;"/><path d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10" style="fill:#ffffff; stroke:#000000;"/><path d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z" style="fill:#000000; stroke:#000000;"/><path d="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z" transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)" style="fill:#000000; stroke:#000000;"/></g>""", # noqa: E501
"P": """<g id="white-pawn" class="white pawn"><path d="M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2.38C17.33 16.5 16 18.59 16 21c0 2.03.94 3.84 2.41 5.03-3 1.06-7.41 5.55-7.41 13.47h23c0-7.92-4.41-12.41-7.41-13.47 1.47-1.19 2.41-3 2.41-5.03 0-2.41-1.33-4.5-3.28-5.62.49-.67.78-1.49.78-2.38 0-2.21-1.79-4-4-4z" fill="#fff" stroke="#000" stroke-width="1.5" stroke-linecap="round"/></g>""", # noqa: E501
"Q": """<g id="white-queen" class="white queen" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM24.5 7.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM41 12a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM16 8.5a2 2 0 1 1-4 0 2 2 0 1 1 4 0zM33 9a2 2 0 1 1-4 0 2 2 0 1 1 4 0z"/><path d="M9 26c8.5-1.5 21-1.5 27 0l2-12-7 11V11l-5.5 13.5-3-15-3 15-5.5-14V25L7 14l2 12zM9 26c0 2 1.5 2 2.5 4 1 1.5 1 1 .5 3.5-1.5 1-1.5 2.5-1.5 2.5-1.5 1.5.5 2.5.5 2.5 6.5 1 16.5 1 23 0 0 0 1.5-1 0-2.5 0 0 .5-1.5-1-2.5-.5-2.5-.5-2 .5-3.5 1-2 2.5-2 2.5-4-8.5-1.5-18.5-1.5-27 0z" stroke-linecap="butt"/><path d="M11.5 30c3.5-1 18.5-1 22 0M12 33.5c6-1 15-1 21 0" fill="none"/></g>""", # noqa: E501
"R": """<g id="white-rook" class="white rook" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 39h27v-3H9v3zM12 36v-4h21v4H12zM11 14V9h4v2h5V9h5v2h5V9h4v5" stroke-linecap="butt"/><path d="M34 14l-3 3H14l-3-3"/><path d="M31 17v12.5H14V17" stroke-linecap="butt" stroke-linejoin="miter"/><path d="M31 29.5l1.5 2.5h-20l1.5-2.5"/><path d="M11 14h23" fill="none" stroke-linejoin="miter"/></g>""", # noqa: E501
}
COORDS = {
"1": """<path d="M6.754 26.996h2.578v-8.898l-2.805.562v-1.437l2.79-.563h1.578v10.336h2.578v1.328h-6.72z"/>""", # noqa: E501
"2": """<path d="M8.195 26.996h5.508v1.328H6.297v-1.328q.898-.93 2.445-2.492 1.555-1.57 1.953-2.024.758-.851 1.055-1.437.305-.594.305-1.164 0-.93-.657-1.516-.648-.586-1.695-.586-.742 0-1.57.258-.82.258-1.758.781v-1.593q.953-.383 1.781-.578.828-.196 1.516-.196 1.812 0 2.89.906 1.079.907 1.079 2.422 0 .72-.274 1.368-.265.64-.976 1.515-.196.227-1.243 1.313-1.046 1.078-2.953 3.023z"/>""", # noqa: E501
"3": """<path d="M11.434 22.035q1.132.242 1.765 1.008.64.766.64 1.89 0 1.727-1.187 2.672-1.187.946-3.375.946-.734 0-1.515-.149-.774-.14-1.602-.43V26.45q.656.383 1.438.578.78.196 1.632.196 1.485 0 2.258-.586.782-.586.782-1.703 0-1.032-.727-1.61-.719-.586-2.008-.586h-1.36v-1.297h1.423q1.164 0 1.78-.46.618-.47.618-1.344 0-.899-.64-1.375-.633-.485-1.82-.485-.65 0-1.391.141-.743.14-1.633.437V16.95q.898-.25 1.68-.375.788-.125 1.484-.125 1.797 0 2.844.82 1.046.813 1.046 2.204 0 .968-.554 1.64-.555.664-1.578.922z"/>""", # noqa: E501
"4": """<path d="M11.016 18.035L7.03 24.262h3.985zm-.414-1.375h1.984v7.602h1.664v1.312h-1.664v2.75h-1.57v-2.75H5.75v-1.523z"/>""", # noqa: E501
"5": """<path d="M6.719 16.66h6.195v1.328h-4.75v2.86q.344-.118.688-.172.343-.063.687-.063 1.953 0 3.094 1.07 1.14 1.07 1.14 2.899 0 1.883-1.171 2.93-1.172 1.039-3.305 1.039-.735 0-1.5-.125-.758-.125-1.57-.375v-1.586q.703.383 1.453.57.75.188 1.586.188 1.351 0 2.14-.711.79-.711.79-1.93 0-1.219-.79-1.93-.789-.71-2.14-.71-.633 0-1.266.14-.625.14-1.281.438z"/>""", # noqa: E501
"6": """<path d="M10.137 21.863q-1.063 0-1.688.727-.617.726-.617 1.992 0 1.258.617 1.992.625.727 1.688.727 1.062 0 1.68-.727.624-.734.624-1.992 0-1.266-.625-1.992-.617-.727-1.68-.727zm3.133-4.945v1.437q-.594-.28-1.204-.43-.601-.148-1.195-.148-1.562 0-2.39 1.055-.82 1.055-.938 3.188.46-.68 1.156-1.04.696-.367 1.531-.367 1.758 0 2.774 1.07 1.023 1.063 1.023 2.899 0 1.797-1.062 2.883-1.063 1.086-2.828 1.086-2.024 0-3.094-1.547-1.07-1.555-1.07-4.5 0-2.766 1.312-4.406 1.313-1.649 3.524-1.649.593 0 1.195.117.61.118 1.266.352z"/>""", # noqa: E501
"7": """<path d="M6.25 16.66h7.5v.672L9.516 28.324H7.867l3.985-10.336H6.25z"/>""", # noqa: E501
"8": """<path d="M10 22.785q-1.125 0-1.773.602-.641.601-.641 1.656t.64 1.656q.649.602 1.774.602t1.773-.602q.649-.61.649-1.656 0-1.055-.649-1.656-.64-.602-1.773-.602zm-1.578-.672q-1.016-.25-1.586-.945-.563-.695-.563-1.695 0-1.399.993-2.211 1-.813 2.734-.813 1.742 0 2.734.813.993.812.993 2.21 0 1-.57 1.696-.563.695-1.571.945 1.14.266 1.773 1.04.641.773.641 1.89 0 1.695-1.04 2.602-1.03.906-2.96.906t-2.969-.906Q6 26.738 6 25.043q0-1.117.64-1.89.641-.774 1.782-1.04zm-.578-2.492q0 .906.562 1.414.57.508 1.594.508 1.016 0 1.586-.508.578-.508.578-1.414 0-.906-.578-1.414-.57-.508-1.586-.508-1.023 0-1.594.508-.562.508-.562 1.414z"/>""", # noqa: E501
"a": """<path d="M23.328 10.016q-1.742 0-2.414.398-.672.398-.672 1.36 0 .765.5 1.218.508.445 1.375.445 1.196 0 1.914-.843.727-.852.727-2.258v-.32zm2.867-.594v4.992h-1.437v-1.328q-.492.797-1.227 1.18-.734.375-1.797.375-1.343 0-2.14-.75-.79-.758-.79-2.024 0-1.476.985-2.226.992-.75 2.953-.75h2.016V8.75q0-.992-.656-1.531-.649-.547-1.829-.547-.75 0-1.46.18-.711.18-1.368.539V6.062q.79-.304 1.532-.453.742-.156 1.445-.156 1.898 0 2.836.984.937.985.937 2.985z"/>""", # noqa: E501
"b": """<path d="M24.922 10.047q0-1.586-.656-2.485-.649-.906-1.79-.906-1.14 0-1.796.906-.649.899-.649 2.485 0 1.586.649 2.492.656.898 1.797.898 1.14 0 1.789-.898.656-.906.656-2.492zm-4.89-3.055q.452-.781 1.14-1.156.695-.383 1.656-.383 1.594 0 2.586 1.266 1 1.265 1 3.328 0 2.062-1 3.328-.992 1.266-2.586 1.266-.96 0-1.656-.375-.688-.383-1.14-1.164v1.312h-1.446V2.258h1.445z"/>""", # noqa: E501
"c": """<path d="M25.96 6v1.344q-.608-.336-1.226-.5-.609-.172-1.234-.172-1.398 0-2.172.89-.773.883-.773 2.485 0 1.601.773 2.492.774.883 2.172.883.625 0 1.234-.164.618-.172 1.227-.508v1.328q-.602.281-1.25.422-.64.14-1.367.14-1.977 0-3.14-1.242-1.165-1.242-1.165-3.351 0-2.14 1.172-3.367 1.18-1.227 3.227-1.227.664 0 1.296.14.633.134 1.227.407z"/>""", # noqa: E501
"d": """<path d="M24.973 6.992V2.258h1.437v12.156h-1.437v-1.312q-.453.78-1.149 1.164-.687.375-1.656.375-1.586 0-2.586-1.266-.992-1.266-.992-3.328 0-2.063.992-3.328 1-1.266 2.586-1.266.969 0 1.656.383.696.375 1.149 1.156zm-4.899 3.055q0 1.586.649 2.492.656.898 1.797.898 1.14 0 1.796-.898.657-.906.657-2.492 0-1.586-.657-2.485-.656-.906-1.796-.906-1.141 0-1.797.906-.649.899-.649 2.485z"/>""", # noqa: E501
"e": """<path d="M26.555 9.68v.703h-6.61q.094 1.484.89 2.265.806.774 2.235.774.828 0 1.602-.203.781-.203 1.547-.61v1.36q-.774.328-1.586.5-.813.172-1.649.172-2.093 0-3.32-1.22-1.219-1.218-1.219-3.296 0-2.148 1.157-3.406 1.164-1.266 3.132-1.266 1.766 0 2.79 1.14 1.03 1.134 1.03 3.087zm-1.438-.422q-.015-1.18-.664-1.883-.64-.703-1.703-.703-1.203 0-1.93.68-.718.68-.828 1.914z"/>""", # noqa: E501
"f": """<path d="M25.285 2.258v1.195H23.91q-.773 0-1.078.313-.297.312-.297 1.125v.773h2.367v1.117h-2.367v7.633H21.09V6.781h-1.375V5.664h1.375v-.61q0-1.46.68-2.124.68-.672 2.156-.672z"/>""", # noqa: E501
"g": """<path d="M24.973 9.937q0-1.562-.649-2.421-.64-.86-1.804-.86-1.157 0-1.805.86-.64.859-.64 2.421 0 1.555.64 2.415.648.859 1.805.859 1.164 0 1.804-.86.649-.859.649-2.414zm1.437 3.391q0 2.234-.992 3.32-.992 1.094-3.04 1.094-.757 0-1.429-.117-.672-.11-1.304-.344v-1.398q.632.344 1.25.508.617.164 1.257.164 1.414 0 2.118-.743.703-.734.703-2.226v-.711q-.446.773-1.141 1.156-.695.383-1.664.383-1.61 0-2.594-1.227-.984-1.226-.984-3.25 0-2.03.984-3.257.985-1.227 2.594-1.227.969 0 1.664.383t1.14 1.156V5.664h1.438z"/>""", # noqa: E501
"h": """<path d="M26.164 9.133v5.281h-1.437V9.18q0-1.243-.485-1.86-.484-.617-1.453-.617-1.164 0-1.836.742-.672.742-.672 2.024v4.945h-1.445V2.258h1.445v4.765q.516-.789 1.211-1.18.703-.39 1.617-.39 1.508 0 2.282.938.773.93.773 2.742z"/>""", # noqa: E501
}
XX = """<g id="xx"><path d="M35.865 9.135a1.89 1.89 0 0 1 0 2.673L25.173 22.5l10.692 10.692a1.89 1.89 0 0 1 0 2.673 1.89 1.89 0 0 1-2.673 0L22.5 25.173 11.808 35.865a1.89 1.89 0 0 1-2.673 0 1.89 1.89 0 0 1 0-2.673L19.827 22.5 9.135 11.808a1.89 1.89 0 0 1 0-2.673 1.89 1.89 0 0 1 2.673 0L22.5 19.827 33.192 9.135a1.89 1.89 0 0 1 2.673 0z" fill="#000" stroke="#fff" stroke-width="1.688"/></g>""" # noqa: E501
CHECK_GRADIENT = """<radialGradient id="check_gradient" r="0.5"><stop offset="0%" stop-color="#ff0000" stop-opacity="1.0" /><stop offset="50%" stop-color="#e70000" stop-opacity="1.0" /><stop offset="100%" stop-color="#9e0000" stop-opacity="0.0" /></radialGradient>""" # noqa: E501
DEFAULT_COLORS = {
"square light": "#ffce9e",
"square dark": "#d18b47",
"square dark lastmove": "#aaa23b",
"square light lastmove": "#cdd16a",
"margin": "#212121",
"coord": "#e5e5e5",
"arrow green": "#15781B80",
"arrow red": "#88202080",
"arrow yellow": "#e68f00b3",
"arrow blue": "#00308880",
}
class Arrow:
"""Details of an arrow to be drawn."""
tail: Square
"""Start square of the arrow."""
head: Square
"""End square of the arrow."""
color: str
"""Arrow color."""
def __init__(self, tail: Square, head: Square, *, color: str = "green") -> None:
self.tail = tail
self.head = head
self.color = color
def pgn(self) -> str:
"""
Returns the arrow in the format used by ``[%csl ...]`` and
``[%cal ...]`` PGN annotations, e.g., ``Ga1`` or ``Ya2h2``.
Colors other than ``red``, ``yellow``, and ``blue`` default to green.
"""
if self.color == "red":
color = "R"
elif self.color == "yellow":
color = "Y"
elif self.color == "blue":
color = "B"
else:
color = "G"
if self.tail == self.head:
return f"{color}{chess.SQUARE_NAMES[self.tail]}"
else:
return f"{color}{chess.SQUARE_NAMES[self.tail]}{chess.SQUARE_NAMES[self.head]}"
def __str__(self) -> str:
return self.pgn()
def __repr__(self) -> str:
return f"Arrow({chess.SQUARE_NAMES[self.tail].upper()}, {chess.SQUARE_NAMES[self.head].upper()}, color={self.color!r})"
@classmethod
def from_pgn(cls, pgn: str) -> Arrow:
"""
Parses an arrow from the format used by ``[%csl ...]`` and
``[%cal ...]`` PGN annotations, e.g., ``Ga1`` or ``Ya2h2``.
Also allows skipping the color prefix, defaulting to green.
:raises: :exc:`ValueError` if the format is invalid.
"""
if pgn.startswith("G"):
color = "green"
pgn = pgn[1:]
elif pgn.startswith("R"):
color = "red"
pgn = pgn[1:]
elif pgn.startswith("Y"):
color = "yellow"
pgn = pgn[1:]
elif pgn.startswith("B"):
color = "blue"
pgn = pgn[1:]
else:
color = "green"
tail = chess.parse_square(pgn[:2])
head = chess.parse_square(pgn[2:]) if len(pgn) > 2 else tail
return cls(tail, head, color=color)
class SvgWrapper(str):
def _repr_svg_(self) -> SvgWrapper:
return self
def _svg(viewbox: int, size: Optional[int]) -> ET.Element:
svg = ET.Element("svg", {
"xmlns": "http://www.w3.org/2000/svg",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
"version": "1.2",
"baseProfile": "tiny",
"viewBox": f"0 0 {viewbox:d} {viewbox:d}",
})
if size is not None:
svg.set("width", str(size))
svg.set("height", str(size))
return svg
def _attrs(attrs: Dict[str, Union[str, int, float, None]]) -> Dict[str, str]:
return {k: str(v) for k, v in attrs.items() if v is not None}
def _color(colors: Dict[str, str], color: str) -> Tuple[str, float]:
color = colors.get(color, DEFAULT_COLORS[color])
if color.startswith("#"):
try:
if len(color) == 5:
return color[:4], int(color[4], 16) / 0xf
elif len(color) == 9:
return color[:7], int(color[7:], 16) / 0xff
except ValueError:
pass # Ignore invalid hex value
return color, 1.0
def _coord(text: str, x: int, y: int, width: int, height: int, horizontal: bool, margin: int, *, color: str, opacity: float) -> ET.Element:
scale = margin / MARGIN
if horizontal:
x += int(width - scale * width) // 2
else:
y += int(height - scale * height) // 2
t = ET.Element("g", _attrs({
"transform": f"translate({x}, {y}) scale({scale}, {scale})",
"fill": color,
"stroke": color,
"opacity": opacity if opacity < 1.0 else None,
}))
t.append(ET.fromstring(COORDS[text]))
return t
def piece(piece: chess.Piece, size: Optional[int] = None) -> str:
"""
Renders the given :class:`chess.Piece` as an SVG image.
>>> import chess
>>> import chess.svg
>>>
>>> chess.svg.piece(chess.Piece.from_symbol("R")) # doctest: +SKIP
.. image:: ../docs/wR.svg
:alt: R
"""
svg = _svg(SQUARE_SIZE, size)
svg.append(ET.fromstring(PIECES[piece.symbol()]))
return SvgWrapper(ET.tostring(svg).decode("utf-8"))
def board(board: Optional[chess.BaseBoard] = None, *,
orientation: Color = chess.WHITE,
lastmove: Optional[chess.Move] = None,
check: Optional[Square] = None,
arrows: Iterable[Union[Arrow, Tuple[Square, Square]]] = [],
squares: Optional[IntoSquareSet] = None,
size: Optional[int] = None,
coordinates: bool = True,
colors: Dict[str, str] = {},
flipped: bool = False,
style: Optional[str] = None) -> str:
"""
Renders a board with pieces and/or selected squares as an SVG image.
:param board: A :class:`chess.BaseBoard` for a chessboard with pieces, or
``None`` (the default) for a chessboard without pieces.
:param orientation: The point of view, defaulting to ``chess.WHITE``.
:param lastmove: A :class:`chess.Move` to be highlighted.
:param check: A square to be marked indicating a check.
:param arrows: A list of :class:`~chess.svg.Arrow` objects, like
``[chess.svg.Arrow(chess.E2, chess.E4)]``, or a list of tuples, like
``[(chess.E2, chess.E4)]``. An arrow from a square pointing to the same
square is drawn as a circle, like ``[(chess.E2, chess.E2)]``.
:param squares: A :class:`chess.SquareSet` with selected squares.
:param size: The size of the image in pixels (e.g., ``400`` for a 400 by
400 board), or ``None`` (the default) for no size limit.
:param coordinates: Pass ``False`` to disable the coordinate margin.
:param colors: A dictionary to override default colors. Possible keys are
``square light``, ``square dark``, ``square light lastmove``,
``square dark lastmove``, ``margin``, ``coord``, ``arrow green``,
``arrow blue``, ``arrow red``, and ``arrow yellow``. Values should look
like ``#ffce9e`` (opaque), or ``#15781B80`` (transparent).
:param flipped: Pass ``True`` to flip the board.
:param style: A CSS stylesheet to include in the SVG image.
>>> import chess
>>> import chess.svg
>>>
>>> board = chess.Board("8/8/8/8/4N3/8/8/8 w - - 0 1")
>>> squares = board.attacks(chess.E4)
>>> chess.svg.board(board, squares=squares, size=350) # doctest: +SKIP
.. image:: ../docs/Ne4.svg
:alt: 8/8/8/8/4N3/8/8/8
.. deprecated:: 1.1
Use *orientation* with a color instead of the *flipped* toggle.
"""
orientation ^= flipped
margin = 15 if coordinates else 0
svg = _svg(8 * SQUARE_SIZE + 2 * margin, size)
if style:
ET.SubElement(svg, "style").text = style
defs = ET.SubElement(svg, "defs")
if board:
for piece_color in chess.COLORS:
for piece_type in chess.PIECE_TYPES:
if board.pieces_mask(piece_type, piece_color):
defs.append(ET.fromstring(PIECES[chess.Piece(piece_type, piece_color).symbol()]))
squares = chess.SquareSet(squares) if squares else chess.SquareSet()
if squares:
defs.append(ET.fromstring(XX))
if check is not None:
defs.append(ET.fromstring(CHECK_GRADIENT))
# Render coordinates.
if coordinates:
margin_color, margin_opacity = _color(colors, "margin")
ET.SubElement(svg, "rect", _attrs({
"x": 0,
"y": 0,
"width": 2 * margin + 8 * SQUARE_SIZE,
"height": 2 * margin + 8 * SQUARE_SIZE,
"fill": margin_color,
"opacity": margin_opacity if margin_opacity < 1.0 else None,
}))
coord_color, coord_opacity = _color(colors, "coord")
for file_index, file_name in enumerate(chess.FILE_NAMES):
x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin
svg.append(_coord(file_name, x, 0, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity))
svg.append(_coord(file_name, x, margin + 8 * SQUARE_SIZE, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity))
for rank_index, rank_name in enumerate(chess.RANK_NAMES):
y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin
svg.append(_coord(rank_name, 0, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity))
svg.append(_coord(rank_name, margin + 8 * SQUARE_SIZE, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity))
# Render board.
for square, bb in enumerate(chess.BB_SQUARES):
file_index = chess.square_file(square)
rank_index = chess.square_rank(square)
x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin
y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin
cls = ["square", "light" if chess.BB_LIGHT_SQUARES & bb else "dark"]
if lastmove and square in [lastmove.from_square, lastmove.to_square]:
cls.append("lastmove")
fill_color, fill_opacity = _color(colors, " ".join(cls))
cls.append(chess.SQUARE_NAMES[square])
ET.SubElement(svg, "rect", _attrs({
"x": x,
"y": y,
"width": SQUARE_SIZE,
"height": SQUARE_SIZE,
"class": " ".join(cls),
"stroke": "none",
"fill": fill_color,
"opacity": fill_opacity if fill_opacity < 1.0 else None,
}))
# Render check mark.
if check is not None:
file_index = chess.square_file(check)
rank_index = chess.square_rank(check)
x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin
y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin
ET.SubElement(svg, "rect", _attrs({
"x": x,
"y": y,
"width": SQUARE_SIZE,
"height": SQUARE_SIZE,
"class": "check",
"fill": "url(#check_gradient)",
}))
# Render pieces and selected squares.
for square, bb in enumerate(chess.BB_SQUARES):
file_index = chess.square_file(square)
rank_index = chess.square_rank(square)
x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin
y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin
if board is not None:
piece = board.piece_at(square)
if piece:
href = f"#{chess.COLOR_NAMES[piece.color]}-{chess.PIECE_NAMES[piece.piece_type]}"
ET.SubElement(svg, "use", {
"href": href,
"xlink:href": href,
"transform": f"translate({x:d}, {y:d})",
})
# Render selected squares.
if squares is not None and square in squares:
ET.SubElement(svg, "use", _attrs({
"href": "#xx",
"xlink:href": "#xx",
"x": x,
"y": y,
}))
# Render arrows.
for arrow in arrows:
try:
tail, head, color = arrow.tail, arrow.head, arrow.color # type: ignore
except AttributeError:
tail, head = arrow # type: ignore
color = "green"
try:
color, opacity = _color(colors, " ".join(["arrow", color]))
except KeyError:
opacity = 1.0
tail_file = chess.square_file(tail)
tail_rank = chess.square_rank(tail)
head_file = chess.square_file(head)
head_rank = chess.square_rank(head)
xtail = margin + (tail_file + 0.5 if orientation else 7.5 - tail_file) * SQUARE_SIZE
ytail = margin + (7.5 - tail_rank if orientation else tail_rank + 0.5) * SQUARE_SIZE
xhead = margin + (head_file + 0.5 if orientation else 7.5 - head_file) * SQUARE_SIZE
yhead = margin + (7.5 - head_rank if orientation else head_rank + 0.5) * SQUARE_SIZE
if (head_file, head_rank) == (tail_file, tail_rank):
ET.SubElement(svg, "circle", _attrs({
"cx": xhead,
"cy": yhead,
"r": SQUARE_SIZE * 0.9 / 2,
"stroke-width": SQUARE_SIZE * 0.1,
"stroke": color,
"opacity": opacity if opacity < 1.0 else None,
"fill": "none",
"class": "circle",
}))
else:
marker_size = 0.75 * SQUARE_SIZE
marker_margin = 0.1 * SQUARE_SIZE
dx, dy = xhead - xtail, yhead - ytail
hypot = math.hypot(dx, dy)
shaft_x = xhead - dx * (marker_size + marker_margin) / hypot
shaft_y = yhead - dy * (marker_size + marker_margin) / hypot
xtip = xhead - dx * marker_margin / hypot
ytip = yhead - dy * marker_margin / hypot
ET.SubElement(svg, "line", _attrs({
"x1": xtail,
"y1": ytail,
"x2": shaft_x,
"y2": shaft_y,
"stroke": color,
"opacity": opacity if opacity < 1.0 else None,
"stroke-width": SQUARE_SIZE * 0.2,
"stroke-linecap": "butt",
"class": "arrow",
}))
marker = [(xtip, ytip),
(shaft_x + dy * 0.5 * marker_size / hypot,
shaft_y - dx * 0.5 * marker_size / hypot),
(shaft_x - dy * 0.5 * marker_size / hypot,
shaft_y + dx * 0.5 * marker_size / hypot)]
ET.SubElement(svg, "polygon", _attrs({
"points": " ".join(f"{x},{y}" for x, y in marker),
"fill": color,
"opacity": opacity if opacity < 1.0 else None,
"class": "arrow",
}))
return SvgWrapper(ET.tostring(svg).decode("utf-8"))

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
#!/usr/bin/python3
import chess.pgn
import logging
logging.getLogger("chess.pgn").setLevel(logging.CRITICAL)
pgn = open("/mnt/cartesi-python-chess/chess-game.pgn")
game = chess.pgn.read_game(pgn)
game.errors
print(("Errors:"), game.errors)

View File

@ -0,0 +1,8 @@
#!/bin/bash
set -x
./edit-rootfs-cartesi-cartesi-python-chess
./edit-mntfs-cartesi-cartesi-python-chess
./build-cartesi-cartesi-python-chess
./run-cartesi-cartesi-python-chess

View File

@ -0,0 +1,6 @@
#!/bin/bash
set -x
vim cartesi-python-chess-cartesi-img/cartesi-python-chess.sh

View File

@ -0,0 +1,17 @@
#!/bin/bash
set -x
MYDIR=`pwd`
cd /home/jebba/devel/cartesi/machine-emulator-sdk/fs
make config
cp -p ~/devel/cartesi/machine-emulator-sdk/fs/cartesi-buildroot-config \
$MYDIR/
cp -p /home/jebba/devel/cartesi/machine-emulator-sdk/fs/rootfs.ext2 \
/opt/cartesi/share/images/rootfs-cartesi-python-chess.ext2

View File

@ -0,0 +1,9 @@
#!/bin/bash
# Launch virtual machine with pre-built root image with cartesi-python-chess
# and cartesi-python-chess.sh script in new image that gets run at boot
cartesi-machine \
--flash-drive=label:cartesi-python-chess,filename:cartesi-python-chess.ext2 \
--flash-drive=label:root,filename:/opt/cartesi/share/images/rootfs-cartesi-python-chess.ext2 \
-- /mnt/cartesi-python-chess/cartesi-python-chess.sh