Cqsi / lichs

♟ Play chess against real players in your terminal using Lichess
https://pypi.org/project/lichs/
MIT License
114 stars 19 forks source link

Reworking Game class #8

Closed ralacerda closed 3 years ago

ralacerda commented 4 years ago

Hello, I was wondering if there should be an effort to re-write the Game class. I think having separated functions to deal with moving and priting the board ( like in #7 ) would make it easier later on if we want to change how the board is displayed, or if you want a way to change between UCI and Algebric. Here are some changes I propose and some code to get us started: (I'm no pyhon expert, so please let me know if there is a better way to do this)

I don't think we need Game to inherent Thread (since we are most likely playing just one game each time).

Game only needs to take three arguments:

Each Game() instance should create its own chess.Board() instance, instead of a global chess.Board().

Instead of making the move on the chess.Board() and sending it to Lichess at the same time, I think we need to first send the command to Lichess, and then we wait for Lichess to send our own move. I think it would then be better to check the legality of the move locally before sending it to Lichess.

I think there is a lot of python-chess features we can use like chess.WHITE and chess.BLACK.

We should also use chess.Board.turn() everytime we get a move update, instead of trying to keep track locally.

import chess

class Game:

    def __init__(self, lichess_board, game_id, player_id):
        self.lichess_board = lichess_board
        self.game_id = game_id
        self.player_id = player_id
        self.stream = self.lichess_board.stream_game_state(self.game_id)

        self.initial_status = next(self.stream)

        self.list_move = self.initial_status["state"]["moves"].split(" ")

        self.chess_board = chess.Board()

We store lichess_board, game_id and player_id We call next(self.stream) for the first time, which will always send us the game information, and the moves so far (we save those to a list). We create an instance of chess.Board().


    def set_player_color(self):
        if "id" in self.initial_status["white"]:
            if self.initial_status["white"]["id"] == self.player_id:
                print("Player is white")
                self.player_color = chess.WHITE
            else:
                print("Player is black")
                self.player_color = chess.BLACK
        else:
            print("Player is black")
            self.player_color = chess.BLACK

This function just checks if the player is white or black. We need to check if "id" is a valid key, because when playing the AI it has no "id".


    def print_board(self):
        if self.player_color is chess.WHITE:
            print(self.chess_board)
        else:
            vertical_flip = self.chess_board.transform(chess.flip_vertical)
            final_flip = vertical_flip.transform(chess.flip_horizontal)
            print(final_flip)

This function flips the board, we can also use ( #7 ).

    def start_game(self):
        self.set_player_color()

        for move_uci in self.list_move:
            move = self.chess_board.parse_uci(move_uci)
            self.chess_board.push(move)

        self.print_board()

We start the game by setting the player color, pushing the stored moves to our local board (this means you can connect to a game midway). And we print the board.

What is missing right now is the event loop for the game. I suggest we go the following way:

  1. chess.Board.turn() checks if it is the player turn:

    • Ask the player for input, if it is valid, send it to lichess, then call next(self.stream)
    • Otherwise, call next(self.stream)
  2. When we receive a new change of state from lichess, we make the move in our local board (this can be either player move), we go back to 1. again.

I think this changes to the class would lead to the following:

Please let me know what you guys think. We can create a separated branch and test it out.

ddugovic commented 4 years ago

I've contributed https://github.com/Cqsi/lichs/actions configuration, so we'll see over time what makes things easier to test. :)

Cqsi commented 3 years ago

Closing since some of the issues have been resolved.