Skip to content

Commit

Permalink
Draft of completed load/save
Browse files Browse the repository at this point in the history
  • Loading branch information
bcorfman committed Nov 7, 2022
1 parent 49034fa commit abe0b1e
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 119 deletions.
3 changes: 3 additions & 0 deletions base/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ def __init__(self, squares, annotation=""):
self.affected_squares = squares
self.annotation = annotation

def __eq__(self, other):
return self.affected_squares == other.affected_squares

def __repr__(self):
return str(self.affected_squares)
2 changes: 1 addition & 1 deletion game/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def _get_captures(self):
player = self.to_move
enemy = self.enemy
squares = self.squares
valid_indices = WHITE_IDX if player == 'white' else BLACK_IDX
valid_indices = WHITE_IDX if player == WHITE else BLACK_IDX
all_captures = []
for i in self.valid_squares:
if squares[i] & player and squares[i] & MAN:
Expand Down
56 changes: 38 additions & 18 deletions game/gamemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
from tkinter import Label, SUNKEN, NW
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter.messagebox import askyesnocancel, showerror
from util.globalconst import BLACK, WHITE, TITLE, VERSION, KING, MAN, PROGRAM_TITLE, TRAINING_DIR
from util.globalconst import square_map, keymap
from datetime import datetime
from game.checkers import Checkers
from gui.boardview import BoardView
from gui.filelist import FileList
from gui.playercontroller import PlayerController
from gui.alphabetacontroller import AlphaBetaController
from parsing.PDN import PDNReader
from parsing.PDN import PDNReader, PDNWriter
from util.globalconst import BLACK, WHITE, TITLE, VERSION, KING, MAN, PROGRAM_TITLE, TRAINING_DIR
from util.globalconst import square_map, keymap


class GameManager(object):
Expand Down Expand Up @@ -174,32 +175,51 @@ def save_game(self):

def _write_file(self, filename):
try:
saved_game = SavedGame()
# redo moves up to the end of play, if possible
to_move = self.model.curr_state.to_move
scoring = self.model.utility(to_move, self.model.curr_state)
if scoring == -4000:
if to_move == WHITE:
result = "1-0"
else:
result = "0-1"
elif scoring == 4000:
if to_move == WHITE:
result = "0-1"
else:
result = "1-0"
else:
result = "*"
# undo moves back to the beginning of play
undo_steps = 0
while self.model.curr_state.undo_list:
undo_steps += 1
self.model.curr_state.undo_move(None, True, True, self.view.get_annotation())
# save the state of the board
saved_game.to_move = self.model.curr_state.to_move
saved_game.num_players = self.num_players
saved_game.black_men = []
saved_game.black_kings = []
saved_game.white_men = []
saved_game.white_kings = []
to_move = self.model.curr_state.to_move
black_men = []
black_kings = []
white_men = []
white_kings = []
for i, sq in enumerate(self.model.curr_state.squares):
if sq == BLACK | MAN:
saved_game.black_men.append(keymap[i])
black_men.append(keymap[i])
elif sq == BLACK | KING:
saved_game.black_kings.append(keymap[i])
black_kings.append(keymap[i])
elif sq == WHITE | MAN:
saved_game.white_men.append(keymap[i])
white_men.append(keymap[i])
elif sq == WHITE | KING:
saved_game.white_kings.append(keymap[i])
# saved_game.description = self.view.serializer.dump()
saved_game.moves = self.model.curr_state.redo_list
saved_game.flip_board = self.view.flip_view
saved_game.write(filename)
white_kings.append(keymap[i])
description = self.view.serializer.dump()
moves = self.model.curr_state.redo_list
annotations = []
board_orientation = "white_on_top" if self.view.flip_view is False else "black_on_top"
black_player = "Player1"
white_player = "Player2"
PDNWriter.to_file(filename, '*', '*', datetime.now().strftime("%d/%m/%Y"), '*', black_player, white_player,
to_move, black_men, white_men, black_kings, white_kings, result, board_orientation,
description, moves, annotations)

# redo moves forward to the previous state
for i in range(undo_steps):
annotation = self.view.get_annotation()
Expand Down
100 changes: 66 additions & 34 deletions parsing/PDN.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from pyparsing import Combine, Forward, Group, LineStart, LineEnd, Literal, OneOrMore, Optional, \
QuotedString, Suppress, Word, WordEnd, WordStart, nums, one_of, rest_of_line, srange
from typing import NamedTuple
from base.move import Move
from game.checkers import Checkers
from util.globalconst import BLACK_IDX, WHITE_IDX, square_map
from util.globalconst import keymap, square_map, WHITE, BLACK


