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