Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Reorganisation of game processing
Browse files Browse the repository at this point in the history
  • Loading branch information
M-DinhHoangViet committed Mar 4, 2024
1 parent 945c5d5 commit d57f415
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 78 deletions.
16 changes: 0 additions & 16 deletions enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,6 @@ class Variant(Enum):
THREE_CHECK = 'threeCheck'


class Game_Status(Enum):
CREATED = 'created'
STARTED = 'started'
ABORTED = 'aborted'
MATE = 'mate'
RESIGN = 'resign'
STALEMATE = 'stalemate'
TIMEOUT = 'timeout'
DRAW = 'draw'
OUT_OF_TIME = 'outoftime'
CHEAT = 'cheat'
NO_START = 'noStart'
UNKNOWN_FINISH = 'unknownFinish'
VARIANT_END = 'variantEnd'


class Perf_Type(Enum):
ULTRA_BULLET = 'ultraBullet'
BULLET = 'bullet'
Expand Down
67 changes: 26 additions & 41 deletions game.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,32 @@
from api import API
from lichess_bot_dataclasses import Game_Information
from chatter import Chatter
from enums import Game_Status
from lichess_game import Lichess_Game


class Game(Thread):
def __init__(self, config: dict, api: API, game_id: str, game_finished_event: Event) -> None:
def __init__(self, config: dict, api: API, game_id: str, game_finished_event: Event, game_queue: Queue) -> None:
Thread.__init__(self)
self.config = config
self.api = api
self.game_id = game_id
self.game_finished_event = game_finished_event
self.lichess_game: Lichess_Game
self.chatter: Chatter
self.game_info: Game_Information
self.game_queue = game_queue

self.game_info = Game_Information.from_gameFull_event(self.game_queue.get())
self.lichess_game = Lichess_Game(self.api, self.game_info, self.config)
self.chatter = Chatter(self.api, self.config, self.game_info, self.lichess_game)

def start(self):
Thread.start(self)

def run(self) -> None:
game_queue = Queue()
game_queue_thread = Thread(target=self.api.get_game_stream, args=(self.game_id, game_queue), daemon=True)
game_queue_thread.start()

self.game_info = Game_Information.from_gameFull_event(game_queue.get())
self._print_game_information()

self.lichess_game = Lichess_Game(self.api, self.game_info, self.config)
self.chatter = Chatter(self.api, self.config, self.game_info, self.lichess_game)

self.chatter.send_greetings()

if self._finish_game(self.game_info.state.get('winner')):
if self.game_info.state['status'] != 'started':
self._print_result_message(self.game_info.state)
self.chatter.send_goodbyes()
self.lichess_game.end_game()
return

Expand All @@ -50,7 +44,7 @@ def run(self) -> None:
abortion_time = datetime.now() + timedelta(seconds=abortion_seconds)

while True:
event = game_queue.get()
event = self.game_queue.get()

if event['type'] not in ['gameFull', 'gameState']:
if self.lichess_game.is_abortable and datetime.now() >= abortion_time:
Expand All @@ -59,25 +53,24 @@ def run(self) -> None:
self.chatter.send_abortion_message()

if event['type'] == 'gameFull':
self.lichess_game.update(event['state'])

if self._finish_game(event['state'].get('winner')):
if event['state']['status'] != 'started':
self._print_result_message(event['state'])
self.chatter.send_goodbyes()
break

if self.lichess_game.is_our_turn:
self._make_move()
else:
self.lichess_game.start_pondering()
elif event['type'] == 'gameState':
updated = self.lichess_game.update(event)

if self._finish_game(event.get('winner')):
if event['status'] != 'started':
self._print_result_message(event)
self.chatter.send_goodbyes()
break

if self.lichess_game.is_game_over:
continue
self.lichess_game.update(event)

if self.lichess_game.is_our_turn and updated:
if self.lichess_game.is_our_turn and not self.lichess_game.board.is_repetition():
self._make_move()
elif event['type'] == 'chatLine':
self.chatter.handle_chat_message(event)
Expand All @@ -99,23 +92,15 @@ def _make_move(self) -> None:
self.api.send_move(self.game_id, uci_move, offer_draw)
self.chatter.print_eval()

def _finish_game(self, winner: str | None) -> bool:
if self.lichess_game.is_finished:
self._print_result_message(winner)
self.chatter.send_goodbyes()
return True

return False

def _print_game_information(self) -> None:
opponents_str = f'{self.game_info.white_str} - {self.game_info.black_str}'
message = (5 * ' ').join([self.game_info.id_str, opponents_str, self.game_info.tc_str,
self.game_info.rated_str, self.game_info.variant_str])

