:Sparkles: Converted all hex functionality to slash commands

This commit is contained in:
NikolajDanger
2021-04-05 23:06:30 +02:00
parent aea2875957
commit d3936fa1a9
6 changed files with 321 additions and 307 deletions

View File

@ -115,37 +115,36 @@ class HexCog(commands.Cog):
def __init__(self,bot): def __init__(self,bot):
"""Runs game stuff.""" """Runs game stuff."""
self.bot = bot self.bot = bot
# Start a game of Hex against another user # Start a game of Hex against another user
@cog_ext.cog_subcommand(**params["hexStartUser"]) @cog_ext.cog_subcommand(**params["hexStartUser"])
async def hexStartUser(self, ctx, user): async def hexStartUser(self, ctx, user):
await ctx.defer() await self.bot.games.hex.start(ctx, user)
await self.bot.games.gameLoops.runHex(ctx, "start "+user.display_name, "#"+str(ctx.author.id))
# Start a game of Hex against Gwendolyn # Start a game of Hex against Gwendolyn
@cog_ext.cog_subcommand(**params["hexStartGwendolyn"]) @cog_ext.cog_subcommand(**params["hexStartGwendolyn"])
async def hexStartGwendolyn(self, ctx, difficulty = 2): async def hexStartGwendolyn(self, ctx, difficulty = 2):
await ctx.defer() await self.bot.games.hex.start(ctx, difficulty)
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))
# Place a piece in the hex game # Place a piece in the hex game
@cog_ext.cog_subcommand(**params["hexPlace"]) @cog_ext.cog_subcommand(**params["hexPlace"])
async def hexPlace(self, ctx, coordinates): 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): def setup(bot):

View File

@ -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))

View File

@ -2,7 +2,6 @@ from .invest import Invest
from .trivia import Trivia from .trivia import Trivia
from .blackjack import Blackjack from .blackjack import Blackjack
from .connectFour import ConnectFour from .connectFour import ConnectFour
from .gameLoops import GameLoops
from .hangman import Hangman from .hangman import Hangman
from .hex import HexGame from .hex import HexGame
@ -14,6 +13,5 @@ class Games():
self.trivia = Trivia(bot) self.trivia = Trivia(bot)
self.blackjack = Blackjack(bot) self.blackjack = Blackjack(bot)
self.connectFour = ConnectFour(bot) self.connectFour = ConnectFour(bot)
self.gameLoops = GameLoops(bot)
self.hangman = Hangman(bot) self.hangman = Hangman(bot)
self.hex = HexGame(bot) self.hex = HexGame(bot)

View File

