def player_move(game: Game) -> None: """ loop to wait for move from player = eventdetected from reed switch matrix. The loop is finished when a valid move has been made. """ State.set(States.PLAYER_TURN) LOG.info('player turn') epaper_screen.update_frame(button_panel, epaper.game_player_turn(button_panel)) epaper_screen.update_frame(button_panel, epaper.game_engine_info( player_turn=True, engine=game.setup.engine), important=False) epaper_screen.update_frame(button_panel, epaper.game_player_turn( button_panel=button_panel, content=epaper.PLAYER_WAIT, partial_frame=True), important=False) legal_moves = game.board.legal_moves legal_move_from = {move.from_square for move in game.board.legal_moves} while State.is_set(States.PLAYER_TURN): if game.piece_up is None: legal_squares = legal_move_from else: legal_squares = { move.to_square for move in legal_moves if move.from_square == game.piece_up } LOG.debug('waiting for move...') button_panel.wait_for_move() if state.is_set(States.MAIN): return incoming = serial_arduino.new_detected_move() if game.hint: erase_hint = epaper.PartialFrame(name='erase_hint', width=200, height=40, pos=(200, 165), important=False) epaper_screen.update_frame(button_panel, erase_hint) game.hint = False new_move = validate_player_move(game, incoming, legal_squares) if isinstance(new_move, chess.Move): break if game.setup.wait_to_confirm: epaper_screen.update_frame(button_panel, epaper.PLAYER_CONFIRM) while not confirm_move(game): pass new_move = chess.Move(game.piece_up, incoming) push_move(game, new_move) State.set(States.GAME)
def undo(game: Game) -> None: """ wait for correct reversed move. show player 2 reversed moves (1 computer, 1 player) remove moves from GAME.board.movestack but keep a copy in the GAME.move_stack_copy keep the old movestack until a new move/confirmation computer move has been made (in case of "redo" call) :return: """ LOG.debug('BUTTON_EVENT undo') # (led indicators) make frame show computer move in reverse move1 = game.board.pop() # pop function from chess.Board move2 = game.board.pop() # copy the move stack fir when the redo function is called game.move_stack_copy.append(move1) game.move_stack_copy.append(move2) # reverse moves move1 = chess.Move(move1.to_square, move1.from_square) move2 = chess.Move(move2.to_square, move2.from_square) text0 = epaper.FrameText(pos=(214, 15), content='Undo move:', fill=config.WHITE) text1 = epaper.FrameText(pos=(30, 40), content=''.join([str(move2), str(move1)]), font=config.FONT_BIG) epaper_screen.update_frame(button_panel, epaper.game_player_turn( button_panel=button_panel, content=(text0, text1), partial_frame=True), important=False) # Interrupt active on buttons 'undo' 'redo' # Undo 1 computer move while True: button_panel.wait_for_move() if validate_computer_move(game, move1): break # Undo 1 player move while True: button_panel.wait_for_move() if validate_computer_move(game, move2): break epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel)) epaper_screen.update_frame(button_panel, epaper.game_player_turn( button_panel=button_panel, content=epaper.PLAYER_WAIT, partial_frame=True), important=False)
def invalid_move(game: Game) -> None: """Handle invalid moves""" if game.piece_up is None: message = 'This piece cannot be moved' else: message = 'Invalid move' validate_board(game, message=message) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel)) epaper_screen.update_frame(button_panel, epaper.game_player_turn( button_panel=button_panel, content=epaper.PLAYER_WAIT, partial_frame=True), important=False)
def redo(game: Game) -> None: """ redo undone move(s). Show player 2 moves. (1 computer, 1 player). Remove moves from GAME.move_stack_copy and push them on the GAME.board :return: """ LOG.debug('BUTTON_EVENT redo') if game.move_stack_copy == 0: message = epaper.FrameText(content='This is the last move', pos=(15, 6)) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=message, partial_frame=True)) return # led indicators # Get 2 moves from the movestack copy move1 = game.move_stack_copy.pop() move2 = game.move_stack_copy.pop() text = epaper.FrameText(pos=(15, 6), content=''.join([str(move2), str(move1)]), fill=config.WHITE, font=config.FONT_BIG) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=text, partial_frame=True)) while True: button_panel.wait_for_move() if validate_computer_move(game, move1): game.board.push(move1) break while True: button_panel.wait_for_move() if validate_computer_move(game, move2): game.board.push(move2) break
def back_to_game(game: Game) -> None: """ go back to previous GAME menu: - Validate board OR - player turn OR - Computer turn """ LOG.debug('BUTTON_EVENT back to GAME') if state.is_set(States.BOARD_INVALID): # redraw the 'validate board' frame current_board = get_board_square_set(game.board) incoming_board = chess.SquareSet(squares=serial_arduino.ask_board()) frame = epaper.game_validate_board(button_panel, "board invalid", current_board, incoming_board, game.board) epaper_screen.update_frame(button_panel, frame, important=True) serial_arduino.trigger_arduino_int() # wait again for a reed interrupt elif state.is_set(States.PLAYER_TURN): engine_info = epaper.game_engine_info(player_turn=True, engine=game.setup.engine) epaper_screen.update_frame(button_panel, epaper.game_player_turn(button_panel)) epaper_screen.update_frame(button_panel, engine_info, important=False) elif state.is_set(States.COMPUTER_TURN): engine_info = epaper.game_engine_info(player_turn=False, engine=game.setup.engine) epaper_screen.update_frame( button_panel, epaper.game_computer_turn(button_panel=button_panel)) epaper_screen.update_frame(button_panel, engine_info, important=False) if game.computer_move.move: new_move = game.computer_move.move epaper_screen.update_frame(button_panel, epaper.COMPUTER_CONFIRM) epaper_screen.update_frame( button_panel, epaper.game_computer_turn(button_panel=button_panel, move_text=epaper.get_move_text( new_move, game.board), partial_frame=True)) else: epaper_screen.update_frame( button_panel, epaper.game_computer_turn( button_panel=button_panel, move_text=epaper.game_computer_thinking(game.setup), partial_frame=True), important=False) # Waiting for player to make computer move button_panel.toggle_alarm(active=False)
def push_move(game: Game, move: chess.Move) -> None: """ Push move to board.move_stack :param game: Game :param move: chess.Move :return: """ if game.setup.color.value == game.board.turn: epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=epaper.PLAYER_MOVE_CONFIRMED, partial_frame=True)) game.board.push(move) game.piece_up = -1 LOG.info('move pushed')
def give_hint(game: Game) -> None: """Write ponder move on the frame --> frame_player_turn""" LOG.debug('BUTTON_EVENT give hint') epaper_screen.update_frame(button_panel, epaper.PLAYER_HINT) if game.computer_move.ponder is not None: text = epaper.get_move_text(game.computer_move.ponder, game.board) else: text = epaper.FrameText(content='No hint available', pos=(75, 25), fill=config.WHITE, font=config.FONT_BIGGER, align=config.CENTER) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=text, partial_frame=True)) game.hint = True
def validate_player_move(game: Game, move: int, legal_moves: Set[chess.Move]) -> chess.Move: """ validations: - can the piece make any move (black and white)? - did the piece made a valid move? - is the move a capture? - detects special moves: castling, promotion, en passant - did the player put a piece back on it"s original square (Which is against some chess rule...)? if any kind of move appears to be invalid the program will get stuck in a loop from the "indicate_missing_pieces" function until all pieces are putted back to the original position (at the beginning of the turn) :returns the valid chess.Move or None in case of a wrong move """ result = None LOG.debug('validate new player move') legal_squares_up = set(move.from_square for move in legal_moves) legal_squares_down = set(move.to_square for move in legal_moves) # INVALID MOVE if move not in legal_squares_up.union(legal_squares_down): LOG.info('invalid move!') invalid_move(game) # VALID MOVE elif move in legal_squares_up: # 1: Put piece back # 2: Piece up # put piece back on same square (not always valid by the chess rules :-) if move == game.piece_up: LOG.info('piece putted back') game.piece_up = None epaper_screen.update_frame(button_panel, epaper.game_player_turn( button_panel=button_panel, content=epaper.PLAYER_WAIT, partial_frame=True), important=False) # Piece up else: game.piece_up = move LOG.info('piece up: %s square_nr:%s', chess.square_name(move), move) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=epaper.get_half_move_text( move, game.board), partial_frame=True)) else: new_move = chess.Move(game.piece_up, move) LOG.info('new move: %s', new_move.uci()) # 1: En passant? # 2: Castling? # 3: Promotion? # 4: normal move # en passant, capture or castling if validate_en_passant(game, new_move) or validate_caputure( game, new_move) or validate_castling(game, new_move): text = epaper.get_move_text(new_move, game.board) # promotion elif game.board.piece_type_at( game.piece_up) == chess.PAWN and chess.square_rank(move) in [ 0, 7 ] and validate_promotion(new_move): text = epaper.get_move_text(new_move, game.board) LOG.info('promotion succesfull!') # normal move else: LOG.info('move is valid') text = epaper.get_move_text(new_move, game.board) epaper_screen.update_frame( button_panel, epaper.game_player_turn(button_panel=button_panel, content=text, partial_frame=True)) result = new_move return result