🔀 Moved draw classes

Moved draw classes to the game files
This commit is contained in:
NikolajDanger
2021-04-13 18:49:25 +02:00
committed by GitHub
8 changed files with 791 additions and 799 deletions

View File

@ -3,11 +3,11 @@ import math
import datetime import datetime
import asyncio import asyncio
import discord import discord
from PIL import Image, ImageDraw, ImageFont
from shutil import copyfile from shutil import copyfile
from utils import replaceMultiple from utils import replaceMultiple
from .blackjackDraw import DrawBlackjack
class Blackjack(): class Blackjack():
def __init__(self,bot): def __init__(self,bot):
@ -795,7 +795,7 @@ class Blackjack():
else: else:
self.bot.log("Ending loop on round "+str(gameRound),str(channel.id)) self.bot.log("Ending loop on round "+str(gameRound),str(channel.id))
# Returning current hi-lo value # Returning current hi-lo value
async def hilo(self, ctx): async def hilo(self, ctx):
channel = ctx.channel_id channel = ctx.channel_id
data = self.bot.database["hilo"].find_one({"_id":str(channel)}) data = self.bot.database["hilo"].find_one({"_id":str(channel)})
@ -825,4 +825,142 @@ class Blackjack():
decksLeft = round(cardsLeft/52,1) decksLeft = round(cardsLeft/52,1)
await ctx.send(f"Cards left:\n{cardsLeft} cards, {decksLeft} decks", hidden=True) await ctx.send(f"Cards left:\n{cardsLeft} cards, {decksLeft} decks", hidden=True)
class DrawBlackjack():
def __init__(self,bot):
self.bot = bot
self.BORDER = 100
self.PLACEMENT = [0,0]
self.ROTATION = 0
def drawImage(self,channel):
self.bot.log("Drawing blackjack table",channel)
game = self.bot.database["blackjack games"].find_one({"_id":channel})
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 50)
fntSmol = ImageFont.truetype('resources/fonts/futura-bold.ttf', 40)
self.BORDERSmol = int(self.BORDER/3.5)
table = Image.open("resources/games/blackjackTable.png")
self.PLACEMENT = [2,1,3,0,4]
textImage = ImageDraw.Draw(table)
hands = game["user hands"]
dealerBusted = game["dealer busted"]
dealerBlackjack = game["dealer blackjack"]
try:
if game["all standing"] == False:
dealerHand = self.drawHand(game["dealer hand"],True,False,False)
else:
dealerHand = self.drawHand(game["dealer hand"],False,dealerBusted,dealerBlackjack)
except:
self.bot.log("Error drawing dealer hand (error code 1341a)")
table.paste(dealerHand,(800-self.BORDERSmol,20-self.BORDERSmol),dealerHand)
for x in range(len(hands)):
key, value = list(hands.items())[x]
key = self.bot.databaseFuncs.getName(key)
#self.bot.log("Drawing "+key+"'s hand")
userHand = self.drawHand(value["hand"],False,value["busted"],value["blackjack"])
try:
if value["split"] == 3:
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),280-self.BORDERSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),420-self.BORDERSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userThirdHand)
userFourthHand = self.drawHand(value["fourth hand"]["hand"],False,value["fourth hand"]["busted"],value["fourth hand"]["blackjack"])
table.paste(userFourthHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userFourthHand)
elif value["split"] == 2:
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),420-self.BORDERSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userThirdHand)
elif value["split"] == 1:
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),560-self.BORDERSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),700-self.BORDERSmol),userOtherHand)
else:
table.paste(userHand,(32-self.BORDERSmol+(384*self.PLACEMENT[x]),680-self.BORDERSmol),userHand)
except:
self.bot.log("Error drawing player hands (error code 1341b)")
textWidth = fnt.getsize(key)[0]
if textWidth < 360:
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2),1005),key,fill=(255,255,255), font=fnt)
else:
textWidth = fntSmol.getsize(key)[0]
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)-2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2)+2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*self.PLACEMENT[x])+117-int(textWidth/2),1015),key,fill=(255,255,255), font=fntSmol)
self.bot.log("Saving table image")
table.save("resources/games/blackjackTables/blackjackTable"+channel+".png")
return
def drawHand(self, hand, dealer, busted, blackjack):
self.bot.log("Drawing hand "+str(hand)+", "+str(busted)+", "+str(blackjack))
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 200)
fnt2 = ImageFont.truetype('resources/fonts/futura-bold.ttf', 120)
length = len(hand)
background = Image.new("RGBA", ((self.BORDER*2)+691+(125*(length-1)),(self.BORDER*2)+1065),(0,0,0,0))
textImage = ImageDraw.Draw(background)
if dealer:
img = Image.open("resources/games/cards/"+hand[0].upper()+".png")
#self.ROTATION = (random.randint(-20,20)/10.0)
img = img.rotate(self.ROTATION,expand = 1)
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(self.BORDER+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
img = Image.open("resources/games/cards/red_back.png")
#self.ROTATION = (random.randint(-20,20)/10.0)
img = img.rotate(self.ROTATION,expand = 1)
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(125+self.BORDER+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
else:
for x in range(length):
img = Image.open("resources/games/cards/"+hand[x].upper()+".png")
#self.ROTATION = (random.randint(-20,20)/10.0)
img = img.rotate(self.ROTATION,expand = 1)
#self.PLACEMENT = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(self.BORDER+(x*125)+self.PLACEMENT[0],self.BORDER+self.PLACEMENT[1]),img)
w, h = background.size
textHeight = 290+self.BORDER
#self.bot.log("Drawing busted/blackjack")
if busted:
textWidth = fnt.getsize("BUSTED")[0]
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight+5),"BUSTED",fill=(255,255,225), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight+5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BUSTED",fill=(255,50,50), font=fnt)
elif blackjack:
textWidth = fnt2.getsize("BLACKJACK")[0]
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BLACKJACK",fill=(155,123,0), font=fnt2)
#self.bot.log("Returning resized image")
return background.resize((int(w/3.5),int(h/3.5)),resample=Image.BILINEAR)

View File

@ -1,141 +0,0 @@
from PIL import Image, ImageDraw, ImageFont
border = 100
placement = [0,0]
rotation = 0
class DrawBlackjack():
def __init__(self,bot):
self.bot = bot
def drawImage(self,channel):
self.bot.log("Drawing blackjack table",channel)
game = self.bot.database["blackjack games"].find_one({"_id":channel})
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 50)
fntSmol = ImageFont.truetype('resources/fonts/futura-bold.ttf', 40)
borderSmol = int(border/3.5)
table = Image.open("resources/games/blackjackTable.png")
placement = [2,1,3,0,4]
textImage = ImageDraw.Draw(table)
hands = game["user hands"]
dealerBusted = game["dealer busted"]
dealerBlackjack = game["dealer blackjack"]
try:
if game["all standing"] == False:
dealerHand = self.drawHand(game["dealer hand"],True,False,False)
else:
dealerHand = self.drawHand(game["dealer hand"],False,dealerBusted,dealerBlackjack)
except:
self.bot.log("Error drawing dealer hand (error code 1341a)")
table.paste(dealerHand,(800-borderSmol,20-borderSmol),dealerHand)
for x in range(len(hands)):
key, value = list(hands.items())[x]
key = self.bot.databaseFuncs.getName(key)
#self.bot.log("Drawing "+key+"'s hand")
userHand = self.drawHand(value["hand"],False,value["busted"],value["blackjack"])
try:
if value["split"] == 3:
table.paste(userHand,(32-borderSmol+(384*placement[x]),280-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userThirdHand)
userFourthHand = self.drawHand(value["fourth hand"]["hand"],False,value["fourth hand"]["busted"],value["fourth hand"]["blackjack"])
table.paste(userFourthHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userFourthHand)
elif value["split"] == 2:
table.paste(userHand,(32-borderSmol+(384*placement[x]),420-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userOtherHand)
userThirdHand = self.drawHand(value["third hand"]["hand"],False,value["third hand"]["busted"],value["third hand"]["blackjack"])
table.paste(userThirdHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userThirdHand)
elif value["split"] == 1:
table.paste(userHand,(32-borderSmol+(384*placement[x]),560-borderSmol),userHand)
userOtherHand = self.drawHand(value["other hand"]["hand"],False,value["other hand"]["busted"],value["other hand"]["blackjack"])
table.paste(userOtherHand,(32-borderSmol+(384*placement[x]),700-borderSmol),userOtherHand)
else:
table.paste(userHand,(32-borderSmol+(384*placement[x]),680-borderSmol),userHand)
except:
self.bot.log("Error drawing player hands (error code 1341b)")
textWidth = fnt.getsize(key)[0]
if textWidth < 360:
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010-3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+3,1010+3),key,fill=(0,0,0), font=fnt)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1005),key,fill=(255,255,255), font=fnt)
else:
textWidth = fntSmol.getsize(key)[0]
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020-2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)-2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2)+2,1020+2),key,fill=(0,0,0), font=fntSmol)
textImage.text((32+(384*placement[x])+117-int(textWidth/2),1015),key,fill=(255,255,255), font=fntSmol)
self.bot.log("Saving table image")
table.save("resources/games/blackjackTables/blackjackTable"+channel+".png")
return
def drawHand(self, hand, dealer, busted, blackjack):
self.bot.log("Drawing hand "+str(hand)+", "+str(busted)+", "+str(blackjack))
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', 200)
fnt2 = ImageFont.truetype('resources/fonts/futura-bold.ttf', 120)
length = len(hand)
background = Image.new("RGBA", ((border*2)+691+(125*(length-1)),(border*2)+1065),(0,0,0,0))
textImage = ImageDraw.Draw(background)
if dealer:
img = Image.open("resources/games/cards/"+hand[0].upper()+".png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(border+placement[0],border+placement[1]),img)
img = Image.open("resources/games/cards/red_back.png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(125+border+placement[0],border+placement[1]),img)
else:
for x in range(length):
img = Image.open("resources/games/cards/"+hand[x].upper()+".png")
#rotation = (random.randint(-20,20)/10.0)
img = img.rotate(rotation,expand = 1)
#placement = [random.randint(-20,20),random.randint(-20,20)]
background.paste(img,(border+(x*125)+placement[0],border+placement[1]),img)
w, h = background.size
textHeight = 290+border
#self.bot.log("Drawing busted/blackjack")
if busted:
textWidth = fnt.getsize("BUSTED")[0]
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20-10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+10,textHeight+20+10),"BUSTED",fill=(0,0,0), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight-5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)-5,textHeight+5),"BUSTED",fill=(255,255,225), font=fnt)
textImage.text((int(w/2)-int(textWidth/2)+5,textHeight+5),"BUSTED",fill=(255,255,255), font=fnt)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BUSTED",fill=(255,50,50), font=fnt)
elif blackjack:
textWidth = fnt2.getsize("BLACKJACK")[0]
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20-6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+6,textHeight+20+6),"BLACKJACK",fill=(0,0,0), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight-3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)-3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2)+3,textHeight+3),"BLACKJACK",fill=(255,255,255), font=fnt2)
textImage.text((int(w/2)-int(textWidth/2),textHeight),"BLACKJACK",fill=(155,123,0), font=fnt2)
#self.bot.log("Returning resized image")
return background.resize((int(w/3.5),int(h/3.5)),resample=Image.BILINEAR)

