Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readme enhancement #36

Merged
merged 16 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,39 @@ Special thanks and dedication to LeMerluche, crushing its opponents on chess.com

## How to play with interface
```python
from interface.interface import MyApp
from pyalapin.interface.interface import MyApp

if __name__ == '__main__':
MyApp().run()
MyApp(
play_with_ai=False # Set to True if you want to play agains AI
).run()

```

![](interface_example.PNG)
![](docs/scholars_mate_interface.gif)

## How to play with Python commands

<img align="right" src="docs/scholars_mate_command.gif">

```python
import sys
sys.path.append("python/")
import python.engine as engine

game = engine.engine.Game()
game = engine.engine.Game(
automatic_draw=True, # Set to True if you want
# to have each turn drawn in terminal
ai=False, # set to True if you want to play agains AI
save_pgn=False # set to True if you want to
# save moves as PGN
)
game.move_from_coordinates(game.player1, 1, 4, 3, 4)
game.move_from_coordinates(game.player2, 6, 0, 5, 0)
game.move_from_coordinates(game.player2, 6, 4, 4, 4)
game.move_from_coordinates(game.player1, 0, 5, 3, 2)
game.move_from_coordinates(game.player2, 6, 3, 5, 4)
game.move_from_coordinates(game.player1, 0, 3, 2, 5)
game.move_from_coordinates(game.player2, 6, 2, 4, 2)
game.move_from_coordinates(game.player2, 2, 5, 6, 5)
```
There are colors in the command line not showing here in the GIF, though...
Binary file added docs/scholars_mate_command.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/scholars_mate_interface.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 29 additions & 4 deletions pyalapin/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,9 @@ def is_threatened(

# King + Rook + Queen
# Checking direct surroundings
for i, j in [(1, 0), (0, -1), (-1, 0), (0, -1)]:
for i, j in [(1, 0), (0, -1), (-1, 0), (0, 1)]:
x_to_check = self.x + i
y_to_check = self.y + j

if 0 <= x_to_check < 8 and 0 <= y_to_check < 8:
cell_to_check = board.get_cell(x_to_check, y_to_check)
piece_to_check = cell_to_check.get_piece()
Expand Down Expand Up @@ -964,11 +963,17 @@ class Game:
List storing all the played move during the game.
automatic draw: bool
Whether to draw the board in the terminal at each round.
save_pgn: bool
Whether to keep track of the moves with PGN.
history: list of str
PGN representation of the past move of the game.
"""

game_status = []

def __init__(self, player1=None, player2=None, automatic_draw=True, ai=False):
def __init__(
self, player1=None, player2=None, automatic_draw=True, ai=False, save_pgn=False
):
"""Initialization of the cell.

Parameters
Expand Down Expand Up @@ -1007,13 +1012,17 @@ def __init__(self, player1=None, player2=None, automatic_draw=True, ai=False):
self.board = Board()
self.status = "ACTIVE"
self.played_moves = []
self.save_pgn = save_pgn
if self.save_pgn:
self.history = []

self.automatic_draw = automatic_draw

def reset_game(self):
"""Method to reset the game. Recreates the borad, the pieces and restarts the game."""
self.board.reset()
self.played_moves = []
self.history = []
self.to_play_player = self.player1

def to_fen(self):
Expand Down Expand Up @@ -1200,6 +1209,8 @@ def move(self, move, player):

# Store move
self.played_moves.append(move)
if self.save_pgn:
self.history.append(move.to_pgn())

# Change player
if self.to_play_player == self.player1:
Expand Down Expand Up @@ -1271,11 +1282,25 @@ def save(self, directory="debug_files"):
draw_text = draw_text.replace("\x1b[31m", "")
import os
import matplotlib.pyplot as plt

"""
plt.rc("figure", figsize=(12, 7))
plt.text(
0.01, 0.05, str(draw_text), {"fontsize": 10}, fontproperties="monospace"
)
plt.axis("off")
plt.tight_layout()
plt.savefig(os.path.join(directory, str(len(self.played_moves)) + ".png"))
"""
with open(os.path.join(directory, str(len(self.played_moves)) + ".txt"), "w") as f:
f.writelines(draw_text)

def to_pgn(self):
assert self.save_pgn
pgn = ""
for i in range(len(self.history)):
if i % 2 == 0:
pgn += f"{int(i/2)+1}. "
pgn += self.history[i]
pgn += " "

return pgn[:-1]
38 changes: 37 additions & 1 deletion pyalapin/engine/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,42 @@ def _set_moved_attribute(self):
else:
self.moved_piece.last_move_is_double = False

def to_pgn(self):
"""
Method to return the PGN representation of the move.

Returns
-------
str:
pgn representation of the move
"""
rows = ["a", "b", "c", "d", "e", "f", "g", "h"]
start = f"{rows[self.start.y]}{self.start.x + 1}"
end = f"{rows[self.end.y]}{self.end.x + 1}"
piece = self.moved_piece.get_str().replace(" ", "")
if isinstance(self.moved_piece, material.Pawn):
piece = ""
if self.killed_piece is not None:
start += "x"
elif self.is_castling:
if (self.moved_piece.is_white() and self.end.y == 1) or (
not self.moved_piece.is_white() and self.end.y == 6
):
piece = "O-O-O"
start = ""
end = ""
king = (
self.board.white_king
if not self.player.white_side
else self.board.black_king
)
if self.board.get_cell(king.x, king.y).is_threatened(
board=self.board, threaten_color=not self.player.white_side
):
end += "+"
print(f"{piece}{start}{end}")
return f"{piece}{start}{end}"

def _set_castling_done(self):
"""
If self is a castling move, then when it is done this function sets the castling_done attribute
Expand Down Expand Up @@ -140,7 +176,7 @@ def _is_castling(self):
return False

else:
if self.end.y == 6: # Castling in the right
if self.end.y == 6: # Castling on the right
rook_to_move = self.board.get_cell(self.start.x, 7).get_piece()
if not isinstance(rook_to_move, material.Rook):
return False
Expand Down
9 changes: 5 additions & 4 deletions pyalapin/player/ai_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,11 @@ def _alpha_beta(
beta=beta,
is_white=not is_white,
)
random_noise = np.random.randint(0, self.random_coeff)
best_move = [best_move, p_mv][
np.argmax([best_score, score + random_noise])
]
if self.random_coeff > 0:
random_noise = np.random.randint(0, self.random_coeff)
else:
random_noise = 0
best_move = [best_move, p_mv][np.argmax([best_score, score + random_noise])]
best_score = np.max([best_score, score + random_noise])

if best_score >= beta:
Expand Down
6 changes: 1 addition & 5 deletions run_app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import sys

sys.path.append("python/")

from pyalapin.interface.interface import MyApp

if __name__ == "__main__":
MyApp(play_with_ai=True).run()
MyApp(play_with_ai=False).run()
12 changes: 9 additions & 3 deletions tests/unit_test/engine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ def test_end_game():
print(keep_going, status)


if __name__ == "__main__":
test_en_passant()
test_end_game()
def test_pgn():
"""Tests the pgn history of the game."""
game = engine.Game(automatic_draw=False, save_pgn=True)
game.move_from_coordinates(game.player1, 1, 4, 3, 4)
game.move_from_coordinates(game.player2, 6, 5, 4, 5)
game.move_from_coordinates(game.player1, 0, 3, 4, 7)
game.move_from_coordinates(game.player2, 6, 6, 5, 6)
print(game.to_pgn())
assert game.to_pgn() == "1. e2e4 f7f5 2. Qd1h5+ g7g6"
Loading