def _move(self, from_: Coords, to: Coords): piece_from = self.get_piece_at(from_, self.grid, fail_if_no_piece=True) piece_to = self.get_piece_at(to, self.grid) # un check check :D. If king is checked only an attempt at solving it # could have been done king = self.get_king(piece_from.color) if king.is_checked: king.is_checked = False # update grid first self.grid[to.row, to.col], self.grid[from_.row, from_.col] = \ self.grid[from_.row, from_.col], 0 # update sprite second if piece_to: self.sprites.remove(piece_to) self.captured.append(self.pieces.pop(piece_to.pid)) piece_from.pos = to # check if movement results in any kind of check if self.is_king_checked(self.grid, Color.next(piece_from.color)): rival_king = self.get_king(Color.next(piece_from.color)) rival_king.is_checked = True # set moved to true third try: piece_from.moved = True except AttributeError: pass
def is_king_checked(self, grid, color): rival_color = Color.next(color) for p in self.get_pieces_for_color(grid, rival_color): for move in p.possible_moves(grid): piece_to = self.get_piece_at(move, grid) if piece_to and piece_to.type == PieceType.king: return True return False
def log_turn(self, prom): self.moves += 1 self.move.log(f'[{self.moves:03}]') msg = str(self.last_move) if prom: msg += ' promoting!' if self.board.is_king_checked(self.board.grid, Color.next(self.turn)): msg += ' check!' self.move.log(msg) self.move.log('')
def draw_armies(self): for i, row in enumerate(self.grid): for j, cell in enumerate(row): if cell: c = str(cell) pid = PieceId(num=cell, color=Color(int(c[-2])), type=PieceType(int(c[-1]))) piece = PieceFactory.make(pid, Coords(x=j, y=i)) self.pieces[pid.num] = piece self.sprites.add(piece)
def events(self, events): move = None grid_click_pos = None promotion_click_pos = None prom = False for event in events: if event.type == pg.KEYDOWN: if event.key == pg.K_d: self.debug = not self.debug if event.type == pg.MOUSEBUTTONUP: if self.is_promoting and self.promotion.rect.collidepoint(event.pos): # check if click was in the promotion menu promotion_click_pos = event.pos elif not self.is_promoting and self.board.rect.collidepoint(event.pos): # check if click was inside chess grid grid_click_pos = event.pos if self.check_mate() or self.draw(): self.is_game_over = True return # no more mr nice guy # handle turn: move or promote is_machine = self.players[self.turn].type == 'machine' if not self.is_promoting and (grid_click_pos or is_machine): mpos = self.board.px_to_grid(Coords(x=grid_click_pos[0], y=grid_click_pos[1])) \ if grid_click_pos is not None else None move = self.players[self.turn].move( self.board, mpos ) elif self.is_promoting and (promotion_click_pos or is_machine): prom = self.players[self.turn].promote( board=self.board, pawn=self.pawn_prom, promotion_selector=self.promotion, pos=promotion_click_pos if promotion_click_pos else None ) self.is_promoting = False self.pawn_prom = None # check if there are any promotions to be done self.pawn_prom = self.board.promotions(self.turn) if self.pawn_prom: self.is_promoting = True if move: self.last_move = move # next turn happens when there are NO PENDING # PROMOTIONS and a MOVE or a PROMOTION took place. if not self.is_promoting and (move or prom): self.log_turn(prom) self.turn = Color.next(self.turn)
def get_piece(self, color: Color, type: PieceType, num: int): uid = num * 100 + Color(color).value * 10 + PieceType(type).value try: return self.pieces[uid] except KeyError: return None
def get_king(self, color: Color): uid = 100 + Color(color).value * 10 + PieceType.king.value return self.pieces[uid]