View File

@ -3,26 +3,25 @@ import copy
import math import math
import discord import discord
from .connectFourDraw import drawConnectFour from PIL import Image, ImageDraw, ImageFont
AISCORES = {
"middle": 3,
"two in a row": 10,
"three in a row": 50,
"enemy two in a row": -35,
"enemy three in a row": -200,
"enemy win": -10000,
"win": 10000,
"avoid losing": 100
}
ROWCOUNT = 6
COLUMNCOUNT = 7
class ConnectFour(): class ConnectFour():
def __init__(self,bot): def __init__(self,bot):
self.bot = bot self.bot = bot
self.draw = drawConnectFour(bot) self.draw = drawConnectFour(bot)
self.AISCORES = {
"middle": 3,
"two in a row": 10,
"three in a row": 50,
"enemy two in a row": -35,
"enemy three in a row": -200,
"enemy win": -10000,
"win": 10000,
"avoid losing": 100
}
self.ROWCOUNT = 6
self.COLUMNCOUNT = 7
# Starts the game # Starts the game
async def start(self, ctx, opponent): async def start(self, ctx, opponent):
@ -74,7 +73,7 @@ class ConnectFour():
canStart = False canStart = False
if canStart: if canStart:
board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)] board = [[0 for _ in range(self.COLUMNCOUNT)] for _ in range(self.ROWCOUNT)]
players = [user, opponent] players = [user, opponent]
random.shuffle(players) random.shuffle(players)
@ -261,13 +260,13 @@ class ConnectFour():
winDirection = "" winDirection = ""
winCoordinates = [0,0] winCoordinates = [0,0]
for row in range(ROWCOUNT): for row in range(self.ROWCOUNT):
for place in range(COLUMNCOUNT): for place in range(self.COLUMNCOUNT):
if won == 0: if won == 0:
piecePlayer = board[row][place] piecePlayer = board[row][place]
if piecePlayer != 0: if piecePlayer != 0:
# Checks horizontal # Checks horizontal
if place <= COLUMNCOUNT-4: if place <= self.COLUMNCOUNT-4:
pieces = [board[row][place+1],board[row][place+2],board[row][place+3]] pieces = [board[row][place+1],board[row][place+2],board[row][place+3]]
else: else:
pieces = [0] pieces = [0]
@ -278,7 +277,7 @@ class ConnectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks vertical # Checks vertical
if row <= ROWCOUNT-4: if row <= self.ROWCOUNT-4:
pieces = [board[row+1][place],board[row+2][place],board[row+3][place]] pieces = [board[row+1][place],board[row+2][place],board[row+3][place]]
else: else:
pieces = [0] pieces = [0]
@ -289,7 +288,7 @@ class ConnectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks right diagonal # Checks right diagonal
if row <= ROWCOUNT-4 and place <= COLUMNCOUNT-4: if row <= self.ROWCOUNT-4 and place <= self.COLUMNCOUNT-4:
pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]] pieces = [board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
else: else:
pieces = [0] pieces = [0]
@ -300,7 +299,7 @@ class ConnectFour():
winCoordinates = [row,place] winCoordinates = [row,place]
# Checks left diagonal # Checks left diagonal
if row <= ROWCOUNT-4 and place >= 3: if row <= self.ROWCOUNT-4 and place >= 3:
pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]] pieces = [board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
else: else:
pieces = [0] pieces = [0]
@ -324,8 +323,8 @@ class ConnectFour():
player = game["players"].index(f"#{self.bot.user.id}")+1 player = game["players"].index(f"#{self.bot.user.id}")+1
difficulty = game["difficulty"] difficulty = game["difficulty"]
scores = [-math.inf for _ in range(COLUMNCOUNT)] scores = [-math.inf for _ in range(self.COLUMNCOUNT)]
for column in range(COLUMNCOUNT): for column in range(self.COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
@ -351,28 +350,28 @@ class ConnectFour():
# Adds points for middle placement # Adds points for middle placement
# Checks horizontal # Checks horizontal
for row in range(ROWCOUNT): for row in range(self.ROWCOUNT):
if board[row][3] == player: if board[row][3] == player:
score += AISCORES["middle"] score += self.AISCORES["middle"]
rowArray = [int(i) for i in list(board[row])] rowArray = [int(i) for i in list(board[row])]
for place in range(COLUMNCOUNT-3): for place in range(self.COLUMNCOUNT-3):
window = rowArray[place:place+4] window = rowArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
# Checks Vertical # Checks Vertical
for column in range(COLUMNCOUNT): for column in range(self.COLUMNCOUNT):
columnArray = [int(i[column]) for i in list(board)] columnArray = [int(i[column]) for i in list(board)]
for place in range(ROWCOUNT-3): for place in range(self.ROWCOUNT-3):
window = columnArray[place:place+4] window = columnArray[place:place+4]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
# Checks right diagonal # Checks right diagonal
for row in range(ROWCOUNT-3): for row in range(self.ROWCOUNT-3):
for place in range(COLUMNCOUNT-3): for place in range(self.COLUMNCOUNT-3):
window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]] window = [board[row][place],board[row+1][place+1],board[row+2][place+2],board[row+3][place+3]]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
for place in range(3,COLUMNCOUNT): for place in range(3,self.COLUMNCOUNT):
window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]] window = [board[row][place],board[row+1][place-1],board[row+2][place-2],board[row+3][place-3]]
score += self.evaluateWindow(window,player,otherPlayer) score += self.evaluateWindow(window,player,otherPlayer)
@ -382,19 +381,19 @@ class ConnectFour():
## Add points if AI wins ## Add points if AI wins
#if won == player: #if won == player:
# score += AISCORES["win"] # score += self.AISCORES["win"]
return score return score
def evaluateWindow(self, window,player,otherPlayer): def evaluateWindow(self, window,player,otherPlayer):
if window.count(player) == 4: if window.count(player) == 4:
return AISCORES["win"] return self.AISCORES["win"]
elif window.count(player) == 3 and window.count(0) == 1: elif window.count(player) == 3 and window.count(0) == 1:
return AISCORES["three in a row"] return self.AISCORES["three in a row"]
elif window.count(player) == 2 and window.count(0) == 2: elif window.count(player) == 2 and window.count(0) == 2:
return AISCORES["two in a row"] return self.AISCORES["two in a row"]
elif window.count(otherPlayer) == 4: elif window.count(otherPlayer) == 4:
return AISCORES["enemy win"] return self.AISCORES["enemy win"]
else: else:
return 0 return 0
@ -407,25 +406,178 @@ class ConnectFour():
return points return points
if maximizingPlayer: if maximizingPlayer:
value = -math.inf value = -math.inf
for column in range(0,COLUMNCOUNT): for column in range(0,self.COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False) evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,False)
if evaluation < -9000: evaluation += AISCORES["avoid losing"] if evaluation < -9000: evaluation += self.AISCORES["avoid losing"]
value = max(value,evaluation) value = max(value,evaluation)
alpha = max(alpha,evaluation) alpha = max(alpha,evaluation)
if beta <= alpha: break if beta <= alpha: break
return value return value
else: else:
value = math.inf value = math.inf
for column in range(0,COLUMNCOUNT): for column in range(0,self.COLUMNCOUNT):
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard = self.placeOnBoard(testBoard,player,column) testBoard = self.placeOnBoard(testBoard,player,column)
if testBoard != None: if testBoard != None:
evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True) evaluation = await self.minimax(testBoard,depth-1,player%2+1,originalPlayer,alpha,beta,True)
if evaluation < -9000: evaluation += AISCORES["avoid losing"] if evaluation < -9000: evaluation += self.AISCORES["avoid losing"]
value = min(value,evaluation) value = min(value,evaluation)
beta = min(beta,evaluation) beta = min(beta,evaluation)
if beta <= alpha: break if beta <= alpha: break
return value return value
class drawConnectFour():
def __init__(self, bot):
self.bot = bot
# Draws the whole thing
def drawImage(self, channel):
self.bot.log("Drawing connect four board")
game = self.bot.database["connect 4 games"].find_one({"_id":channel})
board = game["board"]
border = 40
gridBorder = 40
cornerSize = 300
boardOutlineSize = 10
pieceOutlineSize = 10
emptyOutlineSize = 0
bottomBorder = 110
exampleCircles = 100
w, h = 2800,2400
backgroundColor = (230,230,234,255)
boardOutlineColor = (0,0,0)
pieceOutlineColor = (244,244,248)
emptyOutlineColor = (0,0,0)
player1Color = (254,74,73)
player2Color = (254,215,102)
boardColor = (42,183,202)
placeSize = 300
white = (255,255,255,160)
winBarColor = (250,250,250,255)
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', exampleCircles)
boardSize = [w-(2*(border+gridBorder)),h-(2*(border+gridBorder))]
placeGridSize = [math.floor(boardSize[0]/7),math.floor(boardSize[1]/6)]
pieceStartx = (border+gridBorder)+math.floor(placeGridSize[0]/2)-math.floor(placeSize/2)
pieceStarty = (border+gridBorder)+math.floor(placeGridSize[1]/2)-math.floor(placeSize/2)
if game["players"][0] == "Gwendolyn":
player1 = "Gwendolyn"
else:
player1 = self.bot.databaseFuncs.getName(game["players"][0])
if game["players"][1] == "Gwendolyn":
player2 = "Gwendolyn"
else:
player2 = self.bot.databaseFuncs.getName(game["players"][1])
background = Image.new("RGB", (w,h+bottomBorder),backgroundColor)
d = ImageDraw.Draw(background,"RGBA")
# This whole part was the easiest way to make a rectangle with rounded corners and an outline
# - Corners:
d.ellipse([(border,border),(border+cornerSize,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Rectangle:
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Removing outline on the inside:
d.rectangle([(border+math.floor(cornerSize/2),border+math.floor(cornerSize/2)),(w-(border+math.floor(cornerSize/2)),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
d.rectangle([(border+math.floor(cornerSize/2),border+boardOutlineSize),(w-(border+math.floor(cornerSize/2)),h-(border+boardOutlineSize))],fill=boardColor)
d.rectangle([(border+boardOutlineSize,border+math.floor(cornerSize/2)),(w-(border+boardOutlineSize),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
for x, line in enumerate(board):
for y, piece in enumerate(line):
if piece == 1:
pieceColor = player1Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
elif piece == 2:
pieceColor = player2Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
else:
pieceColor = backgroundColor
outlineWidth = emptyOutlineSize
outlineColor = emptyOutlineColor
startx = pieceStartx + placeGridSize[0]*y
starty = pieceStarty + placeGridSize[1]*x
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=outlineColor,width=outlineWidth)
if game["winner"] != 0:
coordinates = game["win coordinates"]
startx = border + placeGridSize[0]*coordinates[1] + gridBorder
starty = border + placeGridSize[1]*coordinates[0] + gridBorder
a = (placeGridSize[0]*4-gridBorder-border)**2
b = (placeGridSize[1]*4-gridBorder-border)**2
diagonalLength = (math.sqrt(a+b))/placeGridSize[0]
diagonalAngle = math.degrees(math.atan(placeGridSize[1]/placeGridSize[0]))
if game["win direction"] == "h":
winBar = Image.new("RGBA",(placeGridSize[0]*4,placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*3),0),(placeGridSize[0]*4,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*3.5),placeGridSize[1])],fill=white)
elif game["win direction"] == "v":
winBar = Image.new("RGBA",(placeGridSize[0],placeGridSize[1]*4),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([(0,(placeGridSize[1]*3)),(placeGridSize[0],placeGridSize[1]*4)],fill=white)
winD.rectangle([0,(int(placeGridSize[1]*0.5)),(placeGridSize[0],int(placeGridSize[1]*3.5))],fill=white)
elif game["win direction"] == "r":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(-diagonalAngle,expand=1)
startx -= 90
starty -= 100
elif game["win direction"] == "l":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(diagonalAngle,expand=1)
startx -= placeGridSize[0]*3 + 90
starty -= gridBorder + 60
mask = winBar.copy()#.convert("L")
#mask.putalpha(128)
#mask.save("test.png")
winBarImage = Image.new("RGBA",mask.size,color=winBarColor)
background.paste(winBarImage,(startx,starty),mask)
# Bottom
textPadding = 20
exampleHeight = h - border + int((bottomBorder+border)/2) - int(exampleCircles/2)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=player1Color,outline=boardOutlineColor,width=3)
d.text((border+exampleCircles+textPadding,exampleHeight),player1,font=fnt,fill=(0,0,0))
textWidth = fnt.getsize(player2)[0]
d.ellipse([(w-border-exampleCircles-textWidth-textPadding,exampleHeight),(w-border-textWidth-textPadding),(exampleHeight+exampleCircles)],fill=player2Color,outline=boardOutlineColor,width=3)
d.text((w-border-textWidth,exampleHeight),player2,font=fnt,fill=(0,0,0))
background.save("resources/games/connect4Boards/board"+channel+".png")

View File

@ -1,155 +0,0 @@
import math
from PIL import Image, ImageDraw, ImageFont
class drawConnectFour():
def __init__(self, bot):
self.bot = bot
# Draws the whole thing
def drawImage(self, channel):
self.bot.log("Drawing connect four board")
game = self.bot.database["connect 4 games"].find_one({"_id":channel})
board = game["board"]
border = 40
gridBorder = 40
cornerSize = 300
boardOutlineSize = 10
pieceOutlineSize = 10
emptyOutlineSize = 0
bottomBorder = 110
exampleCircles = 100
w, h = 2800,2400
backgroundColor = (230,230,234,255)
boardOutlineColor = (0,0,0)
pieceOutlineColor = (244,244,248)
emptyOutlineColor = (0,0,0)
player1Color = (254,74,73)
player2Color = (254,215,102)
boardColor = (42,183,202)
placeSize = 300
white = (255,255,255,160)
winBarColor = (250,250,250,255)
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', exampleCircles)
boardSize = [w-(2*(border+gridBorder)),h-(2*(border+gridBorder))]
placeGridSize = [math.floor(boardSize[0]/7),math.floor(boardSize[1]/6)]
pieceStartx = (border+gridBorder)+math.floor(placeGridSize[0]/2)-math.floor(placeSize/2)
pieceStarty = (border+gridBorder)+math.floor(placeGridSize[1]/2)-math.floor(placeSize/2)
if game["players"][0] == "Gwendolyn":
player1 = "Gwendolyn"
else:
player1 = self.bot.databaseFuncs.getName(game["players"][0])
if game["players"][1] == "Gwendolyn":
player2 = "Gwendolyn"
else:
player2 = self.bot.databaseFuncs.getName(game["players"][1])
background = Image.new("RGB", (w,h+bottomBorder),backgroundColor)
d = ImageDraw.Draw(background,"RGBA")
# This whole part was the easiest way to make a rectangle with rounded corners and an outline
# - Corners:
d.ellipse([(border,border),(border+cornerSize,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),h-(border+cornerSize)),(w-border,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(border,h-(border+cornerSize)),(border+cornerSize,h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.ellipse([(w-(border+cornerSize),border),(w-border,border+cornerSize)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Rectangle:
d.rectangle([(border+math.floor(cornerSize/2),border),(w-(border+math.floor(cornerSize/2)),h-border)],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
d.rectangle([(border,border+math.floor(cornerSize/2)),(w-border,h-(border+math.floor(cornerSize/2)))],fill=boardColor,outline=boardOutlineColor,width=boardOutlineSize)
# - Removing outline on the inside:
d.rectangle([(border+math.floor(cornerSize/2),border+math.floor(cornerSize/2)),(w-(border+math.floor(cornerSize/2)),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
d.rectangle([(border+math.floor(cornerSize/2),border+boardOutlineSize),(w-(border+math.floor(cornerSize/2)),h-(border+boardOutlineSize))],fill=boardColor)
d.rectangle([(border+boardOutlineSize,border+math.floor(cornerSize/2)),(w-(border+boardOutlineSize),h-(border+math.floor(cornerSize/2)))],fill=boardColor)
for x, line in enumerate(board):
for y, piece in enumerate(line):
if piece == 1:
pieceColor = player1Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
elif piece == 2:
pieceColor = player2Color
outlineWidth = pieceOutlineSize
outlineColor = pieceOutlineColor
else:
pieceColor = backgroundColor
outlineWidth = emptyOutlineSize
outlineColor = emptyOutlineColor
startx = pieceStartx + placeGridSize[0]*y
starty = pieceStarty + placeGridSize[1]*x
d.ellipse([(startx,starty),(startx+placeSize,starty+placeSize)],fill=pieceColor,outline=outlineColor,width=outlineWidth)
if game["winner"] != 0:
coordinates = game["win coordinates"]
startx = border + placeGridSize[0]*coordinates[1] + gridBorder
starty = border + placeGridSize[1]*coordinates[0] + gridBorder
a = (placeGridSize[0]*4-gridBorder-border)**2
b = (placeGridSize[1]*4-gridBorder-border)**2
diagonalLength = (math.sqrt(a+b))/placeGridSize[0]
diagonalAngle = math.degrees(math.atan(placeGridSize[1]/placeGridSize[0]))
if game["win direction"] == "h":
winBar = Image.new("RGBA",(placeGridSize[0]*4,placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*3),0),(placeGridSize[0]*4,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*3.5),placeGridSize[1])],fill=white)
elif game["win direction"] == "v":
winBar = Image.new("RGBA",(placeGridSize[0],placeGridSize[1]*4),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([(0,(placeGridSize[1]*3)),(placeGridSize[0],placeGridSize[1]*4)],fill=white)
winD.rectangle([0,(int(placeGridSize[1]*0.5)),(placeGridSize[0],int(placeGridSize[1]*3.5))],fill=white)
elif game["win direction"] == "r":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(-diagonalAngle,expand=1)
startx -= 90
starty -= 100
elif game["win direction"] == "l":
winBar = Image.new("RGBA",(int(placeGridSize[0]*diagonalLength),placeGridSize[1]),(0,0,0,0))
winD = ImageDraw.Draw(winBar)
winD.ellipse([(0,0),(placeGridSize[0],placeGridSize[1])],fill=white)
winD.ellipse([((placeGridSize[0]*(diagonalLength-1)),0),(placeGridSize[0]*diagonalLength,placeGridSize[1])],fill=white)
winD.rectangle([(int(placeGridSize[0]*0.5),0),(int(placeGridSize[0]*(diagonalLength-0.5)),placeGridSize[1])],fill=white)
winBar = winBar.rotate(diagonalAngle,expand=1)
startx -= placeGridSize[0]*3 + 90
starty -= gridBorder + 60
mask = winBar.copy()#.convert("L")
#mask.putalpha(128)
#mask.save("test.png")
winBarImage = Image.new("RGBA",mask.size,color=winBarColor)
background.paste(winBarImage,(startx,starty),mask)
# Bottom
textPadding = 20
exampleHeight = h - border + int((bottomBorder+border)/2) - int(exampleCircles/2)
d.ellipse([(border,exampleHeight),(border+exampleCircles),(exampleHeight+exampleCircles)],fill=player1Color,outline=boardOutlineColor,width=3)
d.text((border+exampleCircles+textPadding,exampleHeight),player1,font=fnt,fill=(0,0,0))
textWidth = fnt.getsize(player2)[0]
d.ellipse([(w-border-exampleCircles-textWidth-textPadding,exampleHeight),(w-border-textWidth-textPadding),(exampleHeight+exampleCircles)],fill=player2Color,outline=boardOutlineColor,width=3)
d.text((w-border-textWidth,exampleHeight),player2,font=fnt,fill=(0,0,0))
background.save("resources/games/connect4Boards/board"+channel+".png")

View File

@ -1,13 +1,13 @@
import json, urllib, datetime, string, discord import json, urllib, datetime, string, discord
import math, random
from .hangmanDraw import DrawHangman from PIL import ImageDraw, Image, ImageFont
apiUrl = "https://api.wordnik.com/v4/words.json/randomWords?hasDictionaryDef=true&minCorpusCount=5000&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=3&maxLength=11&limit=1&api_key="
class Hangman(): class Hangman():
def __init__(self,bot): def __init__(self,bot):
self.bot = bot self.bot = bot
self.draw = DrawHangman(bot) self.draw = DrawHangman(bot)
self.APIURL = "https://api.wordnik.com/v4/words.json/randomWords?hasDictionaryDef=true&minCorpusCount=5000&maxCorpusCount=-1&minDictionaryCount=1&maxDictionaryCount=-1&minLength=3&maxLength=11&limit=1&api_key="
async def start(self, ctx): async def start(self, ctx):
await self.bot.defer(ctx) await self.bot.defer(ctx)
@ -21,7 +21,7 @@ class Hangman():
apiKey = self.bot.credentials.wordnikKey apiKey = self.bot.credentials.wordnikKey
word = "-" word = "-"
while "-" in word or "." in word: while "-" in word or "." in word:
with urllib.request.urlopen(apiUrl+apiKey) as p: with urllib.request.urlopen(self.APIURL+apiKey) as p:
word = list(json.load(p)[0]["word"].upper()) word = list(json.load(p)[0]["word"].upper())
self.bot.log("Found the word \""+"".join(word)+"\"") self.bot.log("Found the word \""+"".join(word)+"\"")
guessed = [False] * len(word) guessed = [False] * len(word)
@ -162,4 +162,246 @@ class Hangman():
emoji = chr(ord(letter)+127397) emoji = chr(ord(letter)+127397)
await message.add_reaction(emoji) await message.add_reaction(emoji)
class DrawHangman():
def __init__(self,bot):
self.bot = bot
self.CIRCLESIZE = 120
self.LINEWIDTH = 12
self.BODYSIZE =210
self.LIMBSIZE = 60
self.ARMPOSITION = 60
self.MANX = (self.LIMBSIZE*2)+self.LINEWIDTH*4
self.MANY = (self.CIRCLESIZE+self.BODYSIZE+self.LIMBSIZE)+self.LINEWIDTH*4
self.LETTERLINELENGTH = 90
self.LETTERLINEDISTANCE = 30
self.GALLOWX, self.GALLOWY = 360,600
self.GOLDENRATIO = 1-(1 / ((1 + 5 ** 0.5) / 2))
LETTERSIZE = 75
TEXTSIZE = 70
self.FONT = ImageFont.truetype('resources/fonts/comic-sans-bold.ttf', LETTERSIZE)
self.SMALLFONT = ImageFont.truetype('resources/fonts/comic-sans-bold.ttf', TEXTSIZE)
def calcDeviance(self,preDev,preDevAcc,posChange,maxmin,maxAcceleration):
devAcc = preDevAcc + random.uniform(-posChange,posChange)
if devAcc > maxmin * maxAcceleration: devAcc = maxmin * maxAcceleration
elif devAcc < -maxmin * maxAcceleration: devAcc = -maxmin * maxAcceleration
dev = preDev + devAcc
if dev > maxmin: dev = maxmin
elif dev < -maxmin: dev = -maxmin
return dev, devAcc
def badCircle(self):
background = Image.new("RGBA",(self.CIRCLESIZE+(self.LINEWIDTH*3),self.CIRCLESIZE+(self.LINEWIDTH*3)),color=(0,0,0,0))
d = ImageDraw.Draw(background,"RGBA")
middle = (self.CIRCLESIZE+(self.LINEWIDTH*3))/2
devx = 0
devy = 0
devAccx = 0
devAccy = 0
start = random.randint(-100,-80)
degreesAmount = 360 + random.randint(-10,30)
for degree in range(degreesAmount):
devx, devAccx = self.calcDeviance(devx,devAccx,self.LINEWIDTH/100,self.LINEWIDTH,0.03)
devy, devAccy = self.calcDeviance(devy,devAccy,self.LINEWIDTH/100,self.LINEWIDTH,0.03)
x = middle + (math.cos(math.radians(degree+start)) * (self.CIRCLESIZE/2)) - (self.LINEWIDTH/2) + devx
y = middle + (math.sin(math.radians(degree+start)) * (self.CIRCLESIZE/2)) - (self.LINEWIDTH/2) + devy
d.ellipse([(x,y),(x+self.LINEWIDTH,y+self.LINEWIDTH)],fill=(0,0,0,255))
return background
def badLine(self, length, rotated = False):
if rotated:
w, h = length+self.LINEWIDTH*3, self.LINEWIDTH*3
else:
w, h = self.LINEWIDTH*3,length+self.LINEWIDTH*3
background = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(background,"RGBA")
devx = random.randint(-int(self.LINEWIDTH/3),int(self.LINEWIDTH/3))
devy = 0
devAccx = 0
devAccy = 0
for pixel in range(length):
devx, devAccx = self.calcDeviance(devx,devAccx,self.LINEWIDTH/1000,self.LINEWIDTH,0.004)
devy, devAccy = self.calcDeviance(devy,devAccy,self.LINEWIDTH/1000,self.LINEWIDTH,0.004)
if rotated:
x = self.LINEWIDTH + pixel + devx
y = self.LINEWIDTH + devy
else:
x = self.LINEWIDTH + devx
y = self.LINEWIDTH + pixel + devy
d.ellipse([(x,y),(x+self.LINEWIDTH,y+self.LINEWIDTH)],fill=(0,0,0,255))
return background
def drawMan(self, misses):
background = Image.new("RGBA",(self.MANX,self.MANY),color=(0,0,0,0))
if misses >= 1:
head = self.badCircle()
background.paste(head,(int((self.MANX-(self.CIRCLESIZE+(self.LINEWIDTH*3)))/2),0),head)
if misses >= 2:
body = self.badLine(self.BODYSIZE)
background.paste(body,(int((self.MANX-(self.LINEWIDTH*3))/2),self.CIRCLESIZE),body)
if misses >= 3:
limbs = random.sample(["rl","ll","ra","la"],min(misses-2,4))
else: limbs = []
for limb in limbs:
if limb == "ra":
limbDrawing = self.badLine(self.LIMBSIZE,True)
rotation = random.randint(-45,45)
xpos = int((self.MANX-(self.LINEWIDTH*3))/2)
rotationCompensation = min(-int(math.sin(math.radians(rotation))*(self.LIMBSIZE+(self.LINEWIDTH*3))),0)
ypos = self.CIRCLESIZE+self.ARMPOSITION + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "la":
limbDrawing = self.badLine(self.LIMBSIZE,True)
rotation = random.randint(-45,45)
xpos = int((self.MANX-(self.LINEWIDTH*3))/2)-self.LIMBSIZE
rotationCompensation = min(int(math.sin(math.radians(rotation))*(self.LIMBSIZE+(self.LINEWIDTH*3))),0)
ypos = self.CIRCLESIZE+self.ARMPOSITION + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "rl":
limbDrawing = self.badLine(self.LIMBSIZE,True)
rotation = random.randint(-15,15)
xpos = int((self.MANX-(self.LINEWIDTH*3))/2)-self.LINEWIDTH
ypos = self.CIRCLESIZE+self.BODYSIZE-self.LINEWIDTH
limbDrawing = limbDrawing.rotate(rotation-45,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "ll":
limbDrawing = self.badLine(self.LIMBSIZE,True)
rotation = random.randint(-15,15)
limbDrawing = limbDrawing.rotate(rotation+45,expand=1)
xpos = int((self.MANX-(self.LINEWIDTH*3))/2)-limbDrawing.size[0]+self.LINEWIDTH*3
ypos = self.CIRCLESIZE+self.BODYSIZE
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
return background
def badText(self, text, big, color=(0,0,0,255)):
if big: font = self.FONT
else: font = self.SMALLFONT
w, h = font.getsize(text)
img = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(img,"RGBA")
d.text((0,0),text,font=font,fill=color)
return img
def drawGallows(self):
background = Image.new("RGBA",(self.GALLOWX,self.GALLOWY),color=(0,0,0,0))
bottomLine = self.badLine(int(self.GALLOWX*0.75),True)
background.paste(bottomLine,(int(self.GALLOWX*0.125),self.GALLOWY-(self.LINEWIDTH*4)),bottomLine)
lineTwo = self.badLine(self.GALLOWY-self.LINEWIDTH*6)
background.paste(lineTwo,(int(self.GALLOWX*(0.75*self.GOLDENRATIO)),self.LINEWIDTH*2),lineTwo)
topLine = self.badLine(int(self.GALLOWY*0.30),True)
background.paste(topLine,(int(self.GALLOWX*(0.75*self.GOLDENRATIO))-self.LINEWIDTH,self.LINEWIDTH*3),topLine)
lastLine = self.badLine(int(self.GALLOWY*0.125))
background.paste(lastLine,((int(self.GALLOWX*(0.75*self.GOLDENRATIO))+int(self.GALLOWY*0.30)-self.LINEWIDTH),self.LINEWIDTH*3),lastLine)
return background
def drawLetterLines(self, word,guessed,misses):
letterLines = Image.new("RGBA",((self.LETTERLINELENGTH+self.LETTERLINEDISTANCE)*len(word),self.LETTERLINELENGTH+self.LINEWIDTH*3),color=(0,0,0,0))
for x, letter in enumerate(word):
line = self.badLine(self.LETTERLINELENGTH,True)
letterLines.paste(line,(x*(self.LETTERLINELENGTH+self.LETTERLINEDISTANCE),self.LETTERLINELENGTH),line)
if guessed[x]:
letterDrawing = self.badText(letter,True)
letterWidth = self.FONT.getsize(letter)[0]
letterx = int(x*(self.LETTERLINELENGTH+self.LETTERLINEDISTANCE)-(letterWidth/2)+(self.LETTERLINELENGTH*0.5)+(self.LINEWIDTH*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
elif misses == 6:
letterDrawing = self.badText(letter,True,(242,66,54))
letterWidth = self.FONT.getsize(letter)[0]
letterx = int(x*(self.LETTERLINELENGTH+self.LETTERLINEDISTANCE)-(letterWidth/2)+(self.LETTERLINELENGTH*0.5)+(self.LINEWIDTH*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
return letterLines
def shortestDist(self,positions,newPosition):
shortestDist = math.inf
x, y = newPosition
for i, j in positions:
xdist = abs(i-x)
ydist = abs(j-y)
dist = math.sqrt(xdist**2+ydist**2)
if shortestDist > dist: shortestDist = dist
return shortestDist
def drawMisses(self,guesses,word):
background = Image.new("RGBA",(600,400),color=(0,0,0,0))
pos = []
for guess in guesses:
if guess not in word:
placed = False
while placed == False:
letter = self.badText(guess,True)
w, h = self.FONT.getsize(guess)
x = random.randint(0,600-w)
y = random.randint(0,400-h)
if self.shortestDist(pos,(x,y)) > 70:
pos.append((x,y))
background.paste(letter,(x,y),letter)
placed = True
return background
def drawImage(self,channel):
self.bot.log("Drawing hangman image", channel)
game = self.bot.database["hangman games"].find_one({"_id":channel})
random.seed(game["game ID"])
background = Image.open("resources/paper.jpg")
try:
gallow = self.drawGallows()
except:
self.bot.log("Error drawing gallows (error code 1711)")
try:
man = self.drawMan(game["misses"])
except:
self.bot.log("Error drawing stick figure (error code 1712)")
random.seed(game["game ID"])
try:
letterLines = self.drawLetterLines(game["word"],game["guessed"],game["misses"])
except:
self.bot.log("error drawing letter lines (error code 1713)")
random.seed(game["game ID"])
try:
misses = self.drawMisses(game["guessed letters"],game["word"])
except:
self.bot.log("Error drawing misses (error code 1714)")
background.paste(gallow,(100,100),gallow)
background.paste(man,(300,210),man)
background.paste(letterLines,(120,840),letterLines)
background.paste(misses,(600,150),misses)
missesText = self.badText("MISSES",False)
missesTextWidth = missesText.size[0]
background.paste(missesText,(850-int(missesTextWidth/2),50),missesText)
background.save("resources/games/hangmanBoards/hangmanBoard"+channel+".png")

View File

@ -1,252 +0,0 @@
import math, random
from PIL import ImageDraw, Image, ImageFont
circleDegrees = 360
circleSize = 120
lineWidth = 12
bodySize =210
limbSize = 60
armPosition = 60
manx = (limbSize*2)+lineWidth*4
many = (circleSize+bodySize+limbSize)+lineWidth*4
letterSize = 75
textSize = 70
letterLineLength = 90
letterLineDistance = 30
gallowx, gallowy = 360,600
goldenRatio = 1-(1 / ((1 + 5 ** 0.5) / 2))
fnt = ImageFont.truetype('resources/fonts/comic-sans-bold.ttf', letterSize)
smolfnt = ImageFont.truetype('resources/fonts/comic-sans-bold.ttf', textSize)
backgroundColor = (255,255,255,255)
class DrawHangman():
def __init__(self,bot):
self.bot = bot
def calcDeviance(self,preDev,preDevAcc,posChange,maxmin,maxAcceleration):
devAcc = preDevAcc + random.uniform(-posChange,posChange)
if devAcc > maxmin * maxAcceleration: devAcc = maxmin * maxAcceleration
elif devAcc < -maxmin * maxAcceleration: devAcc = -maxmin * maxAcceleration
dev = preDev + devAcc
if dev > maxmin: dev = maxmin
elif dev < -maxmin: dev = -maxmin
return dev, devAcc
def badCircle(self):
background = Image.new("RGBA",(circleSize+(lineWidth*3),circleSize+(lineWidth*3)),color=(0,0,0,0))
d = ImageDraw.Draw(background,"RGBA")
middle = (circleSize+(lineWidth*3))/2
devx = 0
devy = 0
devAccx = 0
devAccy = 0
start = random.randint(-100,-80)
degreesAmount = circleDegrees + random.randint(-10,30)
for degree in range(degreesAmount):
devx, devAccx = self.calcDeviance(devx,devAccx,lineWidth/100,lineWidth,0.03)
devy, devAccy = self.calcDeviance(devy,devAccy,lineWidth/100,lineWidth,0.03)
x = middle + (math.cos(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devx
y = middle + (math.sin(math.radians(degree+start)) * (circleSize/2)) - (lineWidth/2) + devy
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
return background
def badLine(self, length, rotated = False):
if rotated:
w, h = length+lineWidth*3, lineWidth*3
else:
w, h = lineWidth*3,length+lineWidth*3
background = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(background,"RGBA")
devx = random.randint(-int(lineWidth/3),int(lineWidth/3))
devy = 0
devAccx = 0
devAccy = 0
for pixel in range(length):
devx, devAccx = self.calcDeviance(devx,devAccx,lineWidth/1000,lineWidth,0.004)
devy, devAccy = self.calcDeviance(devy,devAccy,lineWidth/1000,lineWidth,0.004)
if rotated:
x = lineWidth + pixel + devx
y = lineWidth + devy
else:
x = lineWidth + devx
y = lineWidth + pixel + devy
d.ellipse([(x,y),(x+lineWidth,y+lineWidth)],fill=(0,0,0,255))
return background
def drawMan(self, misses):
background = Image.new("RGBA",(manx,many),color=(0,0,0,0))
if misses >= 1:
head = self.badCircle()
background.paste(head,(int((manx-(circleSize+(lineWidth*3)))/2),0),head)
if misses >= 2:
body = self.badLine(bodySize)
background.paste(body,(int((manx-(lineWidth*3))/2),circleSize),body)
if misses >= 3:
limbs = random.sample(["rl","ll","ra","la"],min(misses-2,4))
else: limbs = []
for limb in limbs:
if limb == "ra":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)
rotationCompensation = min(-int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "la":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-45,45)
xpos = int((manx-(lineWidth*3))/2)-limbSize
rotationCompensation = min(int(math.sin(math.radians(rotation))*(limbSize+(lineWidth*3))),0)
ypos = circleSize+armPosition + rotationCompensation
limbDrawing = limbDrawing.rotate(rotation,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "rl":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-15,15)
xpos = int((manx-(lineWidth*3))/2)-lineWidth
ypos = circleSize+bodySize-lineWidth
limbDrawing = limbDrawing.rotate(rotation-45,expand=1)
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
elif limb == "ll":
limbDrawing = self.badLine(limbSize,True)
rotation = random.randint(-15,15)
limbDrawing = limbDrawing.rotate(rotation+45,expand=1)
xpos = int((manx-(lineWidth*3))/2)-limbDrawing.size[0]+lineWidth*3
ypos = circleSize+bodySize
background.paste(limbDrawing,(xpos,ypos),limbDrawing)
return background
def badText(self, text, big, color=(0,0,0,255)):
if big: font = fnt
else: font = smolfnt
w, h = font.getsize(text)
img = Image.new("RGBA",(w,h),color=(0,0,0,0))
d = ImageDraw.Draw(img,"RGBA")
d.text((0,0),text,font=font,fill=color)
return img
def drawGallows(self):
background = Image.new("RGBA",(gallowx,gallowy),color=(0,0,0,0))
bottomLine = self.badLine(int(gallowx*0.75),True)
background.paste(bottomLine,(int(gallowx*0.125),gallowy-(lineWidth*4)),bottomLine)
lineTwo = self.badLine(gallowy-lineWidth*6)
background.paste(lineTwo,(int(gallowx*(0.75*goldenRatio)),lineWidth*2),lineTwo)
topLine = self.badLine(int(gallowy*0.30),True)
background.paste(topLine,(int(gallowx*(0.75*goldenRatio))-lineWidth,lineWidth*3),topLine)
lastLine = self.badLine(int(gallowy*0.125))
background.paste(lastLine,((int(gallowx*(0.75*goldenRatio))+int(gallowy*0.30)-lineWidth),lineWidth*3),lastLine)
return background
def drawLetterLines(self, word,guessed,misses):
letterLines = Image.new("RGBA",((letterLineLength+letterLineDistance)*len(word),letterLineLength+lineWidth*3),color=(0,0,0,0))
for x, letter in enumerate(word):
line = self.badLine(letterLineLength,True)
letterLines.paste(line,(x*(letterLineLength+letterLineDistance),letterLineLength),line)
if guessed[x]:
letterDrawing = self.badText(letter,True)
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
elif misses == 6:
letterDrawing = self.badText(letter,True,(242,66,54))
letterWidth = fnt.getsize(letter)[0]
letterx = int(x*(letterLineLength+letterLineDistance)-(letterWidth/2)+(letterLineLength*0.5)+(lineWidth*2))
letterLines.paste(letterDrawing,(letterx,0),letterDrawing)
return letterLines
def shortestDist(self,positions,newPosition):
shortestDist = math.inf
x, y = newPosition
for i, j in positions:
xdist = abs(i-x)
ydist = abs(j-y)
dist = math.sqrt(xdist**2+ydist**2)
if shortestDist > dist: shortestDist = dist
return shortestDist
def drawMisses(self,guesses,word):
background = Image.new("RGBA",(600,400),color=(0,0,0,0))
pos = []
for guess in guesses:
if guess not in word:
placed = False
while placed == False:
letter = self.badText(guess,True)
w, h = fnt.getsize(guess)
x = random.randint(0,600-w)
y = random.randint(0,400-h)
if self.shortestDist(pos,(x,y)) > 70:
pos.append((x,y))
background.paste(letter,(x,y),letter)
placed = True
return background
def drawImage(self,channel):
self.bot.log("Drawing hangman image", channel)
game = self.bot.database["hangman games"].find_one({"_id":channel})
random.seed(game["game ID"])
background = Image.open("resources/paper.jpg")
try:
gallow = self.drawGallows()
except:
self.bot.log("Error drawing gallows (error code 1711)")
try:
man = self.drawMan(game["misses"])
except:
self.bot.log("Error drawing stick figure (error code 1712)")
random.seed(game["game ID"])
try:
letterLines = self.drawLetterLines(game["word"],game["guessed"],game["misses"])
except:
self.bot.log("error drawing letter lines (error code 1713)")
random.seed(game["game ID"])
try:
misses = self.drawMisses(game["guessed letters"],game["word"])
except:
self.bot.log("Error drawing misses (error code 1714)")
background.paste(gallow,(100,100),gallow)
background.paste(man,(300,210),man)
background.paste(letterLines,(120,840),letterLines)
background.paste(misses,(600,150),misses)
missesText = self.badText("MISSES",False)
missesTextWidth = missesText.size[0]
background.paste(missesText,(850-int(missesTextWidth/2),50),missesText)
background.save("resources/games/hangmanBoards/hangmanBoard"+channel+".png")

View File

@ -2,21 +2,21 @@ import random
import copy import copy
import math import math
import discord import discord
import math
from .hexDraw import DrawHex from PIL import Image, ImageDraw, ImageFont
BOARDWIDTH = 11
ALL_POSITIONS = [(i,j) for i in range(11) for j in range(11)]
ALL_SET = set(ALL_POSITIONS)
EMPTY_DIJKSTRA = {}
for position in ALL_POSITIONS:
EMPTY_DIJKSTRA[position] = math.inf # an impossibly high number
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)
self.BOARDWIDTH = 11
self.ALLPOSITIONS = [(i,j) for i in range(11) for j in range(11)]
self.ALLSET = set(self.ALLPOSITIONS)
self.EMPTYDIJKSTRA = {}
for position in self.ALLPOSITIONS:
self.EMPTYDIJKSTRA[position] = math.inf # an impossibly high number
self.HEXDIRECTIONS = [(0,1),(-1,1),(-1,0),(0,-1),(1,-1),(1,0)]
async def surrender(self, ctx): async def surrender(self, ctx):
channel = str(ctx.channel_id) channel = str(ctx.channel_id)
@ -30,7 +30,7 @@ class HexGame():
opponent = (players.index(user) + 1) % 2 opponent = (players.index(user) + 1) % 2
opponentName = self.bot.databaseFuncs.getName(players[opponent]) opponentName = self.bot.databaseFuncs.getName(players[opponent])
self.bot.database["hex games"].update_one({"_id":channel},{"$set":{"winner":opponent + 1}}) 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") await ctx.send(f"{ctx.author.display_name} surrendered")
with open(f"resources/games/oldImages/hex{channel}", "r") as f: with open(f"resources/games/oldImages/hex{channel}", "r") as f:
oldImage = await ctx.channel.fetch_message(int(f.read())) oldImage = await ctx.channel.fetch_message(int(f.read()))
@ -47,6 +47,8 @@ class HexGame():
with open(f"resources/games/oldImages/hex{channel}", "w") as f: with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id)) f.write(str(oldImage.id))
self.bot.database["hex games"].delete_one({"_id":channel})
# Swap # Swap
async def swap(self, ctx): async def swap(self, ctx):
channel = str(ctx.channel_id) channel = str(ctx.channel_id)
@ -149,7 +151,7 @@ class HexGame():
if canStart: 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(self.BOARDWIDTH)] for j in range(self.BOARDWIDTH)]
players = [user, opponent] players = [user, opponent]
random.shuffle(players) # random starting player random.shuffle(players) # random starting player
gameHistory = [] gameHistory = []
@ -276,6 +278,8 @@ class HexGame():
if game["players"][winner-1] != f"#{self.bot.user.id}": if game["players"][winner-1] != f"#{self.bot.user.id}":
winnings = game["difficulty"]*10 winnings = game["difficulty"]*10
self.bot.money.addMoney(game["players"][winner-1].lower(),winnings) self.bot.money.addMoney(game["players"][winner-1].lower(),winnings)
self.bot.database["hex games"].delete_one({"_id":channel})
else: else:
with open(f"resources/games/oldImages/hex{channel}", "w") as f: with open(f"resources/games/oldImages/hex{channel}", "w") as f:
f.write(str(oldImage.id)) f.write(str(oldImage.id))
@ -290,7 +294,7 @@ class HexGame():
# Error handling # Error handling
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(self.BOARDWIDTH) or row not in range(self.BOARDWIDTH):
self.bot.log("Position out of bounds") self.bot.log("Position out of bounds")
return None return None
# Place at the position # Place at the position
@ -381,20 +385,20 @@ class HexGame():
winner = 0 winner = 0
# Here, I use Dijkstra's algorithm to evaluate the board, as proposed by this article: https://towardsdatascience.com/hex-creating-intelligent-adversaries-part-2-heuristics-dijkstras-algorithm-597e4dcacf93 # Here, I use Dijkstra's algorithm to evaluate the board, as proposed by this article: https://towardsdatascience.com/hex-creating-intelligent-adversaries-part-2-heuristics-dijkstras-algorithm-597e4dcacf93
for player in [1,2]: for player in [1,2]:
Distance = copy.deepcopy(EMPTY_DIJKSTRA) Distance = copy.deepcopy(self.EMPTYDIJKSTRA)
# Initialize the starting hexes. For the blue player, this is the leftmost column. For the red player, this is the tom row. # Initialize the starting hexes. For the blue player, this is the leftmost column. For the red player, this is the tom row.
for start in (ALL_POSITIONS[::11] if player == 2 else ALL_POSITIONS[:11]): for start in (self.ALLPOSITIONS[::11] if player == 2 else self.ALLPOSITIONS[:11]):
# An empty hex adds a of distance of 1. A hex of own color add distance 0. Opposite color adds infinite distance. # An empty hex adds a of distance of 1. A hex of own color add distance 0. Opposite color adds infinite distance.
Distance[start] = 1 if (board[start[0]][start[1]] == 0) else 0 if (board[start[0]][start[1]] == player) else math.inf Distance[start] = 1 if (board[start[0]][start[1]] == 0) else 0 if (board[start[0]][start[1]] == player) else math.inf
visited = set() # Also called sptSet, short for "shortest path tree Set" visited = set() # Also called sptSet, short for "shortest path tree Set"
for _ in range(BOARDWIDTH**2): # We can at most check every 121 hexes for _ in range(self.BOARDWIDTH**2): # We can at most check every 121 hexes
# Find the next un-visited hex, that has the lowest distance # Find the next un-visited hex, that has the lowest distance
remainingHexes = ALL_SET.difference(visited) remainingHexes = self.ALLSET.difference(visited)
A = [Distance[k] for k in remainingHexes] # Find the distance to each un-visited hex A = [Distance[k] for k in remainingHexes] # Find the distance to each un-visited hex
u = list(remainingHexes)[A.index(min(A))] # Chooses the one with the lowest distance u = list(remainingHexes)[A.index(min(A))] # Chooses the one with the lowest distance
# Find neighbors of the hex u # Find neighbors of the hex u
for di in HEX_DIRECTIONS: for di in self.HEXDIRECTIONS:
v = (u[0] + di[0] , u[1] + di[1]) # v is a neighbor of u v = (u[0] + di[0] , u[1] + di[1]) # v is a neighbor of u
if v[0] in range(11) and v[1] in range(11) and v not in visited: if v[0] in range(11) and v[1] in range(11) and v not in visited:
new_dist = Distance[u] + (1 if (board[v[0]][v[1]] == 0) else 0 if (board[v[0]][v[1]] == player) else math.inf) new_dist = Distance[u] + (1 if (board[v[0]][v[1]] == 0) else 0 if (board[v[0]][v[1]] == player) else math.inf)
@ -425,7 +429,7 @@ class HexGame():
#self.bot.log("Judging a red move at depth {}".format(depth)) #self.bot.log("Judging a red move at depth {}".format(depth))
for i in possiblePlaces: for i in possiblePlaces:
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 1 # because maximizingPlayer is Red which is number 1 testBoard[i // self.BOARDWIDTH][i % self.BOARDWIDTH] = 1 # because maximizingPlayer is Red which is number 1
evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,False) evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,False)
maxEval = max(maxEval, evaluation) maxEval = max(maxEval, evaluation)
alpha = max(alpha, evaluation) alpha = max(alpha, evaluation)
@ -439,7 +443,7 @@ class HexGame():
#self.bot.log("Judging a blue move at depth {}".format(depth)) #self.bot.log("Judging a blue move at depth {}".format(depth))
for i in possiblePlaces: for i in possiblePlaces:
testBoard = copy.deepcopy(board) testBoard = copy.deepcopy(board)
testBoard[i // BOARDWIDTH][i % BOARDWIDTH] = 2 # because minimizingPlayer is Blue which is number 2 testBoard[i // self.BOARDWIDTH][i % self.BOARDWIDTH] = 2 # because minimizingPlayer is Blue which is number 2
evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,True) evaluation = self.minimaxHex(testBoard,depth-1,alpha,beta,True)
minEval = min(minEval, evaluation) minEval = min(minEval, evaluation)
beta = min(beta, evaluation) beta = min(beta, evaluation)
@ -448,3 +452,192 @@ class HexGame():
break break
return minEval return minEval
class DrawHex():
def __init__(self,bot):
self.bot = bot
# Defining all the variables
self.CANVASWIDTH = 2400
self.CANVASHEIGHT = 1800
self.SIDELENGTH = 75
# The offsets centers the board in the picture
self.XOFFSET = self.CANVASWIDTH/2 - 8*math.sqrt(3)*self.SIDELENGTH
# The offsets are the coordinates of the upperleft point in the
# upperleftmost hexagon
self.YOFFSET = self.CANVASHEIGHT/2 - 8*self.SIDELENGTH
# The whole width of one hexagon
self.HEXAGONWIDTH = math.sqrt(3) * self.SIDELENGTH
# The height difference between two layers
self.HEXAGONHEIGHT = 1.5 * self.SIDELENGTH
self.FONTSIZE = 45
self.TEXTCOLOR = (0,0,0)
self.FONT = ImageFont.truetype('resources/fonts/futura-bold.ttf', self.FONTSIZE)
self.LINETHICKNESS = 15
self.HEXTHICKNESS = 6 # This is half the width of the background lining between every hex
self.XTHICKNESS = self.HEXTHICKNESS * math.cos(math.pi/6)
self.YTHICKNESS = self.HEXTHICKNESS * math.sin(math.pi/6)
self.BACKGROUNDCOLOR = (230,230,230)
self.BETWEENCOLOR = (231,231,231)
self.BLANKCOLOR = "lightgrey"
self.PIECECOLOR = {1:(237,41,57),2:(0,165,255),0:self.BLANKCOLOR} # player1 is red, player2 is blue
self.BOARDCOORDINATES = [ [(self.XOFFSET + self.HEXAGONWIDTH*(column + row/2),self.YOFFSET + self.HEXAGONHEIGHT*row) for column in range(11)] for row in range(11)] # These are the coordinates for the upperleft corner of every hex
self.COLHEXTHICKNESS = 4 # When placing a hex, it is a little bigger than the underlying hex in the background (4 < 6)
self.COLXTHICKNESS = self.COLHEXTHICKNESS * math.cos(math.pi/6)
self.COLYTHICKNESS = self.COLHEXTHICKNESS * math.sin(math.pi/6)
# The Name display things:
self.NAMESIZE = 60
self.NAMEFONT = ImageFont.truetype('resources/fonts/futura-bold.ttf', self.NAMESIZE)
self.XNAME = {1:175, 2:self.CANVASWIDTH-100}
self.YNAME = {1:self.CANVASHEIGHT-150, 2:150}
self.NAMEHEXPADDING = 90
self.SMALLWIDTH = self.HEXAGONWIDTH * 0.6
self.SMALLSIDELENGTH = self.SIDELENGTH * 0.6
def drawBoard(self, channel):
self.bot.log("Drawing empty Hex board")
# Creates the empty image
im = Image.new('RGB', size=(self.CANVASWIDTH, self.CANVASHEIGHT),color = self.BACKGROUNDCOLOR)
# 'd' is a shortcut to drawing on the image
d = ImageDraw.Draw(im,"RGBA")
# Drawing all the hexagons
for column in self.BOARDCOORDINATES:
for startingPoint in column:
x = startingPoint[0]
y = startingPoint[1]
d.polygon([
(x, y),
(x+self.HEXAGONWIDTH/2, y-0.5*self.SIDELENGTH),
(x+self.HEXAGONWIDTH, y),
(x+self.HEXAGONWIDTH, y+self.SIDELENGTH),
(x+self.HEXAGONWIDTH/2, y+1.5*self.SIDELENGTH),
(x, y+self.SIDELENGTH),
],fill = self.BETWEENCOLOR)
d.polygon([
(x+self.XTHICKNESS, y + self.YTHICKNESS),
(x+self.HEXAGONWIDTH/2, y-0.5*self.SIDELENGTH + self.HEXTHICKNESS),
(x+self.HEXAGONWIDTH-self.XTHICKNESS, y + self.YTHICKNESS),
(x+self.HEXAGONWIDTH-self.XTHICKNESS, y+self.SIDELENGTH - self.YTHICKNESS),
(x+self.HEXAGONWIDTH/2, y+1.5*self.SIDELENGTH - self.HEXTHICKNESS),
(x+self.XTHICKNESS, y+self.SIDELENGTH - self.YTHICKNESS),
],fill = self.BLANKCOLOR)
# Draw color on the outside of the board
# Top line, red
d.line(sum((sum([(point[0],point[1],point[0]+self.HEXAGONWIDTH/2,point[1]-self.HEXAGONHEIGHT+self.SIDELENGTH) for point in self.BOARDCOORDINATES[0]],()),(self.BOARDCOORDINATES[0][10][0]+self.HEXAGONWIDTH*3/4,self.BOARDCOORDINATES[0][10][1]-self.SIDELENGTH/4)),()),
fill = self.PIECECOLOR[1],width = self.LINETHICKNESS)
# Bottom line, red
d.line(sum(((self.BOARDCOORDINATES[10][0][0]+self.HEXAGONWIDTH/4,self.BOARDCOORDINATES[10][0][1]+self.SIDELENGTH*5/4),sum([(point[0]+self.HEXAGONWIDTH/2,point[1]+self.HEXAGONHEIGHT,point[0]+self.HEXAGONWIDTH,point[1]+self.SIDELENGTH) for point in self.BOARDCOORDINATES[10]],())),()),
fill = self.PIECECOLOR[1],width = self.LINETHICKNESS)
# Left line, blue
d.line(sum((sum([(row[0][0],row[0][1],row[0][0],row[0][1]+self.SIDELENGTH) for row in self.BOARDCOORDINATES],()),(self.BOARDCOORDINATES[10][0][0]+self.HEXAGONWIDTH/4,self.BOARDCOORDINATES[10][0][1]+self.SIDELENGTH*5/4)),()),
fill = self.PIECECOLOR[2],width = self.LINETHICKNESS)
# Right line, blue
d.line(sum(((self.BOARDCOORDINATES[0][10][0]+self.HEXAGONWIDTH*3/4,self.BOARDCOORDINATES[0][10][1]-self.SIDELENGTH/4),sum([(row[10][0]+self.HEXAGONWIDTH,row[10][1],row[10][0]+self.HEXAGONWIDTH,row[10][1]+self.SIDELENGTH) for row in self.BOARDCOORDINATES],())),()),
fill = self.PIECECOLOR[2],width = self.LINETHICKNESS)
# Writes "abc..", "123.." on the columns and rows
for i in range(11):
# Top letters
d.text( (self.XOFFSET + self.HEXAGONWIDTH*i, self.YOFFSET-66) , "ABCDEFGHIJK"[i], font=self.FONT, fill=self.TEXTCOLOR)
# Bottom letters
d.text( (self.XOFFSET + self.HEXAGONWIDTH*(i+11.5/2), self.YOFFSET - 15 + 11*self.HEXAGONHEIGHT) , "ABCDEFGHIJK"[i], font=self.FONT, fill=self.TEXTCOLOR)
# Left numbers
d.multiline_text( (self.XOFFSET + self.HEXAGONWIDTH*i/2 - 72 -4*(i>8), self.YOFFSET + 18 + i*self.HEXAGONHEIGHT) , str(i+1), font=self.FONT, fill=self.TEXTCOLOR, align="right")
# Right numbers
d.text( (self.XOFFSET + self.HEXAGONWIDTH*(i/2+11) + 30 , self.YOFFSET + 6 + i*self.HEXAGONHEIGHT) , str(i+1), font=self.FONT, fill=self.TEXTCOLOR)
# Write player names and color
game = self.bot.database["hex games"].find_one({"_id":channel})
for p in [1,2]:
playername = self.bot.databaseFuncs.getName(game["players"][p-1])
# Draw name
x = self.XNAME[p]
x -= self.NAMEFONT.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = self.YNAME[p]
d.text((x,y),playername, font=self.NAMEFONT, fill = self.TEXTCOLOR)
# Draw a half-size Hexagon to indicate the player's color
x -= self.NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+self.SMALLWIDTH/2, y-self.SMALLSIDELENGTH/2),
(x+self.SMALLWIDTH, y),
(x+self.SMALLWIDTH, y+self.SMALLSIDELENGTH),
(x+self.SMALLWIDTH/2, y+self.SMALLSIDELENGTH*3/2),
(x, y+self.SMALLSIDELENGTH),
],fill = self.PIECECOLOR[p])
im.save("resources/games/hexBoards/board"+channel+".png")
def drawHexPlacement(self, channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
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()
position = position.lower()
column = ord(position[0])-97 # ord() translates from letter to number
row = int(position[1:])-1
# Find the coordinates for the filled hex drawing
hexCoords = [
(self.BOARDCOORDINATES[row][column][0]+self.COLXTHICKNESS, self.BOARDCOORDINATES[row][column][1] + self.COLYTHICKNESS),
(self.BOARDCOORDINATES[row][column][0]+self.HEXAGONWIDTH/2, self.BOARDCOORDINATES[row][column][1]-0.5*self.SIDELENGTH + self.COLHEXTHICKNESS),
(self.BOARDCOORDINATES[row][column][0]+self.HEXAGONWIDTH-self.COLXTHICKNESS, self.BOARDCOORDINATES[row][column][1] + self.COLYTHICKNESS),
(self.BOARDCOORDINATES[row][column][0]+self.HEXAGONWIDTH-self.COLXTHICKNESS, self.BOARDCOORDINATES[row][column][1]+self.SIDELENGTH - self.COLYTHICKNESS),
(self.BOARDCOORDINATES[row][column][0]+self.HEXAGONWIDTH/2, self.BOARDCOORDINATES[row][column][1]+1.5*self.SIDELENGTH - self.COLHEXTHICKNESS),
(self.BOARDCOORDINATES[row][column][0]+self.COLXTHICKNESS, self.BOARDCOORDINATES[row][column][1]+self.SIDELENGTH - self.COLYTHICKNESS),
]
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Draws the hex piece
d.polygon(hexCoords,fill = self.PIECECOLOR[player], outline = self.BETWEENCOLOR)
# Save
im.save(FILEPATH)
except:
self.bot.log("Error drawing new hex on board (error code 1541")
def drawSwap(self, channel):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
game = self.bot.database["hex games"].find_one({"_id":channel})
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Write player names and color
for p in [1,2]:
playername = self.bot.databaseFuncs.getName(game["players"][p%2])
x = self.XNAME[p]
x -= self.NAMEFONT.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = self.YNAME[p]
# Draw a half-size Hexagon to indicate the player's color
x -= self.NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+self.SMALLWIDTH/2, y-self.SMALLSIDELENGTH/2),
(x+self.SMALLWIDTH, y),
(x+self.SMALLWIDTH, y+self.SMALLSIDELENGTH),
(x+self.SMALLWIDTH/2, y+self.SMALLSIDELENGTH*3/2),
(x, y+self.SMALLSIDELENGTH),
],fill = self.PIECECOLOR[p % 2 + 1])
# Save
im.save(FILEPATH)
except:
self.bot.log("Error drawing swap (error code 1542)")

View File

@ -1,185 +0,0 @@
import math
from PIL import Image, ImageDraw, ImageFont
# Defining all the variables
CANVAS_WIDTH = 2400
CANVAS_HEIGHT = 1800
SIDELENGTH = 75
X_OFFSET = CANVAS_WIDTH/2 - 8*math.sqrt(3)*SIDELENGTH # The offsets centers the board in the picture
Y_OFFSET = CANVAS_HEIGHT/2 - 8*SIDELENGTH # The offsets are the coordinates of the upperleft point in the upperleftmost hexagon
HEXAGONWIDTH = math.sqrt(3) * SIDELENGTH # the whole width of one hexagon
HEXAGONHEIGHT = 1.5 * SIDELENGTH # not really the entire height, but the height difference between two layers
FONTSIZE = 45
TEXTCOLOR = (0,0,0)
fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', FONTSIZE)
LINETHICKNESS = 15
HEXTHICKNESS = 6 # This is half the width of the background lining between every hex
X_THICKNESS = HEXTHICKNESS * math.cos(math.pi/6)
Y_THICKNESS = HEXTHICKNESS * math.sin(math.pi/6)
BACKGROUND_COLOR = (230,230,230)
BETWEEN_COLOR = (231,231,231)
BLANK_COLOR = "lightgrey"
PIECECOLOR = {1:(237,41,57),2:(0,165,255),0:BLANK_COLOR} # player1 is red, player2 is blue
BOARDCOORDINATES = [ [(X_OFFSET + HEXAGONWIDTH*(column + row/2),Y_OFFSET + HEXAGONHEIGHT*row) for column in range(11)] for row in range(11)] # These are the coordinates for the upperleft corner of every hex
COLHEXTHICKNESS = 4 # When placing a hex, it is a little bigger than the underlying hex in the background (4 < 6)
COLX_THICKNESS = COLHEXTHICKNESS * math.cos(math.pi/6)
COLY_THICKNESS = COLHEXTHICKNESS * math.sin(math.pi/6)
# The Name display things:
NAMESIZE = 60
NAME_fnt = ImageFont.truetype('resources/fonts/futura-bold.ttf', NAMESIZE)
X_NAME = {1:175, 2:CANVAS_WIDTH-100}
Y_NAME = {1:CANVAS_HEIGHT-150, 2:150}
NAMEHEXPADDING = 90
SMOL_WIDTH = HEXAGONWIDTH * 0.6
SMOL_SIDELENGTH = SIDELENGTH * 0.6
class DrawHex():
def __init__(self,bot):
self.bot = bot
def drawBoard(self, channel):
self.bot.log("Drawing empty Hex board")
# Creates the empty image
im = Image.new('RGB', size=(CANVAS_WIDTH, CANVAS_HEIGHT),color = BACKGROUND_COLOR)
# 'd' is a shortcut to drawing on the image
d = ImageDraw.Draw(im,"RGBA")
# Drawing all the hexagons
for column in BOARDCOORDINATES:
for startingPoint in column:
x = startingPoint[0]
y = startingPoint[1]
d.polygon([
(x, y),
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH),
(x+HEXAGONWIDTH, y),
(x+HEXAGONWIDTH, y+SIDELENGTH),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH),
(x, y+SIDELENGTH),
],fill = BETWEEN_COLOR)
d.polygon([
(x+X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH/2, y-0.5*SIDELENGTH + HEXTHICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y + Y_THICKNESS),
(x+HEXAGONWIDTH-X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
(x+HEXAGONWIDTH/2, y+1.5*SIDELENGTH - HEXTHICKNESS),
(x+X_THICKNESS, y+SIDELENGTH - Y_THICKNESS),
],fill = BLANK_COLOR)
# Draw color on the outside of the board
# Top line, red
d.line(sum((sum([(point[0],point[1],point[0]+HEXAGONWIDTH/2,point[1]-HEXAGONHEIGHT+SIDELENGTH) for point in BOARDCOORDINATES[0]],()),(BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4)),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Bottom line, red
d.line(sum(((BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4),sum([(point[0]+HEXAGONWIDTH/2,point[1]+HEXAGONHEIGHT,point[0]+HEXAGONWIDTH,point[1]+SIDELENGTH) for point in BOARDCOORDINATES[10]],())),()),
fill = PIECECOLOR[1],width = LINETHICKNESS)
# Left line, blue
d.line(sum((sum([(row[0][0],row[0][1],row[0][0],row[0][1]+SIDELENGTH) for row in BOARDCOORDINATES],()),(BOARDCOORDINATES[10][0][0]+HEXAGONWIDTH/4,BOARDCOORDINATES[10][0][1]+SIDELENGTH*5/4)),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Right line, blue
d.line(sum(((BOARDCOORDINATES[0][10][0]+HEXAGONWIDTH*3/4,BOARDCOORDINATES[0][10][1]-SIDELENGTH/4),sum([(row[10][0]+HEXAGONWIDTH,row[10][1],row[10][0]+HEXAGONWIDTH,row[10][1]+SIDELENGTH) for row in BOARDCOORDINATES],())),()),
fill = PIECECOLOR[2],width = LINETHICKNESS)
# Writes "abc..", "123.." on the columns and rows
for i in range(11):
# Top letters
d.text( (X_OFFSET + HEXAGONWIDTH*i, Y_OFFSET-66) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Bottom letters
d.text( (X_OFFSET + HEXAGONWIDTH*(i+11.5/2), Y_OFFSET - 15 + 11*HEXAGONHEIGHT) , "ABCDEFGHIJK"[i], font=fnt, fill=TEXTCOLOR)
# Left numbers
d.multiline_text( (X_OFFSET + HEXAGONWIDTH*i/2 - 72 -4*(i>8), Y_OFFSET + 18 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR, align="right")
# Right numbers
d.text( (X_OFFSET + HEXAGONWIDTH*(i/2+11) + 30 , Y_OFFSET + 6 + i*HEXAGONHEIGHT) , str(i+1), font=fnt, fill=TEXTCOLOR)
# Write player names and color
game = self.bot.database["hex games"].find_one({"_id":channel})
for p in [1,2]:
playername = self.bot.databaseFuncs.getName(game["players"][p-1])
# Draw name
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
d.text((x,y),playername, font=NAME_fnt, fill = TEXTCOLOR)
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p])
im.save("resources/games/hexBoards/board"+channel+".png")
def drawHexPlacement(self, channel,player,position):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
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()
position = position.lower()
column = ord(position[0])-97 # ord() translates from letter to number
row = int(position[1:])-1
# Find the coordinates for the filled hex drawing
hexCoords = [
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]-0.5*SIDELENGTH + COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1] + COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH-COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
(BOARDCOORDINATES[row][column][0]+HEXAGONWIDTH/2, BOARDCOORDINATES[row][column][1]+1.5*SIDELENGTH - COLHEXTHICKNESS),
(BOARDCOORDINATES[row][column][0]+COLX_THICKNESS, BOARDCOORDINATES[row][column][1]+SIDELENGTH - COLY_THICKNESS),
]
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Draws the hex piece
d.polygon(hexCoords,fill = PIECECOLOR[player], outline = BETWEEN_COLOR)
# Save
im.save(FILEPATH)
except:
self.bot.log("Error drawing new hex on board (error code 1541")
def drawSwap(self, channel):
FILEPATH = "resources/games/hexBoards/board"+channel+".png"
game = self.bot.database["hex games"].find_one({"_id":channel})
# Opens the image
try:
with Image.open(FILEPATH) as im:
d = ImageDraw.Draw(im,"RGBA")
# Write player names and color
for p in [1,2]:
playername = self.bot.databaseFuncs.getName(game["players"][p%2])
x = X_NAME[p]
x -= NAME_fnt.getsize(playername)[0] if p==2 else 0 # player2's name is right-aligned
y = Y_NAME[p]
# Draw a half-size Hexagon to indicate the player's color
x -= NAMEHEXPADDING # To the left of both names
d.polygon([
(x, y),
(x+SMOL_WIDTH/2, y-SMOL_SIDELENGTH/2),
(x+SMOL_WIDTH, y),
(x+SMOL_WIDTH, y+SMOL_SIDELENGTH),
(x+SMOL_WIDTH/2, y+SMOL_SIDELENGTH*3/2),
(x, y+SMOL_SIDELENGTH),
],fill = PIECECOLOR[p % 2 + 1])
# Save
im.save(FILEPATH)
except:
self.bot.log("Error drawing swap (error code 1542)")