print(f'\n{message}\n{128 * "‾"}')

def _print_result_message(self, winner: str | None) -> None:
if winner:
def _print_result_message(self, game_state: dict) -> None:
if winner:= game_state.get('winner'):
if winner == 'white':
message = f'{self.game_info.white_name} won'
loser = self.game_info.black_name
Expand All @@ -127,19 +112,19 @@ def _print_result_message(self, winner: str | None) -> None:
white_result = '0'
black_result = '1'

if self.lichess_game.status == Game_Status.MATE:
if game_state['status'] == 'mate':
message += ' by checkmate!'
elif self.lichess_game.status == Game_Status.OUT_OF_TIME:
elif game_state['status'] == 'outoftime':
message += f'! {loser} ran out of time.'
elif self.lichess_game.status == Game_Status.RESIGN:
elif game_state['status'] == 'resign':
message += f'! {loser} resigned.'
elif self.lichess_game.status == Game_Status.VARIANT_END:
elif game_state['status'] == 'variantEnd':
message += ' by variant rules!'
else:
white_result = '½'
black_result = '½'

if self.lichess_game.status == Game_Status.DRAW:
if game_state['status'] == 'draw':
if self.lichess_game.board.is_fifty_moves():
message = 'Game drawn by 50-move rule.'
elif self.lichess_game.board.is_repetition():
Expand All @@ -150,7 +135,7 @@ def _print_result_message(self, winner: str | None) -> None:
message = 'Game drawn by variant rules.'
else:
message = 'Game drawn by agreement.'
elif self.lichess_game.status == Game_Status.STALEMATE:
elif game_state['status'] == 'stalemate':
message = 'Game drawn by stalemate.'
else:
message = 'Game aborted.'
Expand Down
6 changes: 5 additions & 1 deletion game_manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections import deque
from datetime import datetime, timedelta
from queue import Queue
from threading import Event, Thread

from aliases import Challenge_ID, Game_ID
Expand Down Expand Up @@ -129,7 +130,10 @@ def _start_game(self, game_id: Game_ID) -> None:
self.api.abort_game(game_id)
return

self.games[game_id] = Game(self.config, self.api, game_id, self.changed_event)
game_queue = Queue()
Thread(target=self.api.get_game_stream, args=(game_id, game_queue), daemon=True).start()

self.games[game_id] = Game(self.config, self.api, game_id, self.changed_event, game_queue)
self.games[game_id].start()

def _finish_game(self, game_id: Game_ID) -> None:
Expand Down
23 changes: 3 additions & 20 deletions lichess_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from api import API
from lichess_bot_dataclasses import Book_Settings, Game_Information, Move_Response
from engine import Engine
from enums import Game_Status, Variant
from enums import Variant


class Lichess_Game:
Expand All @@ -26,7 +26,6 @@ def __init__(self, api: API, game_information: Game_Information, config: dict) -
self.black_time: float = self.game_info.state['btime'] / 1000
self.increment = self.game_info.increment_ms / 1000
self.is_white: bool = self.game_info.white_name == config['username']
self.status = Game_Status(self.game_info.state['status'])
self.draw_enabled: bool = config['offer_draw']['enabled']
self.resign_enabled: bool = config['resign']['enabled']
self.move_overhead = self._get_move_overhead()
Expand Down Expand Up @@ -75,39 +74,23 @@ def make_move(self) -> tuple[UCI_Move, Offer_Draw, Resign]:
self._offer_draw(move_response.is_drawish),
self._resign(move_response.is_resignable))

def update(self, gameState_event: dict) -> bool:
self.status = Game_Status(gameState_event['status'])

def update(self, gameState_event: dict) -> None:
moves = gameState_event['moves'].split()
if len(moves) <= len(self.board.move_stack):
return False
return

self.board.push(chess.Move.from_uci(moves[-1]))
self.white_time = gameState_event['wtime'] / 1000
self.black_time = gameState_event['btime'] / 1000

return True

@property
def is_our_turn(self) -> bool:
return self.is_white == self.board.turn

@property
def is_game_over(self) -> bool:
return self.board.is_checkmate() or \
self.board.is_stalemate() or \
self.board.is_insufficient_material() or \
self.board.is_fifty_moves() or \
self.board.is_repetition()

@property
def is_abortable(self) -> bool:
return len(self.board.move_stack) < 2

@property
def is_finished(self) -> bool:
return self.status != Game_Status.STARTED

@property
def own_time(self) -> float:
return self.white_time if self.is_white else self.black_time
Expand Down

0 comments on commit d57f415

Please sign in to comment.