def _is_move(delta):
Expand All @@ -20,7 +21,7 @@ def _removeLineFeed(s):

Game = NamedTuple("Game", [("event", str), ("site", str), ("date", str),
("round", str), ("black_player", str), ("white_player", str),
("next_to_move", str), ("black_men", list), ("white_men", list),
("next_to_move", int), ("black_men", list), ("white_men", list),
("black_kings", list), ("white_kings", list),
("result", str), ("board_orientation", str),
("description", str), ("moves", list)])
Expand Down Expand Up @@ -188,7 +189,7 @@ def _set_board_defaults_if_needed(self):
if self._flip_board is None:
self._flip_board = "white_on_top"
if self._next_to_move is None:
self._next_to_move = "black"
self._next_to_move = BLACK
if self._black_men is None:
self._black_men = list(range(1, 13))
self._black_kings = []
Expand Down Expand Up @@ -235,6 +236,7 @@ def read_game(self, idx):
"FEN": self._read_fen,
"BoardOrientation": self._read_board_orientation}

self._reset_pdn_vars()
if not self._game_indexes:
self.get_game_list()
self._stream.seek(self._game_indexes[idx])
Expand Down Expand Up @@ -272,14 +274,14 @@ def read_game(self, idx):
return Game(self._event, self._site, self._date, self._round, self._black_player,
self._white_player, self._next_to_move, self._black_men, self._white_men,
self._black_kings, self._white_kings, self._result, self._flip_board,
self._description, self._translate_moves_to_board(self._moves))
self._description, self._PDN_to_board(self._moves))

def _get_player_to_move(self, turn):
turn = turn.upper()
if turn == "B":
result = "black"
result = BLACK
elif turn == "W":
result = "white"
result = WHITE
else:
raise SyntaxError("Unknown turn type {turn} in FEN")
return result
Expand Down Expand Up @@ -312,26 +314,29 @@ def _try_jump(self, squares: list, annotation: str, state_copy: Checkers):
board_squares = [square_map[sq] for sq in squares]
if self._model.captures_available(state_copy):
legal_moves = self._model.legal_moves(state_copy)
sq_len = len(squares)
for move in legal_moves:
if all(sq == move.affected_squares[i*2][0] for i, sq in enumerate(board_squares)):
move.annotation = annotation
self._model.make_move(move, state_copy, False, False)
return move

def _translate_moves_to_board(self, moves: list):
def _PDN_to_board(self, pdn_moves: list):
""" Each move in the file lists the beginning and ending square, along
with an optional annotation string (in Creole fmt) that describes it.
I make sure that each move works on a copy of the model before I commit
to using it inside the code. """
state_copy = copy.deepcopy(self._model.curr_state)

# remove last item in list before processing if it's a single element
# (i.e., game separator)
last_move, last_annotation = pdn_moves[-1]
if len(last_move) == 1:
pdn_moves.pop()
# analyze squares to perform a move or jump.
idx = 0
moves_len = len(moves)
moves_len = len(pdn_moves)
translated_moves = []
while idx < moves_len:
squares, annotation = moves[idx]
squares, annotation = pdn_moves[idx]
delta = squares[0] - squares[1]
if _is_move(delta):
move = self._try_move(squares, annotation, state_copy)
Expand All @@ -350,10 +355,10 @@ def _translate_moves_to_board(self, moves: list):
return translated_moves


def _translate_to_fen(next_to_move, black_men, white_men, black_kings, white_kings):
if next_to_move.lower() == "black":
def translate_to_fen(next_to_move, black_men, white_men, black_kings, white_kings):
if next_to_move == 'black':
fen = "B:"
elif next_to_move.lower() == "white":
elif next_to_move == 'white':
fen = "W:"
else:
raise RuntimeError(f"Unknown player {next_to_move} in next_to_move variable")
Expand Down Expand Up @@ -384,18 +389,14 @@ def _translate_to_text(move):
return sep.join([str(n) for n in move])

