def test_make_move_draw_by_threefold_repetition(self): board = chess.Board() board.push_san("Nf3") board.push_san("Nf6") board.push_san("Ng1") board.push_san("Ng8") board.push_san("Nf3") board.push_san("Nf6") board.push_san("Ng1") game = Game() game.board = board game.player1 = FakeDiscordUser(id=1) game.player2 = FakeDiscordUser(id=2) game.current_player = game.player2 chess_bot = Chess() chess_bot.games.append(game) self.assertFalse(chess_bot.is_game_over(game)) result = asyncio.run(chess_bot.make_move(game, 'Ng8')) self.assertIsInstance(result, Game) self.assertEqual(len(chess_bot.games), 0) self.assertEqual( self.db_session.query(ChessGame).filter_by(result=0).count(), 1) self.assertTrue(chess_bot.is_game_over(result)) self.assertEqual(result.result, '1/2-1/2')
def test_make_move_finish_game(self): board = chess.Board() board.push_san("g4") board.push_san("e5") board.push_san("f4") game = Game() game.board = board game.player1 = FakeDiscordUser(id=1) game.player2 = FakeDiscordUser(id=2) game.current_player = game.player1 chess_bot = Chess() chess_bot.games.append(game) result = asyncio.run(chess_bot.make_move(game, 'd8h4')) self.assertIsInstance(result, Game) self.assertEqual(len(chess_bot.games), 0) self.assertEqual( self.db_session.query(ChessGame).filter_by(result=-1).count(), 1) self.assertTrue(chess_bot.is_game_over(result)) self.assertEqual(result.result, '0-1')
class ChessCog(commands.Cog): """ Xadrez """ def __init__(self, client): self.client = client self.chess_bot = Chess() self.puzzle_bot = Puzzle() @commands.Cog.listener() async def on_connect(self): await self.chess_bot.load_games() logging.info(f'Successfully loaded {len(self.chess_bot.games)} active chess games') @commands.command(aliases=['xn']) async def xadrez_novo(self, ctx, user2: discord.User, color_schema=None): """ Inicie uma nova partida de xadrez com alguém Passe o usuário contra o qual deseja jogar para começar uma partida. \ Se quiser personalizar as cores do tabuleiro, passe o nome da cor que deseja usar \ (opções válidas: `blue`, `purple`, `green`, `red`, `gray` e `wood`). """ bot_info = await self.client.application_info() if user2.id == bot_info.id: return await ctx.send( i(ctx, "In order to play a game against the bot, use the command `{prefix}xadrez_bot`") .format(prefix=self.client.command_prefix) ) try: game = self.chess_bot.new_game(ctx.author, user2, color_schema=color_schema) await ctx.send(i(ctx, 'Game started! {}, play your move').format(game.player1.name)) except ChessException as e: await ctx.send(i(ctx, e.message)) @commands.command(aliases=['xpve', 'xcpu', 'xb']) async def xadrez_bot(self, ctx, cpu_level: int, color_schema=None): """ Inicie uma nova partida de xadrez contra o bot Passe o nível de dificuldade que desejar (de 0 a 20). \ Se quiser personalizar as cores do tabuleiro, passe o nome da cor que deseja usar \ (opções válidas: `blue`, `purple`, `green`, `red`, `gray` e `wood`). """ bot_info = await self.client.application_info() try: game = self.chess_bot.new_game( ctx.author, bot_info, cpu_level=cpu_level, color_schema=color_schema) await ctx.send(i(ctx, 'Game started! {}, play your move').format(game.player1.name)) except ChessException as e: await ctx.send(i(ctx, e.message)) @commands.command(aliases=['xj']) @get_current_game async def xadrez_jogar(self, ctx, move, *, game): """ Faça uma jogada em sua partida atual Use anotação SAN ou UCI. Movimentos inválidos ou ambíguos são rejeitados. {user2_doc} """ async with ctx.channel.typing(): try: game = await self.chess_bot.make_move(game, move) except ChessException as e: return await ctx.send(i(ctx, e.message)) if self.chess_bot.is_game_over(game): pgn = self.chess_bot.generate_pgn(game) message = f'{i(ctx, "Game over!")}\n\n{pgn}' else: message = i(ctx, "That's your turn now, {}").format(game.current_player.name) board_png_bytes = self.chess_bot.build_png_board(game) await ctx.send( content=message, file=discord.File(board_png_bytes, 'board.png') ) evaluation = await self.chess_bot.eval_last_move(game) if evaluation["blunder"]: await ctx.send("👀") elif evaluation["mate_in"] and evaluation["mate_in"] in range(1, 4): sheev_msgs = [ i(ctx, "DEW IT!"), i(ctx, "Kill him! Kill him now!"), i(ctx, "Good, {username}, good!").format(username=game.current_player.name) ] await ctx.send(sheev_msgs[evaluation["mate_in"] - 1]) @commands.command(aliases=['xa']) @get_current_game async def xadrez_abandonar(self, ctx, *, game): """ Abandone a partida atual {user2_doc} """ async with ctx.channel.typing(): game = await self.chess_bot.resign(game) pgn = self.chess_bot.generate_pgn(game) board_png_bytes = self.chess_bot.build_png_board(game) await ctx.send( content=i(ctx, '{} has abandoned the game!').format(game.current_player.name)+f'\n{pgn}', file=discord.File(board_png_bytes, 'board.png') ) @commands.command(aliases=['xpgn']) @get_current_game async def xadrez_pgn(self, ctx, *, user2: discord.User=None, game): """ Gera o PGN da partida atual {user2_doc} """ async with ctx.channel.typing(): result = self.chess_bot.generate_pgn(game) await ctx.send(result) @commands.command(aliases=['xpos']) @get_current_game async def xadrez_posicao(self, ctx, *, game): """ Mostra a posição atual da partida em andamento {user2_doc} """ async with ctx.channel.typing(): image = self.chess_bot.build_png_board(game) await ctx.send(file=discord.File(image, 'board.png')) @commands.command(aliases=['xt', 'xadrez_jogos']) async def xadrez_todos(self, ctx, page: int=0): """ Veja todas as partidas que estão sendo jogadas agora """ async with ctx.channel.typing(): png_bytes = await self.chess_bot.get_all_boards_png(page) if not png_bytes: await ctx.send( i(ctx, "No game is being played currently... ☹️ Start a new one with `{prefix}!xadrez_novo`") .format(prefix=self.client.command_prefix) ) else: await ctx.send(file=discord.File(png_bytes, 'boards.png')) @commands.command(aliases=['xgif']) async def xadrez_gif(self, ctx, game_id: str, move_number: int, *moves): """ Exibe um GIF animado com uma variante fornecida para o jogo em questão, a partir do lance fornecido É necessário passar o jogo em questão, identificado com seu UUID, e o número do lance a partir do qual \ a sequência fornecida se inicia, que deve ser uma sequência de lances em UCI ou SAN separados por espaço. Exemplo de uso: `xgif f63e5e4f-dd94-4439-a283-33a1c1a065a0 11 Nxf5 Qxf5 Qxf5 gxf5` """ async with ctx.channel.typing(): chess_game = await self.chess_bot.get_game_by_id(game_id) if not chess_game: return await ctx.send(i(ctx, "Game not found")) gif_bytes = await self.chess_bot.build_animated_sequence_gif( chess_game, move_number, moves) if not gif_bytes: return await ctx.send(i(ctx, "Invalid move for the given sequence")) return await ctx.send(file=discord.File(gif_bytes, 'variation.gif')) @commands.command(aliases=['xp']) async def xadrez_puzzle(self, ctx, puzzle_id=None, move=''): """ Pratique um puzzle de xadrez Envie o comando sem argumentos para um novo puzzle. Para tentar uma jogada em um puzzle, \ envie o ID do puzzle como primeiro argumento e a jogada como segundo. Exemplo de novo puzzle: `xadrez_puzzle` Exemplo de jogada em puzzle existente: `xadrez_puzzle 557b7aa7e13823b82b9bc1e9 Qa2` """ await ctx.trigger_typing() if not puzzle_id: puzzle_dict = await self.puzzle_bot.get_random_puzzle() if 'error' in puzzle_dict: return await ctx.send( f'{i(ctx, "There has been an error when trying to fetch a new puzzle")}: {puzzle_dict["error"]}') puzzle = self.puzzle_bot.build_puzzle(puzzle_dict) if 'error' in puzzle: return await ctx.send( f'{i(ctx, "There has been an error when trying to build a new puzzle")}: {puzzle["error"]}') return await ctx.send(puzzle["id"], file=discord.File(self.chess_bot.build_png_board(puzzle["game"]), 'puzzle.png')) try: puzzle_result = self.puzzle_bot.validate_puzzle_move(puzzle_id, move) except ChessException as e: return await ctx.send(i(ctx, e.message)) if puzzle_result: if self.puzzle_bot.is_puzzle_over(puzzle_id): return await ctx.send(i(ctx, "Good job, puzzle solved 👍")) if puzzle_result or move == '': return await ctx.send(file=discord.File( self.chess_bot.build_png_board( self.puzzle_bot.puzzles[puzzle_id]["game"]), 'puzzle.png') ) return await ctx.send(i(ctx, "Wrong answer"))