-
Notifications
You must be signed in to change notification settings - Fork 3
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
Game loop GUI #247
base: master
Are you sure you want to change the base?
Game loop GUI #247
Changes from 17 commits
77ec111
5ec03c5
117ee4c
6581f57
30f4776
4dc02b5
3140930
ecd9e30
e8dceb8
8d8aa2e
b6c1a21
2c8eee4
6bf3a6f
8f92c5b
6622816
507ac33
08ab6e2
c07d357
f74ded9
2af1212
db1b27e
5457e78
21c7a54
5937e34
d6a5066
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
""" | ||
adapted code from: | ||
* Title: chess_tk | ||
* Author: Guatam Sharma | ||
* Date: May 19, 2016 | ||
* Availability: https://github.com/saavedra29/chess_tk | ||
""" | ||
from copy import deepcopy | ||
import re | ||
import pieces | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a newline between |
||
|
||
START_PATTERN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of having this be global, can you pls make it a class variable? You can add it right after the declaration of |
||
|
||
|
||
class Board(dict): | ||
"""Board class to disply current board state. | ||
""" | ||
y_axis = ("A", "B", "C", "D", "E", "F", "G", "H") | ||
x_axis = (1, 2, 3, 4, 5, 6, 7, 8) | ||
captured_pieces = {"white": [], "black": []} | ||
player_turn = None | ||
halfmove_clock = 0 | ||
fullmove_number = 1 | ||
history = [] | ||
|
||
def __init__(self, pat=None): # pylint: disable=super-init-not-called unused-argument | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of having this pylint disable comment, please add super().__init__() as the first line of the function and remove the pylint comment |
||
self.show(START_PATTERN) | ||
|
||
def is_in_check_after_move(self, p1, p2): | ||
"""Checks if the king is in check after move has been made | ||
""" | ||
tmp = deepcopy(self) | ||
tmp.move(p1, p2) | ||
return tmp.king_in_check(self[p1].color) | ||
|
||
def shift(self, p1, p2): | ||
"""Checks if a move is valid and then makes the move | ||
""" | ||
p1, p2 = p1.upper(), p2.upper() | ||
piece = self[p1] | ||
try: | ||
dest = self[p2] | ||
except: # pylint: disable=W0702 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of having this pylint disable comment, please change the line except Exception as e: and remove the pylint comment |
||
dest = None | ||
if self.player_turn != piece.color: | ||
raise NotYourTurn("Not " + piece.color + "'s turn!") | ||
enemy = ("white" if piece.color == "black" else "black") | ||
moves_available = piece.moves_available(p1) | ||
if p2 not in moves_available: | ||
raise InvalidMove | ||
if self.all_moves_available(enemy): | ||
if self.is_in_check_after_move(p1, p2): | ||
raise Check | ||
if not moves_available and self.king_in_check(piece.color): | ||
raise CheckMate | ||
elif not moves_available: | ||
raise Draw | ||
else: | ||
self.move(p1, p2) | ||
self.complete_move(piece, dest, p1, p2) | ||
|
||
def move(self, p1, p2): | ||
"""Moves a piece from p1 to p2 | ||
""" | ||
piece = self[p1] | ||
try: | ||
dest = self[p2] #pylint: disable=W0612 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls change the name of |
||
except: # pylint: disable=W0702 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, |
||
pass | ||
del self[p1] | ||
self[p2] = piece | ||
|
||
def complete_move(self, piece, dest, p1, p2): #pylint: disable=unused-argument | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pls update the function signature to remove |
||
"""Makes a complete move by updating values and changes the turn to the opponent | ||
""" | ||
enemy = ("white" if piece.color == "black" else "black") | ||
if piece.color == "black": | ||
self.fullmove_number += 1 | ||
self.halfmove_clock += 1 | ||
self.player_turn = enemy | ||
abbr = piece.shortname | ||
if abbr == "P": | ||
abbr = "" | ||
self.halfmove_clock = 0 | ||
if dest is None: | ||
movetext = abbr + p2.lower() | ||
else: | ||
movetext = abbr + "x" + p2.lower() | ||
self.halfmove_clock = 0 | ||
self.history.append(movetext) | ||
|
||
def all_moves_available(self, color): | ||
"""Returns an array of all the available moves | ||
""" | ||
result = [] | ||
for coord in self.keys(): | ||
if (self[coord] is not None) and self[coord].color == color: | ||
moves = self[coord].moves_available(coord) | ||
if moves: result += moves | ||
return result | ||
|
||
def occupied(self, color): | ||
"""Returns an array of occupied coordinates | ||
""" | ||
result = [] | ||
for coord in iter(self.keys()): | ||
if self[coord].color == color: | ||
result.append(coord) | ||
return result | ||
|
||
def position_of_king(self, color): | ||
"""Returns the position of the king | ||
""" | ||
for pos in self.keys(): | ||
if isinstance(self[pos], pieces.King) and self[pos].color == color: | ||
return pos | ||
|
||
def king_in_check(self, color): | ||
"""Checks if the king is in check | ||
""" | ||
kingpos = self.position_of_king(color) | ||
opponent = ("black" if color == "white" else "white") | ||
for pieces in self.items(): #pylint: disable=redefined-outer-name unused-variable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please change the variable name for _ in self.items():
return bool(kingpos in self.all_moves_available(opponent)) and then remove |
||
return bool(kingpos in self.all_moves_available(opponent)) | ||
|
||
def alpha_notation(self, xycoord): | ||
"""Returns x,y coordinates in numbers and letters (e.g., "e6") of | ||
position on chessboard. | ||
""" | ||
if xycoord[0] < 0 or xycoord[0] > 7 or xycoord[1] < 0 or xycoord[ | ||
1] > 7: | ||
return | ||
return self.y_axis[int(xycoord[1])] + str(self.x_axis[int(xycoord[0])]) | ||
|
||
def num_notation(self, coord): | ||
"""Returns x,y coordinates in numbers of position on chessboard. | ||
""" | ||
return int(coord[1]) - 1, self.y_axis.index(coord[0]) | ||
|
||
def is_on_board(self, coord): | ||
"""Checks if the given coord is on the board | ||
""" | ||
if coord[1] < 0 or coord[1] > 7 or coord[0] < 0 or coord[0] > 7: | ||
return False | ||
else: | ||
return True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can condense this to return all(coord[1] >= 0, coord[1] <= 7, coord[0] >= 0, coord[0] <= 7) |
||
|
||
def show(self, pat): | ||
"""Prints a visual representation of the board state based on a | ||
fen string. | ||
""" | ||
self.clear() | ||
pat = pat.split(" ") | ||
|
||
def expand(match): | ||
return " " * int(match.group(0)) | ||
|
||
pat[0] = re.compile(r"\d").sub(expand, pat[0]) | ||
for x, row in enumerate(pat[0].split("/")): | ||
for y, letter in enumerate(row): | ||
if letter == " ": | ||
continue | ||
coord = self.alpha_notation((7 - x, y)) | ||
self[coord] = pieces.create_piece(letter) | ||
self[coord].place(self) | ||
if pat[1] == "w": | ||
self.player_turn = "white" | ||
else: | ||
self.player_turn = "black" | ||
self.halfmove_clock = int(pat[4]) | ||
self.fullmove_number = int(pat[5]) | ||
|
||
class ChessError(Exception): | ||
pass | ||
|
||
class Check(ChessError): | ||
pass | ||
|
||
class InvalidMove(ChessError): | ||
pass | ||
|
||
class CheckMate(ChessError): | ||
pass | ||
|
||
class Draw(ChessError): | ||
pass | ||
|
||
class NotYourTurn(ChessError): | ||
pass | ||
|
||
class InvalidCoord(ChessError): | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,7 @@ def is_white_turn(self): | |
def last_made_move(self): | ||
"""Returns the last made move, if applicable. If no moves have been made, returns None. | ||
""" | ||
if self.board.engine.chess_board.move_stack: | ||
if not self.board.engine.chess_board.move_stack: | ||
return None | ||
return self.board.engine.chess_board.peek().uci() | ||
|
||
|
@@ -74,7 +74,7 @@ def send_uci_move_to_board(self, uci_move): | |
"Should we loop until move is valid? What if " | ||
"the board is messed up? Need to revisit.") | ||
|
||
def process(self, player): | ||
def process(self, player, verbose=False): | ||
"""One iteration of main game loop. | ||
|
||
Note: expects caller to check game.is_game_over before calling. | ||
|
@@ -85,11 +85,12 @@ def process(self, player): | |
made_move: boolean that is True if turn changes, otherwise False. | ||
""" | ||
arduino_status = self.board.get_status_from_arduino() | ||
print(f"\nBoard Status: {arduino_status}") | ||
if verbose: | ||
print(f"\nBoard Status: {arduino_status}") | ||
|
||
if arduino_status.status == status.ArduinoStatus.EXECUTING_MOVE: | ||
# Wait for move in progress to finish executing | ||
time.sleep(1) # reduce the amount of polling while waiting for move to finish | ||
time.sleep(.01) # reduce the amount of polling while waiting for move to finish | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please make this a static class variable called |
||
|
||
if self.board.ser is None: | ||
# Allows testing other game loop functionality with simulated connection to Arduino | ||
|
@@ -105,7 +106,7 @@ def process(self, player): | |
|
||
if arduino_status.status == status.ArduinoStatus.IDLE: | ||
# Don't spam new Arduino messages too frequently if waiting for Arduino status to update | ||
time.sleep(1) | ||
time.sleep(.01) | ||
|
||
if self.board.msg_queue: | ||
# We have a separate move counter for moves and instructions; to resolve conflicts | ||
|
@@ -170,5 +171,5 @@ def process(self, player): | |
|
||
raise ValueError("We shouldn't reach this point in the function.") | ||
|
||
if __name__ == '__main__': | ||
print("No main for this file, please use `cliinterface.py`") | ||
if __name__ == '__main__': | ||
print("No main for this file, please use `cliinterface.py`") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be indented |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update to: