From d3936fa1a9e2aaeb773fb2531df917b2745e9691 Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Mon, 5 Apr 2021 23:06:30 +0200 Subject: [PATCH] :Sparkles: Converted all hex functionality to slash commands --- cogs/GameCogs.py | 39 ++- funcs/games/gameLoops.py | 66 ----- funcs/games/gamesContainer.py | 2 - funcs/games/hex.py | 512 ++++++++++++++++++++-------------- funcs/games/hexDraw.py | 2 +- utils/helperClasses.py | 7 +- 6 files changed, 321 insertions(+), 307 deletions(-) delete mode 100644 funcs/games/gameLoops.py diff --git a/cogs/GameCogs.py b/cogs/GameCogs.py index ae07f11..87f71fe 100644 --- a/cogs/GameCogs.py +++ b/cogs/GameCogs.py @@ -115,37 +115,36 @@ class HexCog(commands.Cog): def __init__(self,bot): """Runs game stuff.""" self.bot = bot + # Start a game of Hex against another user @cog_ext.cog_subcommand(**params["hexStartUser"]) async def hexStartUser(self, ctx, user): - await ctx.defer() - await self.bot.games.gameLoops.runHex(ctx, "start "+user.display_name, "#"+str(ctx.author.id)) + await self.bot.games.hex.start(ctx, user) # Start a game of Hex against Gwendolyn @cog_ext.cog_subcommand(**params["hexStartGwendolyn"]) async def hexStartGwendolyn(self, ctx, difficulty = 2): - await ctx.defer() - await self.bot.games.gameLoops.runHex(ctx, "start "+str(difficulty), "#"+str(ctx.author.id)) - - # Undo your last hex move - @cog_ext.cog_subcommand(**params["hexUndo"]) - async def hexUndo(self, ctx): - await self.bot.games.gameLoops.runHex(ctx, "undo", "#"+str(ctx.author.id)) - - # Perform a hex swap - @cog_ext.cog_subcommand(**params["hexSwap"]) - async def hexSwap(self, ctx): - await self.bot.games.gameLoops.runHex(ctx, "swap", "#"+str(ctx.author.id)) - - # Surrender the hex game - @cog_ext.cog_subcommand(**params["hexSurrender"]) - async def hexSurrender(self, ctx): - await self.bot.games.gameLoops.runHex(ctx, "surrender", "#"+str(ctx.author.id)) + await self.bot.games.hex.start(ctx, difficulty) # Place a piece in the hex game @cog_ext.cog_subcommand(**params["hexPlace"]) async def hexPlace(self, ctx, coordinates): - await self.bot.games.gameLoops.runHex(ctx, "place "+coordinates, "#"+str(ctx.author.id)) + await self.bot.games.hex.placeHex(ctx, coordinates, f"#{ctx.author.id}") + + # Undo your last hex move + @cog_ext.cog_subcommand(**params["hexUndo"]) + async def hexUndo(self, ctx): + await self.bot.games.hex.undo(ctx) + + # Perform a hex swap + @cog_ext.cog_subcommand(**params["hexSwap"]) + async def hexSwap(self, ctx): + await self.bot.games.hex.swap(ctx) + + # Surrender the hex game + @cog_ext.cog_subcommand(**params["hexSurrender"]) + async def hexSurrender(self, ctx): + await self.bot.games.hex.surrender(ctx) def setup(bot): diff --git a/funcs/games/gameLoops.py b/funcs/games/gameLoops.py deleted file mode 100644 index c5215d4..0000000 --- a/funcs/games/gameLoops.py +++ /dev/null @@ -1,66 +0,0 @@ -import asyncio -import discord - -class GameLoops(): - def __init__(self,bot): - self.bot = bot - - - # Deletes a message - async def deleteMessage(self, imageLocation,channel): - try: - with open("resources/games/oldImages/"+imageLocation, "r") as f: - messages = f.read().splitlines() - - for message in messages: - oldMessage = await channel.fetch_message(int(message)) - self.bot.log("Deleting old message") - await oldMessage.delete() - except: - oldMessage = "" - - return oldMessage - - # Runs Hex - async def runHex(self,ctx,command,user): - channelId = ctx.channel_id - try: - response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.games.hex.parseHex(command,str(channelId),user) - except: - self.bot.log("Error parsing command (error code 1510)") - - await ctx.send(response) - - self.bot.log(response,str(channelId)) - if showImage: - if deleteImage: - try: - oldImage = await self.deleteMessage("hex"+str(channelId),ctx.channel) - except: - self.bot.log("Error deleting old image (error code 1501)") - oldImage = await ctx.channel.send(file = discord.File("resources/games/hexBoards/board"+str(channelId)+".png")) - if gwendoTurn and not gameDone: - try: - response, showImage, deleteImage, gameDone, gwendoTurn = self.bot.games.hex.hexAI(str(channelId)) - except: - response, showImage, deleteImage, gameDone, gwendoTurn = "An AI error ocurred",False,False,False,False - self.bot.log("AI error (error code 1520)") - await ctx.channel.send(response) - self.bot.log(response,str(channelId)) - if showImage: - if deleteImage: - await oldImage.delete() - oldImage = await ctx.channel.send(file = discord.File("resources/games/hexBoards/board"+str(channelId)+".png")) - if not gameDone: - with open("resources/games/oldImages/hex"+str(channelId), "w") as f: - f.write(str(oldImage.id)) - - if gameDone: - game = self.bot.database["hex games"].find_one({"_id":str(channelId)}) - - winner = game["winner"] - if winner != 0 and game["players"][0] != game["players"][1]: # player1 != player2 - winnings = game["difficulty"]*10 - self.bot.money.addMoney(game["players"][winner-1].lower(),winnings) - - self.bot.databaseFuncs.deleteGame("hex games",str(channelId)) diff --git a/funcs/games/gamesContainer.py b/funcs/games/gamesContainer.py index 099acff..203209a 100644 --- a/funcs/games/gamesContainer.py +++ b/funcs/games/gamesContainer.py @@ -2,7 +2,6 @@ from .invest import Invest from .trivia import Trivia from .blackjack import Blackjack from .connectFour import ConnectFour -from .gameLoops import GameLoops from .hangman import Hangman from .hex import HexGame @@ -14,6 +13,5 @@ class Games(): self.trivia = Trivia(bot) self.blackjack = Blackjack(bot) self.connectFour = ConnectFour(bot) - self.gameLoops = GameLoops(bot) self.hangman = Hangman(bot) self.hex = HexGame(bot) diff --git a/funcs/games/hex.py b/funcs/games/hex.py index 3af263f..7cc5274 100644 --- a/funcs/games/hex.py +++ b/funcs/games/hex.py @@ -1,6 +1,7 @@ import random import copy import math +import discord from .hexDraw import DrawHex @@ -13,102 +14,146 @@ for position in ALL_POSITIONS: HEX_DIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)] class HexGame(): - def __init__(self,bot): + def __init__(self, bot): self.bot = bot self.draw = DrawHex(bot) - # Parses command - def parseHex(self, command, channel, user): - commands = command.lower().split() + async def surrender(self, ctx): + channel = str(ctx.channel_id) game = self.bot.database["hex games"].find_one({"_id":channel}) - if command == "" or command == " ": - return "I didn't get that. Use \"/hex start [opponent]\" to start a game.", False, False, False, False - - elif commands[0] == "start": - # Starting a game - if len(commands) == 1: # if the commands is "/hex start", the opponent is Gwendolyn at difficulty 2 - commands.append("2") - self.bot.log("Starting a hex game with hexStart(). "+str(user)+" challenged "+commands[1]) - return self.hexStart(channel,user,commands[1]) # commands[1] is the opponent - - # If using a command with no game, return error - elif game == None: - return "There's no game in this channel", False, False, False, False - - # Stopping the game - elif commands[0] == "stop": - if user in game["players"]: - return "Ending game.", False, False, True, False - else: - return "You can't end a game where you're not a player.", False, False, False, False - - # Placing a piece - elif commands[0] == "place": - try: - return self.placeHex(channel,commands[1], user) - except: - return "I didn't get that. To place a piece use \"/hex place [position]\". A valid position is e.g. \"E2\".", False, False, False, False - - # Undo - elif commands[0] == "undo": - return self.undoHex(channel, user) - - # Surrender - elif commands[0] == "surrender": - players = game["players"] - if user in players: - opponent = (players.index(user) + 1) % 2 - self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}}) - return "{} surrendered. That means {} won! Adding 30 Gwendobucks to their account.".format(self.bot.databaseFuncs.getName(user),self.bot.databaseFuncs.getName(players[opponent])), False, False, True, False - else: - return "You can't surrender when you're not a player.", False, False, False, False - - # Swap - elif commands[0] == "swap": - if len(game["gameHistory"]) == 1: # Only after the first move - self.bot.database["hex games"].update_one({"_id":channel}, - {"$set":{"players":game["players"][::-1]}}) # Swaps their player-number - - # Swaps the color of the hexes on the board drawing: - self.draw.drawSwap(channel) - player2 = game["players"][1] - gwendoTurn = (player2 == "Gwendolyn") - return "The color of both players were swapped. It is now {}'s turn".format(player2), True, True, False, gwendoTurn - else: - return "You can only swap as the second player after the very first move.", False, False, False, False + user = f"#{ctx.author.id}" + players = game["players"] + if user not in players: + await ctx.send("You can't surrender when you're not a player.") else: - return "I didn't get that. Use \"/hex start [opponent]\" to start a game, \"/hex place [position]\" to place a piece, \"/hex undo\" to undo your last move or \"/hex stop\" to stop a current game.", False, False, False, False + opponent = (players.index(user) + 1) % 2 + opponentName = self.bot.databaseFuncs.getName(players[opponent]) + self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}}) + await ctx.send(f"{ctx.author.display_name} surrendered. That means {opponentName} won! Adding 30 Gwendobucks to their account") + + with open(f"resources/games/oldImages/hex{channel}", "r") as f: + oldImage = await ctx.channel.fetch_message(int(f.read())) + + if oldImage is not None: + await oldImage.delete() + else: + self.bot.log("The old image was already deleted") + + self.bot.log("Sending the image") + filePath = f"resources/games/hexBoards/board{channel}.png" + oldImage = await ctx.channel.send(file = discord.File(filePath)) + + with open(f"resources/games/oldImages/hex{channel}", "w") as f: + f.write(str(oldImage.id)) + + # Swap + async def swap(self, ctx): + channel = str(ctx.channel_id) + game = self.bot.database["hex games"].find_one({"_id":channel}) + user = f"#{ctx.author.id}" + + if game is None: + await ctx.send("You can't swap nothing") + elif user not in game["players"]: + await ctx.send("You're not in the game") + elif len(game["gameHistory"]) != 1: # Only after the first move + await ctx.send("You can only swap as the second player after the very first move.") + elif user != game["players"][game["turn"]-1]: + await ctx.send("You can only swap after your opponent has placed their piece") + else: + self.bot.database["hex games"].update_one({"_id":channel}, + {"$set":{"players":game["players"][::-1]}}) # Swaps their player-number + + # Swaps the color of the hexes on the board drawing: + self.draw.drawSwap(channel) + + opponent = game["players"][::-1][game["turn"]-1] + gwendoTurn = (opponent == f"#{self.bot.user.id}") + opponentName = self.bot.databaseFuncs.getName(opponent) + await ctx.send(f"The color of the players were swapped. It is now {opponentName}'s turn") + + with open(f"resources/games/oldImages/hex{channel}", "r") as f: + oldImage = await ctx.channel.fetch_message(int(f.read())) + + if oldImage is not None: + await oldImage.delete() + else: + self.bot.log("The old image was already deleted") + + self.bot.log("Sending the image") + filePath = f"resources/games/hexBoards/board{channel}.png" + oldImage = await ctx.channel.send(file = discord.File(filePath)) + + with open(f"resources/games/oldImages/hex{channel}", "w") as f: + f.write(str(oldImage.id)) + + if gwendoTurn: + await self.hexAI(ctx) # Starts the game - def hexStart(self, channel, user, opponent): + async def start(self, ctx, opponent): + try: + await ctx.defer() + except: + self.bot.log("Defer failed") + user = f"#{ctx.author.id}" + channel = str(ctx.channel_id) game = self.bot.database["hex games"].find_one({"_id":channel}) - if game == None: - if opponent in ["1","2","3","4","5"]: - difficulty = int(opponent) - diffText = " with difficulty "+opponent - opponent = "Gwendolyn" - elif opponent.lower() == "gwendolyn": - difficulty = 2 - diffText = " with difficulty 2" - opponent = "Gwendolyn" - else: - try: - int(opponent) - return "That difficulty doesn't exist", False, False, False, False - except: - opponent = self.bot.databaseFuncs.getID(opponent) - if opponent == None: - return "I can't find that user", False, False, False, False - else: - # Opponent is another player - difficulty = 3 - diffText = "" + startedGame = False + canStart = True + if game != None: + sendMessage = "There's already a hex game going on in this channel" + logMessage = "There was already a game going on" + canStart = False + else: + if type(opponent) == int: + # Opponent is Gwendolyn + if opponent in range(1, 6): + opponentName = "Gwendolyn" + difficulty = int(opponent) + diffText = f" with difficulty {difficulty}" + opponent = f"#{self.bot.user.id}" + else: + sendMessage = "Difficulty doesn't exist" + logMessage = "They tried to play against a difficulty that doesn't exist" + canStart = False + + elif type(opponent) == discord.member.Member: + if opponent.bot: + # User has challenged a bot + if opponent == self.bot.user: + # It was Gwendolyn + opponentName = "Gwendolyn" + difficulty = 2 + diffText = f" with difficulty {difficulty}" + opponent = f"#{self.bot.user.id}" + else: + sendMessage = "You can't challenge a bot!" + logMessage = "They tried to challenge a bot" + canStart = False + else: + # Opponent is another player + if ctx.author != opponent: + opponentName = opponent.display_name + opponent = f"#{opponent.id}" + difficulty = 5 + diffText = "" + else: + sendMessage = "You can't play against yourself" + logMessage = "They tried to play against themself" + canStart = False + else: + canStart = False + logMessage = f"Opponent was neither int or member. It was {type(opponent)}" + sendMessage = "Something went wrong" + + if canStart: # board is 11x11 - board = [ [ 0 for i in range(BOARDWIDTH) ] for j in range(BOARDWIDTH) ] - players = [user,opponent] + board = [[0 for i in range(BOARDWIDTH)] for j in range(BOARDWIDTH)] + players = [user, opponent] random.shuffle(players) # random starting player gameHistory = [] @@ -120,137 +165,196 @@ class HexGame(): # draw the board self.draw.drawBoard(channel) - gwendoTurn = True if players[0] == "Gwendolyn" else False - showImage = True - return "Started Hex game against "+self.bot.databaseFuncs.getName(opponent)+ diffText+". It's "+self.bot.databaseFuncs.getName(players[0])+"'s turn", showImage, False, False, gwendoTurn - else: - return "There's already a hex game going on in this channel", False, False, False, False + gwendoTurn = (players[0] == f"#{self.bot.user.id}") + startedGame = True + + turnName = self.bot.databaseFuncs.getName(players[0]) + sendMessage = f"Started Hex game against {opponentName}{diffText}. It's {turnName}'s turn" + logMessage = "Game started" + + await ctx.send(sendMessage) + self.bot.log(logMessage) + + if startedGame: + filePath = f"resources/games/hexBoards/board{ctx.channel_id}.png" + newImage = await ctx.channel.send(file = discord.File(filePath)) + + with open(f"resources/games/oldImages/hex{ctx.channel_id}", "w") as f: + f.write(str(newImage.id)) + + if gwendoTurn: + await self.hexAI(ctx) # Places a piece at the given location and checks things afterwards - def placeHex(self, channel : str,position : str, user): + async def placeHex(self, ctx, position : str, user): + channel = str(ctx.channel_id) game = self.bot.database["hex games"].find_one({"_id":channel}) + placedPiece = False - if game != None: - players = game["players"] - if user in players: - turn = game["turn"] - if players[0] == players[1]: - player = turn - else: - player = players.index(user)+1 - - if player == turn: - board = game["board"] - - self.bot.log("Placing a piece on the board with placeHex()") - # Places on board - board = self.placeOnHexBoard(board,player,position) - - if isinstance(board, list): - # If the move is valid: - self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"board":board}}) - turn = 1 if turn == 2 else 2 - self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"turn":turn}}) - - # Checking for a win - self.bot.log("Checking for win") - winner = self.evaluateBoard(game["board"])[1] - - if winner == 0: # Continue with the game. - gameWon = False - message = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+". It's now "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn."# The score is "+str(score) - - else: # Congratulations! - gameWon = True - self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":winner}}) - message = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+" and won!" - if game["players"][winner-1] != "Gwendolyn": - winAmount = game["difficulty"]*10 - message += " Adding "+str(winAmount)+" GwendoBucks to their account." - - self.bot.database["hex games"].update_one({"_id":channel}, - {"$push":{"gameHistory":(int(position[1])-1, ord(position[0])-97)}}) - - # Is it now Gwendolyn's turn? - gwendoTurn = False - if game["players"][turn-1] == "Gwendolyn": - self.bot.log("It's Gwendolyn's turn") - gwendoTurn = True - - # Update the board - self.draw.drawHexPlacement(channel,player,position) - - return message, True, True, gameWon, gwendoTurn - else: - # Invalid move. "board" is the error message - message = board - return message, False, False, False, False - else: - # Move out of turn - message = "It isn't your turn, it is "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn." - return message, False, False, False, False - else: - message = "You can't place when you're not in the game. The game's players are: "+self.bot.databaseFuncs.getName(game["players"][0])+" and "+self.bot.databaseFuncs.getName(game["players"][1])+"." - return message, False, False, False, False + if game == None: + sendMessage = "There's no game in this channel" + self.bot.log("There was no game going on") + elif not (position[0].isalpha() and position[1].isnumeric() and len(position) == 2): + sendMessage = "The position must be a letter followed by a number." + self.bot.log(f"The position was not valid, {position}") else: - return "There's no game in this channel", False, False, False, False + players = game["players"] + if user not in players: + sendMessage = f"You can't place when you're not in the game. The game's players are: {self.bot.databaseFuncs.getName(game['players'][0])} and {self.bot.databaseFuncs.getName(game['players'][1])}." + self.bot.log("They aren't in the game") + elif players[game["turn"]-1] != user: + sendMessage = "It's not your turn" + self.bot.log("It wasn't their turn") + else: + player = game["turn"] + turn = game["turn"] + board = game["board"] + + self.bot.log("Placing a piece on the board with placeHex()") + # Places on board + board = self.placeOnHexBoard(board,player,position) + + if board is None: + self.bot.log("It was an invalid position") + sendMessage = ("That's an invalid position. You must place your piece on an empty field.") + else: + # If the move is valid: + self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"board":board}}) + turn = (turn % 2) + 1 + self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"turn":turn}}) + + # Checking for a win + self.bot.log("Checking for win") + winner = self.evaluateBoard(game["board"])[1] + + if winner == 0: # Continue with the game. + gameWon = False + sendMessage = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+". It's now "+self.bot.databaseFuncs.getName(game["players"][turn-1])+"'s turn."# The score is "+str(score) + + else: # Congratulations! + gameWon = True + self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":winner}}) + sendMessage = self.bot.databaseFuncs.getName(game["players"][player-1])+" placed at "+position.upper()+" and won!" + if game["players"][winner-1] != f"#{self.bot.user.id}": + winAmount = game["difficulty"]*10 + sendMessage += " Adding "+str(winAmount)+" GwendoBucks to their account." + + self.bot.database["hex games"].update_one({"_id":channel}, + {"$push":{"gameHistory":(int(position[1])-1, ord(position[0])-97)}}) + + # Is it now Gwendolyn's turn? + gwendoTurn = False + if game["players"][turn-1] == f"#{self.bot.user.id}": + self.bot.log("It's Gwendolyn's turn") + gwendoTurn = True + + placedPiece = True + + if user == f"#{self.bot.user.id}": + await ctx.channel.send(sendMessage) + else: + await ctx.send(sendMessage) + + if placedPiece: + # Update the board + self.draw.drawHexPlacement(channel,player, position) + + with open(f"resources/games/oldImages/hex{channel}", "r") as f: + oldImage = await ctx.channel.fetch_message(int(f.read())) + + if oldImage is not None: + await oldImage.delete() + else: + self.bot.log("The old image was already deleted") + + self.bot.log("Sending the image") + filePath = f"resources/games/hexBoards/board{channel}.png" + oldImage = await ctx.channel.send(file = discord.File(filePath)) + + if gameWon: + self.bot.log("Dealing with the winning player") + game = self.bot.database["hex games"].find_one({"_id":channel}) + + winner = game["winner"] + if game["players"][winner-1] != f"#{self.bot.user.id}": + winnings = game["difficulty"]*10 + self.bot.money.addMoney(game["players"][winner-1].lower(),winnings) + else: + with open(f"resources/games/oldImages/hex{channel}", "w") as f: + f.write(str(oldImage.id)) + + if gwendoTurn: + await self.hexAI(ctx) # Returns a board where the placement has ocurred def placeOnHexBoard(self, board,player,position): # Translates the position position = position.lower() # Error handling - try: - column = ord(position[0]) - 97 # ord() translates from letter to number - row = int(position[1:]) - 1 - if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH): - self.bot.log("Position out of bounds (error code 1533)") - return "Error. That position is out of bounds." - except: - self.bot.log("Invalid position (error code 1531)") - return "Error. The position should be a letter followed by a number, e.g. \"e2\"." + column = ord(position[0]) - 97 # ord() translates from letter to number + row = int(position[1:]) - 1 + if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH): + self.bot.log("Position out of bounds") + return None # Place at the position if board[row][column] == 0: board[row][column] = player return board else: self.bot.log("Cannot place on existing piece (error code 1532)") - return "Error. You must place on an empty space." + return None # After your move, you have the option to undo get your turn back #TimeTravel - def undoHex(self, channel, user): + async def undo(self, ctx): + channel = str(ctx.channel_id) + user = f"#{ctx.author.id}" + undid = False + game = self.bot.database["hex games"].find_one({"_id":channel}) - if user in game["players"]: - if len(game["gameHistory"]): - turn = game["turn"] - # You can only undo after your turn, which is the opponent's turn. - if user == game["players"][(turn % 2)]: # If it's not your turn - self.bot.log("Undoing {}'s last move".format(self.bot.databaseFuncs.getName(user))) - - lastMove = game["gameHistory"].pop() - game["board"][lastMove[0]][lastMove[1]] = 0 - self.bot.database["hex games"].update_one({"_id":channel}, - {"$set":{"board":game["board"]}}) - self.bot.database["hex games"].update_one({"_id":channel}, - {"$set":{"turn":turn%2 + 1}}) - - # Update the board - self.draw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear - return "You undid your last move at {}".format(lastMove), True, True, False, False - else: - # Sassy - return "Nice try. You can't undo your opponent's move. ", False, False, False, False - else: - # Sassy - return "Really? You undo right at the start of the game?", False, False, False, False - + if user not in game["players"]: + sendMessage = "You're not a player in the game" + elif len(game["gameHistory"]) == 0: + sendMessage = "You can't undo nothing" + elif user != game["players"][(game["turn"] % 2)]: # If it's not your turn + sendMessage = "It's not your turn" else: - return "You're not a player in the game", False, False, False, False + turn = game["turn"] + self.bot.log("Undoing {}'s last move".format(self.bot.databaseFuncs.getName(user))) + + lastMove = game["gameHistory"].pop() + game["board"][lastMove[0]][lastMove[1]] = 0 + self.bot.database["hex games"].update_one({"_id":channel}, + {"$set":{"board":game["board"]}}) + self.bot.database["hex games"].update_one({"_id":channel}, + {"$set":{"turn":turn%2 + 1}}) + + # Update the board + self.draw.drawHexPlacement(channel,0,"abcdefghijk"[lastMove[1]]+str(lastMove[0]+1)) # The zero makes the hex disappear + sendMessage = f"You undid your last move at {lastMove}" + undid = True + + await ctx.send(sendMessage) + if undid: + with open(f"resources/games/oldImages/hex{channel}", "r") as f: + oldImage = await ctx.channel.fetch_message(int(f.read())) + + if oldImage is not None: + await oldImage.delete() + else: + self.bot.log("The old image was already deleted") + + self.bot.log("Sending the image") + filePath = f"resources/games/hexBoards/board{channel}.png" + oldImage = await ctx.channel.send(file = discord.File(filePath)) + + with open(f"resources/games/oldImages/hex{channel}", "w") as f: + f.write(str(oldImage.id)) # Plays as the AI - def hexAI(self, channel): + async def hexAI(self, ctx): + channel = str(ctx.channel_id) self.bot.log("Figuring out best move") game = self.bot.database["hex games"].find_one({"_id":channel}) board = game["board"] @@ -269,32 +373,10 @@ class HexGame(): moves.remove(move) chosenMove = random.choice(moves) - """ - GwenColor = data[channel]["players"].index("Gwendolyn") + 1 # either 1 or 2 - red or blue - if len(data[channel]["gameHistory"]) == 0: - return placeHex(channel,"F6", "Gwendolyn") # If starting, start in the middle - board = data[channel]["board"] - difficulty = data[channel]["difficulty"] - possiblePlaces = [i for i,v in enumerate(sum(board,[])) if v == 0] - judgements = [float('nan')]*len(possiblePlaces) # All possible moves are yet to be judged - - current_score = evaluateBoard(board)[0] - for i in possiblePlaces: - testBoard = copy.deepcopy(board) - testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = GwenColor - if evaluateBoard(testBoard)[0] != current_score: # only think about a move if it improves the score (it's impossible to get worse) - # Testing a move and evaluating it - judgements[i] = minimaxHex(testBoard,difficulty,-math.inf,math.inf,GwenColor==2) - self.bot.log("Best score for place {} is {}".format((i // BOARDWIDTH,i % BOARDWIDTH),judgements[i])) - - bestScore = max(judgements) if (GwenColor == 1) else min(judgements) # this line has an error - indices = [i for i, x in enumerate(judgements) if x == bestScore] # which moves got that score? - i = random.choice(indices) - chosenMove = (i // BOARDWIDTH , i % BOARDWIDTH) - """ placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1) - self.bot.log("ChosenMove is {} at {}".format(chosenMove,placement)) - return self.placeHex(channel,placement, "Gwendolyn") + self.bot.log(f"ChosenMove is {chosenMove} at {placement}") + + await self.placeHex(ctx, placement, f"#{self.bot.user.id}") def evaluateBoard(self, board): diff --git a/funcs/games/hexDraw.py b/funcs/games/hexDraw.py index 44a064c..8dcd7d0 100644 --- a/funcs/games/hexDraw.py +++ b/funcs/games/hexDraw.py @@ -122,7 +122,7 @@ class DrawHex(): def drawHexPlacement(self, channel,player,position): FILEPATH = "resources/games/hexBoards/board"+channel+".png" - self.bot.log("Drawing a newly placed hex. Filepath: "+FILEPATH) + self.bot.log(f"Drawing a newly placed hex. Filename: board{channel}.png") # Translates position # We don't need to error-check, because the position is already checked in placeOnHexBoard() diff --git a/utils/helperClasses.py b/utils/helperClasses.py index 3a95326..53894f3 100644 --- a/utils/helperClasses.py +++ b/utils/helperClasses.py @@ -53,10 +53,10 @@ class databaseFuncs(): def getName(self, userID): user = self.bot.database["users"].find_one({"_id":userID}) - if user != None: - return user["user name"] - elif userID == f"#{self.bot.user.id}": + if userID == f"#{self.bot.user.id}": return "Gwendolyn" + elif user != None: + return user["user name"] else: self.bot.log(f"Couldn't find user {userID}") return userID @@ -78,6 +78,7 @@ class databaseFuncs(): self.bot.database["blackjack games"].delete_many({}) self.bot.database["connect 4 games"].delete_many({}) self.bot.database["hangman games"].delete_many({}) + self.bot.database["hex games"].delete_many({}) if not self.bot.options.testing: g = git.cmd.Git("")