moves.reverse()
if annotations:
annotations.reverse()
annotations.reverse()
movetext = ""
movenum = 0
while True:
if len(moves) == 0:
break
item = moves.pop()
if annotations:
anno = annotations.pop()
else:
anno = ["", ""]
anno = annotations.pop()

if len(item) == 1:
movetext += item.pop()
Expand All @@ -408,30 +409,30 @@ def _translate_to_text(move):
# will be replaced with spaces.
movetext += f"{movenum}.`"
black_move = item.pop()
comment = anno.pop()
if comment and comment[0] in ['!', '?']:
tokens = comment.split(maxsplit=1)
black_comment = anno.pop()
if black_comment and black_comment[0] in ['!', '?']:
tokens = black_comment.split(maxsplit=1)
black_strength = tokens[0]
comment = tokens[1] if len(tokens) > 1 else ""
black_comment = tokens[1] if len(tokens) > 1 else ""
else:
black_strength = ""
movetext += f"{_translate_to_text(black_move)}{black_strength}"
if comment:
movetext += " {" + f"{comment}" + "} "
if black_comment:
movetext += " {" + f"{black_comment}" + "} "
else:
movetext += "`"
if item:
white_move = item.pop()
comment = anno.pop()
if comment and comment[0] in ['!', '?']:
tokens = comment.split(maxsplit=1)
white_comment = anno.pop()
if white_comment and white_comment[0] in ['!', '?']:
tokens = white_comment.split(maxsplit=1)
white_strength = tokens[0]
comment = tokens[1] if len(tokens) > 1 else ""
white_comment = tokens[1] if len(tokens) > 1 else ""
else:
white_strength = ""
movetext += f"{_translate_to_text(white_move)}{white_strength}"
if comment:
movetext += " {" + f"{comment}" + "}"
if white_comment:
movetext += " {" + f"{white_comment}" + "}"
movetext += " "
return movetext

Expand Down Expand Up @@ -459,13 +460,15 @@ def _write(self, event: str, site: str, date: str, rnd: str, black_player: str,
frozenset(white_men) != frozenset(range(21, 33))):
self.stream.write('[SetUp "1"]')
self.stream.write(f'[FEN "{result}"]\n')
for line in self._wrapper.wrap(_translate_to_fen(next_to_move, black_men, white_men, black_kings,
white_kings)):
for line in self._wrapper.wrap(translate_to_fen(next_to_move, black_men, white_men, black_kings,
white_kings)):
self.stream.write(line + '\n')
self.stream.write(f'[BoardOrientation "{board_orientation}"]\n')
if description:
for line in description:
self.stream.write(line)
if annotations is None:
annotations = [["", ""] for _ in moves]
for line in self._wrapper.wrap(_translate_to_movetext(moves, annotations)):
line = line.replace("`", " ") # NOTE: see _translate_to_movetext function
self.stream.write(line + '\n')
Expand All @@ -490,3 +493,32 @@ def to_stream(cls, stream, event, site, date, rnd, black_player, white_player, n
black_kings, white_kings, result, board_orientation, moves, annotations=None, description=""):
cls(stream, event, site, date, rnd, black_player, white_player, next_to_move, black_men, white_men, black_kings,
white_kings, result, board_orientation, description, moves, annotations)


def board_to_PDN(board_moves: list[Move]):
pdn_moves = ""
move_count = 1
for idx, move in enumerate(board_moves):
num_squares = len(move.affected_squares)
if idx % 2 == 0:
pdn_moves += f"{move_count}. "
move_count += 1
if num_squares == 2: # move
sq1 = keymap[move.affected_squares[0][0]]
sq2 = keymap[move.affected_squares[1][0]]
pdn_moves += f"{sq1}-{sq2}"
elif num_squares >= 3: # jump
for i in range(0, num_squares-2, 2):
sq = keymap[move.affected_squares[i][0]]
pdn_moves += f"{sq}x"
sq = keymap[move.affected_squares[-1][0]]
pdn_moves += f"{sq}"
else:
raise RuntimeError("unknown number of affected_squares")
if move.annotation:
pdn_moves += " {" + f"{move.annotation}" + "}"
if idx % 2 == 1:
pdn_moves += " "
else:
pdn_moves += " "
return pdn_moves.rstrip()
22 changes: 0 additions & 22 deletions parsing/gamepersist.py

This file was deleted.

Loading

0 comments on commit abe0b1e

Please sign in to comment.