async def uno(self, ctx): ''' Play an Uno game. EVERYTHING HERE IS WIP! __How to play Uno:__ - ''' ''' uno new uno start uno join uno leave uno end uno play [card / cards (if stacking same color cards is allowed)] uno draw uno kick uno board uno hand uno config ''' if guild_or_dm(ctx).id not in self.unos: self.unos[guild_or_dm(ctx).id] = [] if ctx.invoked_subcommand == None: await ctx.send_help('uno')
async def mc_join(self, ctx, user: discord.User): ''' Join someone's Mancala game ''' mancala = self.curr_game(guild_or_dm(ctx), user, "mancalas") # arg in game check if not self.in_game(guild_or_dm(ctx), user, "mancalas") or mancala.running or len(mancala.players) > 1: await ctx.send('User is not starting a game!') return mancala.players.append(ctx.author.id) await ctx.send(f"Joined {discord.utils.escape_mentions(user.name)}'s game!")
async def mcf_turn(self, ctx, turn: int): ''' Change the game's turn. ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if turn not in (0, 1): raise commands.BadArgument('Turn number can only be set to 0 or 1.') mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") mancala.turn = turn await ctx.send(f"Set game's turn to **{mancala.player_names(turn)}**")
async def mc_finish(self, ctx, additional_message = None): """ Completes game. Triggerable via e&mancala end or by a terminal condition in e&mancala board """ mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") msg = f'Final board: ' + mancala.display(True) if additional_message != None: msg = additional_message + '\n' + msg await ctx.send(msg) self.mancalas[guild_or_dm(ctx).id].remove(mancala)
async def uno_join(self, ctx, user: discord.User): ''' Join an Uno game. ''' uno = self.curr_game(guild_or_dm(ctx), user, "unos") # arg in game check if not self.in_game(guild_or_dm(ctx), user, "unos") or uno.running: await ctx.send('User is not starting a game!') return uno.players.append(ctx.author.id) await ctx.send(f"Joined {discord.utils.escape_mentions(user.name)}'s game!")
async def uno_end(self, ctx): ''' Ends an unfinished game. ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") if ctx.author.id != uno.players[0]: await ctx.send('You are not the owner of this game! Leaving game...') await self.uno_leave(ctx) return self.unos[guild_or_dm(ctx).id].remove(uno) await ctx.send('Game ended.')
async def mc_next(self, ctx): """ Owner only: Skips the current player's move """ mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") mancala.turn = 1 - mancala.turn await self.mc_board(ctx)
async def mcf_mobile(self, ctx, arg: bool): ''' If toggled on, the board is rotated for better viewing on mobile. ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") mancala.mobile = arg await self.mc_board(ctx)
async def mc_new(self, ctx, gametype, size: int = 6): ''' Create a new Mancala game. Args: Select gametype: player vs. player, player vs. AI, or AI vs. player Select board size: The total number of slots on one side of the board ''' # gametype check if gametype == 'pvp': if ctx.guild == None: raise commands.NoPrivateMessage('PVP mode cannot be played in DMs.') players = [ctx.author.id, ] elif gametype == 'avp': players = [ai, ctx.author.id] elif gametype == 'pva': players = [ctx.author.id, ai] else: raise commands.BadArgument('Invalid gametype.') # size check if size < 1: raise commands.BadArgument('Board should at least 1 slot.') board = [[4] * size, [4] * size] for side in board: side.append(0) # display start mancala = Mancala(players=players, board=board, bot=self.bot) self.mancalas[guild_or_dm(ctx).id].append(mancala) await self.mc_board(ctx)
async def unoc_unicode(self, ctx, opt: bool): ''' Enable/disable unicode characters (`🟥🟩🟦🟨`). Enabled by default. ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["unicode"] = opt await self.uno_config(ctx)
async def mc_end(self, ctx): mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if ai not in mancala.players and ctx.author.id != mancala.players[0]: await ctx.send('You are not the owner of this game! Leaving game...') await self.mc_leave(ctx) return await self.mc_finish(ctx)
async def mc_pause(self, ctx): ''' Pause the game. ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") mancala.running = False await ctx.send('Game paused!') await self.mc_board(ctx)
async def mc_start(self, ctx): mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if len(mancala.players) == 1: await ctx.send(f'Game cannot start without two players. Type `{ctx.prefix}{self.mcf_ai} true` to add an AI player.') return mancala.running = True await ctx.send(f'Game started! Type `{ctx.prefix}{self.mc_play} [0-{mancala.size - 1}]` to play.') await self.mc_board(ctx)
async def unoc_rank_stack(self, ctx, opt: bool): ''' Enable/disable rank stacking. Disabled by default. - If enabled, cards of the same rank can be played at once. (e&uno play card1 card2 card3...) ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["rank_stack"] = opt await self.uno_config(ctx)
async def mancala(self, ctx): ''' Play a Mancala game. __How to play Mancala:__ - On both sides of the board, you have slots with a certain set of pebbles. - When playing, you pick up the pebbles in your slot, move counter-clockwise through each of the slots, dropping one pebble in each of the slots (this includes the opponent slots and your store (the large hole after slot 5), but not the opponent's store) until you run out of pebbles. - The winner is whoever has the most pebbles in their store by the end of the game. __Additional rules:__ - If your last pebble lands on your store, you get another move. - If your last pebble lands on an empty slot on your side of the board, you "capture" the opponent's slot. (This means the pebble you just placed and all of the pebbles on the opposing side are taken and added to your store.) ''' if guild_or_dm(ctx).id not in self.mancalas: self.mancalas[guild_or_dm(ctx).id] = [] if ctx.invoked_subcommand == None: await ctx.send_help('mancala')
async def unoc_hand(self, ctx, hand_size: int): ''' Change the initial size of the hands. ''' if hand_size <= 0 or hand_size >= 51: raise commands.BadArgument('Size of hands at start must be between 1 and 50 cards.') uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["hand_size"] = hand_size await self.uno_config(ctx)
async def uno_start(self, ctx): ''' Start an Uno game after it's been created. At least two people are necessary for a game to start. ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.start() await self.uno_board(ctx) for user_id, hand in uno.hands.items(): await self.bot.get_user( int(user_id) ).send('**Your hand:**```' + ' '.join(uno.display_card(card) for card in hand) + '```')
async def unoc_draw_stack(self, ctx, opt: bool): ''' Enable/disable draw stacking. Enabled by default. - When forced to draw cards due to a +2 or +4 card, you can place a +2 or +4 to avoid drawing and pass the burden onto the next player. - Considered a house rule by Hasbro ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["draw_stack"] = opt await self.uno_config(ctx)
async def unoc_jump_in(self, ctx, opt: bool): ''' Enable/disable jump ins. Disabled by default. - If the card on the top of the discard pile matches the rank and color of a card in your hand, that card can be played, skipping all players before you. - Considered a house rule by Hasbro ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["jump_in"] = opt await self.uno_config(ctx)
async def mc_leave(self, ctx): mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if ai in mancala.players or len(mancala.players) == 1: await self.mc_end(ctx) return mancala.running = False mancala.players.remove(ctx.author.id) await ctx.send('You have left the game.')
async def uno_new(self, ctx, hand_size: int = 7): ''' Make a new Uno game. Use `e&uno config` to configurate game. ''' if hand_size <= 0 or hand_size >= 51: raise commands.BadArgument('Size of hands at start must be between 1 and 50 cards.') uno = Uno(players=[ctx.author.id], hand_size=hand_size, bot=self.bot) self.unos[guild_or_dm(ctx).id].append(uno) await ctx.send(f'New Uno game created!\nType `{ctx.prefix}{self.uno_config}` to configurate game.\nType `{ctx.prefix}{self.uno_join} @{ctx.author}` to join this game.\nType `{ctx.prefix}{self.uno_start}` to start.')
async def unoc_seven_o(self, ctx, opt: bool): ''' Enable/disable special abilities of rank 0 and 7. Disabled by default. - Every time a 0 is played, all players pass their hands to the next player in direction of play. - Every time a 7 is played, the player who played the 7 card must trade their hand with another player of their choice. - Considered a house rule by Hasbro ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") uno.config["seven_o"] = opt await self.uno_config(ctx)
async def uno_board(self, ctx): ''' Show current discard pile. ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") display_pile = [uno.display_card(card) for card in uno.discard_pile] display_pile.reverse() top, rest = display_pile[0], display_pile[1:] disp_str = f"**Top card**: `{top.rjust(2, ' ')}`\n" disp_str += f"**Rest of pile**:```{' '.join(card.rjust(2, ' ') for card in rest)}```" if len(rest) > 0 else '' await ctx.send(disp_str)
async def mc_play(self, ctx, slot: int): ''' Select a slot to play. ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if mancala.players[mancala.turn] != ctx.author.id: await ctx.send("It's not your turn!") return if slot < 0 or slot >= mancala.size or mancala.board[mancala.turn][slot] == 0: raise commands.BadArgument("You can't play that slot!") mancala.replace(mancala.result([slot])) await self.mc_board(ctx)
async def uno_leave(self, ctx): ''' Leave an Uno game. Cards are returned to the Draw pile. ''' uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") if len(uno.players) == 1: await self.uno_end(ctx) return uno.players.remove(ctx.author.id) hand = uno.hands.pop(ctx.author.id) uno.draw_pile += hand random.shuffle(uno.draw_pile) await ctx.send('You have left the game. Your hand has been reshuffled into the draw pile.')
async def mc_config(self, ctx): ''' Change the configuration of the board. ''' if ctx.invoked_subcommand == None: mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") configs = { "board": mancala.board, "turn": mancala.turn, "ai": ai in mancala.players, "mobile": mancala.mobile, } config_str = '```py\n' + '\n'.join([f'{key}: {str(val)}' for key, val in configs.items()]) + '```' config_str += f'Type `{ctx.prefix}{self.mc_config} <setting> <new value>` to change the desired setting.' await ctx.send(config_str)
async def eval(self, ctx, *, args: str): ''' Evaluates a Python expression. If this is not blocked, then whoops, I'm doomed! ''' # shorthands bot = self.bot author = ctx.author channel = ctx.channel guild = guild_or_dm(ctx) cogs = bot.cogs try: await ctx.send(eval(args)) except Exception as err: await ctx.send(str(err)) ANSI.print('red', str(err)) print_exc()
async def uno_config(self, ctx): ''' Enable/disable house rules before starting. ''' if ctx.invoked_subcommand == None: uno = self.curr_game(guild_or_dm(ctx), ctx.author, "unos") configs = { "hand": uno.config["hand_size"], "unicode": uno.config["unicode"], "draw_stack": uno.config["draw_stack"], "jump_in": uno.config["jump_in"], "seven-o": uno.config["seven_o"], "rank_stack": uno.config["rank_stack"], } config_str = '```py\n' + '\n'.join([f'{key}: {str(val)}' for key, val in configs.items()]) + '```' config_str += f'Type `{ctx.prefix}{self.uno_config} <setting> <new value>` to change the desired setting.' await ctx.send(config_str)
async def mc_board(self, ctx): ''' Load board. ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") def gen_player_disp(): str = '' if len(mancala.players) == 1: str += 'Waiting for second player...' elif mancala.turn == 0: str += f'**{mancala.player_names(0)}** vs. {mancala.player_names(1)}' else: str += f'{mancala.player_names(0)} vs. **{mancala.player_names(1)}**' if mancala.special == 'capture': str += '\nCapture!' elif mancala.special == 'again': str += '\nFree move!' return str if not mancala.running: if len(mancala.players) == 1: await ctx.send(gen_player_disp() + mancala.display() + f'\nType `{ctx.prefix}{self.mc_join} [user]` to join!') return await ctx.send(gen_player_disp() + mancala.display() + f'\nType `{ctx.prefix}{self.mc_start}` to begin!') return await ctx.send(gen_player_disp() + mancala.display()) if mancala.players[mancala.turn] == ai: best_move = mancala.minimax(5)[1] await ctx.send(str(best_move)) await sleep(1) for move in best_move: mancala.replace(mancala.result([move])) await ctx.send(gen_player_disp() + mancala.display()) await sleep(1) if mancala.terminal(): # let normal display play but then play the end screen mancala.end() if winner := mancala.player_names(mancala.winner()): await self.mc_finish(ctx, f'**Winner: {winner}**') else: await self.mc_finish(ctx, 'Tie!') return
async def mcf_ai(self, ctx, ai_player: bool): ''' Add or remove AI player from game ''' mancala = self.curr_game(guild_or_dm(ctx), ctx.author, "mancalas") if ai_player: # two players in game if len(mancala.players) != 1: await ctx.send('There are currently two players in game. A player must leave before adding an AI player.') return mancala.players.append(ai) await self.mc_board(ctx) return # ai isn't in game if ai not in mancala.players: await ctx.send('AI is not in game.') return mancala.players.remove(ai) await self.mc_board(ctx)