@ -1,6 +1,7 @@
import random import random
import copy import copy
import math import math
import discord
from .hexDraw import DrawHex 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)] HEX_DIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)]
class HexGame(): class HexGame():
def __init__(self,bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.draw = DrawHex(bot) self.draw = DrawHex(bot)
# Parses command async def surrender(self, ctx):
def parseHex(self, command, channel, user): channel = str(ctx.channel_id)
commands = command.lower().split()
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
if command == "" or command == " ": user = f"#{ctx.author.id}"
return "I didn't get that. Use \"/hex start [opponent]\" to start a game.", False, False, False, False players = game["players"]
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
if user not in players:
await ctx.send("You can't surrender when you're not a player.")
else: 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 # 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}) game = self.bot.database["hex games"].find_one({"_id":channel})
if game == None: startedGame = False
if opponent in ["1","2","3","4","5"]: canStart = True
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 = ""
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 is 11x11
board = [ [ 0 for i in range(BOARDWIDTH) ] for j in range(BOARDWIDTH) ] board = [[0 for i in range(BOARDWIDTH)] for j in range(BOARDWIDTH)]
players = [user,opponent] players = [user, opponent]
random.shuffle(players) # random starting player random.shuffle(players) # random starting player
gameHistory = [] gameHistory = []
@ -120,137 +165,196 @@ class HexGame():
# draw the board # draw the board
self.draw.drawBoard(channel) self.draw.drawBoard(channel)
gwendoTurn = True if players[0] == "Gwendolyn" else False gwendoTurn = (players[0] == f"#{self.bot.user.id}")
showImage = True startedGame = 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: turnName = self.bot.databaseFuncs.getName(players[0])
return "There's already a hex game going on in this channel", False, False, False, False 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 # 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}) game = self.bot.database["hex games"].find_one({"_id":channel})
placedPiece = False
if game != None: if game == None:
players = game["players"] sendMessage = "There's no game in this channel"
if user in players: self.bot.log("There was no game going on")
turn = game["turn"] elif not (position[0].isalpha() and position[1].isnumeric() and len(position) == 2):
if players[0] == players[1]: sendMessage = "The position must be a letter followed by a number."
player = turn self.bot.log(f"The position was not valid, {position}")
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
else: 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 # Returns a board where the placement has ocurred
def placeOnHexBoard(self, board,player,position): def placeOnHexBoard(self, board,player,position):
# Translates the position # Translates the position
position = position.lower() position = position.lower()
# Error handling # Error handling
try: column = ord(position[0]) - 97 # ord() translates from letter to number
column = ord(position[0]) - 97 # ord() translates from letter to number row = int(position[1:]) - 1
row = int(position[1:]) - 1 if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH):
if column not in range(BOARDWIDTH) or row not in range(BOARDWIDTH): self.bot.log("Position out of bounds")
self.bot.log("Position out of bounds (error code 1533)") return None
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\"."
# Place at the position # Place at the position
if board[row][column] == 0: if board[row][column] == 0:
board[row][column] = player board[row][column] = player
return board return board
else: else:
self.bot.log("Cannot place on existing piece (error code 1532)") 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 # 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}) game = self.bot.database["hex games"].find_one({"_id":channel})
if user in game["players"]: if user not in game["players"]:
if len(game["gameHistory"]): sendMessage = "You're not a player in the game"
turn = game["turn"] elif len(game["gameHistory"]) == 0:
# You can only undo after your turn, which is the opponent's turn. sendMessage = "You can't undo nothing"
if user == game["players"][(turn % 2)]: # If it's not your turn elif user != game["players"][(game["turn"] % 2)]: # If it's not your turn
self.bot.log("Undoing {}'s last move".format(self.bot.databaseFuncs.getName(user))) sendMessage = "It's not your turn"
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
else: 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 # 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") self.bot.log("Figuring out best move")
game = self.bot.database["hex games"].find_one({"_id":channel}) game = self.bot.database["hex games"].find_one({"_id":channel})
board = game["board"] board = game["board"]
@ -269,32 +373,10 @@ class HexGame():
moves.remove(move) moves.remove(move)
chosenMove = random.choice(moves) 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) placement = "abcdefghijk"[chosenMove[1]]+str(chosenMove[0]+1)
self.bot.log("ChosenMove is {} at {}".format(chosenMove,placement)) self.bot.log(f"ChosenMove is {chosenMove} at {placement}")
return self.placeHex(channel,placement, "Gwendolyn")
await self.placeHex(ctx, placement, f"#{self.bot.user.id}")
def evaluateBoard(self, board): def evaluateBoard(self, board):

View File

@ -122,7 +122,7 @@ class DrawHex():
def drawHexPlacement(self, channel,player,position): def drawHexPlacement(self, channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png" 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 # Translates position
# We don't need to error-check, because the position is already checked in placeOnHexBoard() # We don't need to error-check, because the position is already checked in placeOnHexBoard()

View File

@ -53,10 +53,10 @@ class databaseFuncs():
def getName(self, userID): def getName(self, userID):
user = self.bot.database["users"].find_one({"_id":userID}) user = self.bot.database["users"].find_one({"_id":userID})
if user != None: if userID == f"#{self.bot.user.id}":
return user["user name"]
elif userID == f"#{self.bot.user.id}":
return "Gwendolyn" return "Gwendolyn"
elif user != None:
return user["user name"]
else: else:
self.bot.log(f"Couldn't find user {userID}") self.bot.log(f"Couldn't find user {userID}")
return userID return userID
@ -78,6 +78,7 @@ class databaseFuncs():
self.bot.database["blackjack games"].delete_many({}) self.bot.database["blackjack games"].delete_many({})
self.bot.database["connect 4 games"].delete_many({}) self.bot.database["connect 4 games"].delete_many({})
self.bot.database["hangman games"].delete_many({}) self.bot.database["hangman games"].delete_many({})
self.bot.database["hex games"].delete_many({})
if not self.bot.options.testing: if not self.bot.options.testing:
g = git.cmd.Git("") g = git.cmd.Git("")