init
34
assets.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class Piece:
|
||||||
|
def get_valid_jumps():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Bee(Piece):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Beetle(Piece):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Spider(Piece):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Grasshopper(Piece):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Ant(Piece):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PieceTranslator(Enum):
|
||||||
|
q = Bee
|
||||||
|
b = Beetle
|
||||||
|
s = Spider
|
||||||
|
g = Grasshopper
|
||||||
|
a = Ant
|
254
base.py
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
# DO NOT MODIFY THIS FILE
|
||||||
|
# THIS FILE IS NOT UPLOADED TO BRUTE (all changes in it will be ignored by Brute)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Board:
|
||||||
|
def __init__(self, myIsUpper, size, myPieces, rivalPieces):
|
||||||
|
self.size = size #integer, size of the board
|
||||||
|
self.myMove = 0 #integer, index of actual move
|
||||||
|
self.board = {} #dict of board, use self.board[p][q] to acess cell (p,q)
|
||||||
|
self.myColorIsUpper = myIsUpper #if true, by figures are big (A,Q,S,G,B), otherwise there are small (a,q,s,g,b)
|
||||||
|
self.algorithmName = "some algorithm"
|
||||||
|
self.playerName = "some name"
|
||||||
|
self.tournament = 0 #filled by Brute, if True, player is run in tournament mode
|
||||||
|
|
||||||
|
self.myPieces = myPieces.copy() # dict of key=animal, value = number of available, self.myPieces["b"] = 3
|
||||||
|
self._myPiecesOriginal = myPieces.copy()
|
||||||
|
|
||||||
|
self.rivalPieces = rivalPieces.copy()
|
||||||
|
self._rivalPiecesOriginal = rivalPieces.copy()
|
||||||
|
|
||||||
|
# the rest of the coe is just for drawing to png
|
||||||
|
|
||||||
|
self._images = {}
|
||||||
|
self._imagesSmall = {}
|
||||||
|
|
||||||
|
for imagename in ["ant", "beetle", "bee", "spider", "grasshopper" ]:
|
||||||
|
self._images[ imagename ] = Image.open("images/{}.png".format(imagename)).resize((70,70))
|
||||||
|
self._imagesSmall[ imagename ] = Image.open("images/{}.png".format(imagename)).resize((20,20))
|
||||||
|
|
||||||
|
#create empty board as a dictionary
|
||||||
|
for p in range(-self.size,self.size):
|
||||||
|
for q in range(-self.size, self.size):
|
||||||
|
if self.inBoard(p,q):
|
||||||
|
if not p in self.board:
|
||||||
|
self.board[p] = {}
|
||||||
|
self.board[p][q] = ""
|
||||||
|
|
||||||
|
#this is for visualization and to synchronize colors between png/js
|
||||||
|
self._colors = {}
|
||||||
|
self._colors[-1] = "#fdca40" #sunglow
|
||||||
|
self._colors[0] = "#ffffff" #white
|
||||||
|
self._colors[1] = "#947bd3" #medium purple
|
||||||
|
self._colors[2] = "#ff0000" #red
|
||||||
|
self._colors[3] = "#00ff00" #green
|
||||||
|
self._colors[4] = "#0000ff" #blue
|
||||||
|
self._colors[5] = "#566246" #ebony
|
||||||
|
self._colors[6] = "#a7c4c2" #opan
|
||||||
|
self._colors[7] = "#ADACB5" #silver metalic
|
||||||
|
self._colors[8] = "#8C705F" #liver chestnut
|
||||||
|
self._colors[9] = "#FA7921" #pumpkin
|
||||||
|
self._colors[10] = "#566E3D" #dark olive green
|
||||||
|
|
||||||
|
|
||||||
|
def inBoard(self,p,q):
|
||||||
|
""" return True if (p,q) is valid coordinate """
|
||||||
|
return (q>= 0) and (q < self.size) and (p >= -(q//2)) and (p < (self.size - q//2))
|
||||||
|
|
||||||
|
def rotateRight(self,p,q):
|
||||||
|
pp = -q
|
||||||
|
qq = p+q
|
||||||
|
return pp,qq
|
||||||
|
|
||||||
|
def rotateLeft(self, p,q):
|
||||||
|
pp = p+q
|
||||||
|
qq = -p
|
||||||
|
return pp, qq
|
||||||
|
|
||||||
|
|
||||||
|
def letter2image(self, lastLetter):
|
||||||
|
impaste = None
|
||||||
|
impaste2 = None
|
||||||
|
lastLetter = lastLetter.lower()
|
||||||
|
if lastLetter == "q":
|
||||||
|
impaste, impaste2 = self._images["bee"], self._imagesSmall["bee"]
|
||||||
|
elif lastLetter == "b":
|
||||||
|
impaste, impaste2 = self._images["beetle"], self._imagesSmall["beetle"]
|
||||||
|
elif lastLetter == "s":
|
||||||
|
impaste, impaste2 = self._images["spider"], self._imagesSmall["spider"]
|
||||||
|
elif lastLetter == "g":
|
||||||
|
impaste, impaste2 = self._images["grasshopper"], self._imagesSmall["grasshopper"]
|
||||||
|
elif lastLetter == "a":
|
||||||
|
impaste, impaste2 = self._images["ant"], self._imagesSmall["ant"]
|
||||||
|
return impaste, impaste2
|
||||||
|
|
||||||
|
def saveImage(self, filename, HL = {}, LINES = [], HLA = {}):
|
||||||
|
""" draw actual board to png. Empty cells are white, -1 = red, 1 = green, other values according to
|
||||||
|
this list
|
||||||
|
-1 red, 0 = white, 1 = green
|
||||||
|
HL is dict of coordinates and colors, e.g.
|
||||||
|
HL[(3,4)] = #RRGGBB #will use color #RRGGBB to highlight cell (3,4)
|
||||||
|
LINES is list of extra lines to be drawn in format
|
||||||
|
LINES = [ line1, line2 ,.... ], where each line is [#RRGGBB, p1, q1, p2,q2] - will draw line from cell (p1,q1) to cell (p2,q2)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def pq2hexa(p,q):
|
||||||
|
cx = cellRadius*(math.sqrt(3)*p + math.sqrt(3)/2*q) + cellRadius
|
||||||
|
cy = cellRadius*(0*p + 3/2*q) + cellRadius
|
||||||
|
|
||||||
|
pts = []
|
||||||
|
for a in [30,90,150,210,270,330]:
|
||||||
|
nx = cx + cellRadius * math.cos(a*math.pi/180)
|
||||||
|
ny = cy + cellRadius * math.sin(a*math.pi/180)
|
||||||
|
pts.append(nx)
|
||||||
|
pts.append(ny)
|
||||||
|
return cx,cy, pts
|
||||||
|
|
||||||
|
def drawPieces(piecesToDraw, piecesToDrawOriginal, draw, p,q, HLA = {}):
|
||||||
|
#HLA is dict, key is animal for highlight, value is color, e.g. HLA["a"] = "#RRGGBB" will highlight my own piece 'a'
|
||||||
|
for animal in piecesToDraw:
|
||||||
|
for v in range(piecesToDrawOriginal[animal]):
|
||||||
|
#draw this animal
|
||||||
|
cx,cy, pts = pq2hexa(p, q)
|
||||||
|
color = "#ff00ff"
|
||||||
|
|
||||||
|
lastLetter = animal
|
||||||
|
if lastLetter.islower():
|
||||||
|
color = self._colors[-1]
|
||||||
|
else:
|
||||||
|
color = self._colors[1]
|
||||||
|
if v < piecesToDraw[animal] and animal in HLA:
|
||||||
|
color = HLA[animal]
|
||||||
|
|
||||||
|
draw.polygon(pts,fill=color)
|
||||||
|
pts.append(pts[0])
|
||||||
|
pts.append(pts[1])
|
||||||
|
draw.line(pts,fill="black", width=1)
|
||||||
|
|
||||||
|
lastLetter = animal.lower()
|
||||||
|
icx = int(cx) - cellRadius//1;
|
||||||
|
icy = int(cy) - cellRadius//1;
|
||||||
|
if v < piecesToDraw[animal]:
|
||||||
|
impaste, impaste2 = self.letter2image(lastLetter)
|
||||||
|
if impaste:
|
||||||
|
img.paste(impaste, (int(icx),int(icy)), impaste )
|
||||||
|
p += 1
|
||||||
|
|
||||||
|
cellRadius = 35
|
||||||
|
cellWidth = int(cellRadius*(3**0.5))
|
||||||
|
cellHeight = 2*cellRadius
|
||||||
|
|
||||||
|
width = cellWidth*self.size + cellRadius*3
|
||||||
|
height = cellHeight*self.size
|
||||||
|
|
||||||
|
img = Image.new('RGB',(width,height),"white")
|
||||||
|
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
lineColor = (50,50,50)
|
||||||
|
|
||||||
|
allQ = []
|
||||||
|
allP = []
|
||||||
|
|
||||||
|
for p in self.board:
|
||||||
|
allP.append(p)
|
||||||
|
for q in self.board[p]:
|
||||||
|
allQ.append(q)
|
||||||
|
cx,cy, pts = pq2hexa(p,q)
|
||||||
|
|
||||||
|
color = "#ff00ff" #pink is for values out of range -1,..10
|
||||||
|
if self.isEmpty(p,q, self.board):
|
||||||
|
color = self._colors[0]
|
||||||
|
else:
|
||||||
|
lastLetter = self.board[p][q][-1]
|
||||||
|
if lastLetter.islower():
|
||||||
|
color = self._colors[-1]
|
||||||
|
else:
|
||||||
|
color = self._colors[1]
|
||||||
|
# if lastLetter.lower() in "bB" and len(self.board[p][q]) > 1:
|
||||||
|
# color = self._colors[2] #red beetle
|
||||||
|
|
||||||
|
if (p,q) in HL:
|
||||||
|
color = HL[(p,q)]
|
||||||
|
draw.polygon(pts,fill=color)
|
||||||
|
|
||||||
|
if not self.isEmpty(p,q, self.board) and self.board[p][q][-1].lower() in "bB" and len(self.board[p][q]) > 1:
|
||||||
|
#draw half of the polygon in red color to highlight that beetle is on the top
|
||||||
|
polygon2 = pts[6:] + pts[:2]
|
||||||
|
draw.polygon(polygon2,fill= self._colors[2] )
|
||||||
|
|
||||||
|
pts.append(pts[0])
|
||||||
|
pts.append(pts[1])
|
||||||
|
draw.line(pts,fill="black", width=1)
|
||||||
|
draw.text([cx-3,cy-3], "{} {}".format(p,q), fill="black", anchor="mm")
|
||||||
|
if not self.isEmpty(p,q, self.board):
|
||||||
|
draw.text([cx,cy], "{}".format(self.board[p][q]), fill="black", anchor="mm")
|
||||||
|
lastLetter = self.board[p][q][-1].lower()
|
||||||
|
|
||||||
|
icx = int(cx) - cellRadius//1;
|
||||||
|
icy = int(cy) - cellRadius//1;
|
||||||
|
impaste,impaste2 = self.letter2image(lastLetter)
|
||||||
|
|
||||||
|
if impaste:
|
||||||
|
img.paste(impaste, (int(icx),int(icy)), impaste )
|
||||||
|
|
||||||
|
maxq = max(allQ)
|
||||||
|
minp = min(allP)
|
||||||
|
maxq += 2
|
||||||
|
minp += 1
|
||||||
|
|
||||||
|
drawPieces(self.myPieces, self._myPiecesOriginal, draw, minp, maxq, HLA)
|
||||||
|
maxq += 1
|
||||||
|
drawPieces(self.rivalPieces, self._rivalPiecesOriginal, draw, minp, maxq, HLA)
|
||||||
|
|
||||||
|
for line in LINES:
|
||||||
|
color, p1, q1, p2, q2 = line
|
||||||
|
cx1,cy1, _ = pq2hexa(p1,q1)
|
||||||
|
cx2,cy2, _ = pq2hexa(p2,q2)
|
||||||
|
draw.line([cx1,cy1,cx2,cy2], fill=color, width=2)
|
||||||
|
|
||||||
|
img.save(filename)
|
||||||
|
|
||||||
|
def print(self, board):
|
||||||
|
for p in board:
|
||||||
|
for q in board[p]:
|
||||||
|
value =board[p][q]
|
||||||
|
if value == "":
|
||||||
|
value = ".."
|
||||||
|
print(value, end=" ")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def isMyColor(self, p,q, board):
|
||||||
|
""" assuming board[p][q] is not empty """
|
||||||
|
return ((not self.myColorIsUpper) and board[p][q][-1].islower()) or (self.myColorIsUpper and board[p][q][-1].isupper())
|
||||||
|
|
||||||
|
def isEmpty(self,p,q, board):
|
||||||
|
return board[p][q] == ""
|
||||||
|
|
||||||
|
def a2c(self,p,q):
|
||||||
|
x = p
|
||||||
|
z = q
|
||||||
|
y = -x -z
|
||||||
|
return x,y,z
|
||||||
|
|
||||||
|
def c2a(self, x,y,z):
|
||||||
|
p = x
|
||||||
|
q = z
|
||||||
|
return p,q
|
||||||
|
|
||||||
|
def distance(self,p1,q1,p2,q2):
|
||||||
|
""" return distance between two cells (p1,q1) and (p2,q2) """
|
||||||
|
x1,y1,z1 = self.a2c(p1,q1)
|
||||||
|
x2,y2,z2 = self.a2c(p2,q2)
|
||||||
|
dist = ( abs(x1-x2) + abs(y1-y2) + abs(z1-z2) ) // 2
|
||||||
|
return dist
|
||||||
|
|
||||||
|
|
||||||
|
|
BIN
images/ant.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
images/ant.xcf
Normal file
BIN
images/antRed.xcf
Normal file
BIN
images/bee.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
images/bee.xcf
Normal file
BIN
images/beetle.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
images/beetle.xcf
Normal file
BIN
images/grasshopper.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
images/grasshopper.xcf
Normal file
BIN
images/hive.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/hiveHR.png
Normal file
After Width: | Height: | Size: 719 KiB |
BIN
images/hiveHR2.png
Normal file
After Width: | Height: | Size: 916 KiB |
BIN
images/spider.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
images/spider.xcf
Normal file
128
player.py
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
import base as Base
|
||||||
|
import copy, random, time, math
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
|
# Player template for HIVE --- ALP semestral work
|
||||||
|
# Vojta Vonasek, 2023
|
||||||
|
|
||||||
|
|
||||||
|
# PUT ALL YOUR IMPLEMENTATION INTO THIS FILE
|
||||||
|
|
||||||
|
class Player(Base.Board):
|
||||||
|
def __init__(self, playerName, myIsUpper, size, myPieces, rivalPieces): #do not change this line
|
||||||
|
Base.Board.__init__(self, myIsUpper, size, myPieces, rivalPieces) #do not change this line
|
||||||
|
self.playerName = playerName
|
||||||
|
self.algorithmName = "myGreatMethod"
|
||||||
|
|
||||||
|
|
||||||
|
def getAllEmptyCells(self):
|
||||||
|
result = []
|
||||||
|
for p in self.board:
|
||||||
|
for q in self.board[p]:
|
||||||
|
if self.isEmpty(p,q, self.board):
|
||||||
|
result.append( [p,q] )
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def getAllNonemptyCells(self):
|
||||||
|
result = []
|
||||||
|
for p in self.board:
|
||||||
|
for q in self.board[p]:
|
||||||
|
if not self.isEmpty(p,q, self.board):
|
||||||
|
result.append( [p,q] )
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
""" return [animal, oldP, oldQ, newP, newQ], or [animal, None, None, newP, newQ] or [] """
|
||||||
|
|
||||||
|
#the following code just randomly places (ignoring all the rules) some random figure at the board
|
||||||
|
emptyCells = self.getAllEmptyCells()
|
||||||
|
|
||||||
|
if len(emptyCells) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
randomCell = emptyCells[ random.randint(0, len(emptyCells)-1) ]
|
||||||
|
randomP, randomQ = randomCell
|
||||||
|
|
||||||
|
for animal in self.myPieces:
|
||||||
|
if self.myPieces[animal] > 0: #is this animal still available? if so, let's place it
|
||||||
|
return [ animal, None, None, randomP, randomQ ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#all animals are places, let's move some randomly (again, while ignoring all rules)
|
||||||
|
allFigures = self.getAllNonemptyCells()
|
||||||
|
randomCell = allFigures[ random.randint(0, len(allFigures)-1) ]
|
||||||
|
randomFigureP, randomFigureQ = randomCell
|
||||||
|
#determine which animal is at randomFigureP, randomFigureQ
|
||||||
|
animal = self.board[ randomFigureP ][ randomFigureQ ][-1] # [-1] means the last letter
|
||||||
|
return [animal, randomFigureP, randomFigureQ, randomP, randomQ ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def updatePlayers(move, activePlayer, passivePlayer):
|
||||||
|
""" write move made by activePlayer player
|
||||||
|
this method assumes that all moves are correct, no checking is made
|
||||||
|
"""
|
||||||
|
if len(move) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
animal, p,q, newp, newq = move
|
||||||
|
if p == None and q == None:
|
||||||
|
#placing new animal
|
||||||
|
activePlayer.myPieces[animal]-=1
|
||||||
|
passivePlayer.rivalPieces = activePlayer.myPieces.copy()
|
||||||
|
else:
|
||||||
|
#just moving animal
|
||||||
|
#delete its old position
|
||||||
|
activePlayer.board[p][q] = activePlayer.board[p][q][:-1]
|
||||||
|
passivePlayer.board[p][q] = passivePlayer.board[p][q][:-1]
|
||||||
|
|
||||||
|
activePlayer.board[newp][newq] += animal
|
||||||
|
passivePlayer.board[newp][newq] += animal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
boardSize = 13
|
||||||
|
smallFigures = { "q":1, "a":2, "b":2, "s":2, "g":2 } #key is animal, value is how many is available for placing
|
||||||
|
bigFigures = { figure.upper(): smallFigures[figure] for figure in smallFigures } #same, but with upper case
|
||||||
|
|
||||||
|
P1 = Player("player1", False, 13, smallFigures, bigFigures)
|
||||||
|
P2 = Player("player2", True, 13, bigFigures, smallFigures)
|
||||||
|
|
||||||
|
filename = "begin.png"
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
moveIdx = 0
|
||||||
|
while True:
|
||||||
|
|
||||||
|
move = P1.move()
|
||||||
|
print("P1 returned", move)
|
||||||
|
updatePlayers(move, P1, P2) #update P1 and P2 according to the move
|
||||||
|
filename = "move-{:03d}-player1.png".format(moveIdx)
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
|
||||||
|
move = P2.move()
|
||||||
|
print("P2 returned", move)
|
||||||
|
updatePlayers(move, P2, P1) #update P2 and P1 according to the move
|
||||||
|
filename = "move-{:03d}-player2.png".format(moveIdx)
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
moveIdx += 1
|
||||||
|
P1.myMove = moveIdx
|
||||||
|
P2.myMove = moveIdx
|
||||||
|
|
||||||
|
if moveIdx > 50:
|
||||||
|
print("End of the test game")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
128
player_template.py
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
import base as Base
|
||||||
|
import copy, random, time, math
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
|
# Player template for HIVE --- ALP semestral work
|
||||||
|
# Vojta Vonasek, 2023
|
||||||
|
|
||||||
|
|
||||||
|
# PUT ALL YOUR IMPLEMENTATION INTO THIS FILE
|
||||||
|
|
||||||
|
class Player(Base.Board):
|
||||||
|
def __init__(self, playerName, myIsUpper, size, myPieces, rivalPieces): #do not change this line
|
||||||
|
Base.Board.__init__(self, myIsUpper, size, myPieces, rivalPieces) #do not change this line
|
||||||
|
self.playerName = playerName
|
||||||
|
self.algorithmName = "myGreatMethod"
|
||||||
|
|
||||||
|
|
||||||
|
def getAllEmptyCells(self):
|
||||||
|
result = []
|
||||||
|
for p in self.board:
|
||||||
|
for q in self.board[p]:
|
||||||
|
if self.isEmpty(p,q, self.board):
|
||||||
|
result.append( [p,q] )
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def getAllNonemptyCells(self):
|
||||||
|
result = []
|
||||||
|
for p in self.board:
|
||||||
|
for q in self.board[p]:
|
||||||
|
if not self.isEmpty(p,q, self.board):
|
||||||
|
result.append( [p,q] )
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
""" return [animal, oldP, oldQ, newP, newQ], or [animal, None, None, newP, newQ] or [] """
|
||||||
|
|
||||||
|
#the following code just randomly places (ignoring all the rules) some random figure at the board
|
||||||
|
emptyCells = self.getAllEmptyCells()
|
||||||
|
|
||||||
|
if len(emptyCells) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
|
randomCell = emptyCells[ random.randint(0, len(emptyCells)-1) ]
|
||||||
|
randomP, randomQ = randomCell
|
||||||
|
|
||||||
|
for animal in self.myPieces:
|
||||||
|
if self.myPieces[animal] > 0: #is this animal still available? if so, let's place it
|
||||||
|
return [ animal, None, None, randomP, randomQ ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#all animals are places, let's move some randomly (again, while ignoring all rules)
|
||||||
|
allFigures = self.getAllNonemptyCells()
|
||||||
|
randomCell = allFigures[ random.randint(0, len(allFigures)-1) ]
|
||||||
|
randomFigureP, randomFigureQ = randomCell
|
||||||
|
#determine which animal is at randomFigureP, randomFigureQ
|
||||||
|
animal = self.board[ randomFigureP ][ randomFigureQ ][-1] # [-1] means the last letter
|
||||||
|
return [animal, randomFigureP, randomFigureQ, randomP, randomQ ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def updatePlayers(move, activePlayer, passivePlayer):
|
||||||
|
""" write move made by activePlayer player
|
||||||
|
this method assumes that all moves are correct, no checking is made
|
||||||
|
"""
|
||||||
|
if len(move) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
animal, p,q, newp, newq = move
|
||||||
|
if p == None and q == None:
|
||||||
|
#placing new animal
|
||||||
|
activePlayer.myPieces[animal]-=1
|
||||||
|
passivePlayer.rivalPieces = activePlayer.myPieces.copy()
|
||||||
|
else:
|
||||||
|
#just moving animal
|
||||||
|
#delete its old position
|
||||||
|
activePlayer.board[p][q] = activePlayer.board[p][q][:-1]
|
||||||
|
passivePlayer.board[p][q] = passivePlayer.board[p][q][:-1]
|
||||||
|
|
||||||
|
activePlayer.board[newp][newq] += animal
|
||||||
|
passivePlayer.board[newp][newq] += animal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
boardSize = 13
|
||||||
|
smallFigures = { "q":1, "a":2, "b":2, "s":2, "g":2 } #key is animal, value is how many is available for placing
|
||||||
|
bigFigures = { figure.upper(): smallFigures[figure] for figure in smallFigures } #same, but with upper case
|
||||||
|
|
||||||
|
P1 = Player("player1", False, 13, smallFigures, bigFigures)
|
||||||
|
P2 = Player("player2", True, 13, bigFigures, smallFigures)
|
||||||
|
|
||||||
|
filename = "begin.png"
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
moveIdx = 0
|
||||||
|
while True:
|
||||||
|
|
||||||
|
move = P1.move()
|
||||||
|
print("P1 returned", move)
|
||||||
|
updatePlayers(move, P1, P2) #update P1 and P2 according to the move
|
||||||
|
filename = "move-{:03d}-player1.png".format(moveIdx)
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
|
||||||
|
move = P2.move()
|
||||||
|
print("P2 returned", move)
|
||||||
|
updatePlayers(move, P2, P1) #update P2 and P1 according to the move
|
||||||
|
filename = "move-{:03d}-player2.png".format(moveIdx)
|
||||||
|
P1.saveImage(filename)
|
||||||
|
|
||||||
|
moveIdx += 1
|
||||||
|
P1.myMove = moveIdx
|
||||||
|
P2.myMove = moveIdx
|
||||||
|
|
||||||
|
if moveIdx > 50:
|
||||||
|
print("End of the test game")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
90
tile_hard.py
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import base
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class GridManager:
|
||||||
|
# orphans from earlier attempt
|
||||||
|
offsetter = lambda x: x // 2
|
||||||
|
get_internal = lambda index: (index[0] + GridManager.offsetter(index[1]), index[1])
|
||||||
|
get_hex = lambda index: (index[0] - GridManager.offsetter(index[1]), index[1])
|
||||||
|
|
||||||
|
def __init__(self, size):
|
||||||
|
self.grid = [
|
||||||
|
[0 for _ in range(size)] for _ in range(size)
|
||||||
|
] # orphan from earlier attempt
|
||||||
|
self.board = base.Board(size)
|
||||||
|
|
||||||
|
def internalize(self, stones: list) -> list: # orphan from earlier attempt
|
||||||
|
return [list(map(self.get_internal, stone)) for stone in stones]
|
||||||
|
|
||||||
|
def hexize(self, stones: list) -> list: # orphan from earlier attempt
|
||||||
|
return [list(map(self.get_hex, stone)) for stone in stones]
|
||||||
|
|
||||||
|
def place_stones(self, stones: list, placed: list, output_file: str) -> bool:
|
||||||
|
if len(placed) == len(stones):
|
||||||
|
return True
|
||||||
|
curr = stones[len(placed)]
|
||||||
|
color: int = stones.index(curr) + 1
|
||||||
|
for rotation in range(6):
|
||||||
|
for p in range(-self.board.size, self.board.size):
|
||||||
|
for q in range(-self.board.size, self.board.size):
|
||||||
|
if self.board.inBoard(p, q) and self.check(curr, p, q):
|
||||||
|
self.place_stone(curr, color, p, q)
|
||||||
|
placed.append((p, q, rotation))
|
||||||
|
if self.place_stones(stones, placed, output_file):
|
||||||
|
return True
|
||||||
|
self.remove_stone(curr, p, q)
|
||||||
|
placed.pop()
|
||||||
|
curr = self.rotate_stone(curr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rotate_stone(self, stone: list) -> list:
|
||||||
|
rotated_stone = [(self.board.rotateLeft(x, y)) for (x, y) in stone]
|
||||||
|
return rotated_stone
|
||||||
|
|
||||||
|
def check(self, stone: list, *index: (int, int)) -> bool:
|
||||||
|
for cell in stone:
|
||||||
|
x, y = cell
|
||||||
|
if (
|
||||||
|
not self.board.inBoard(index[0] + x, index[1] + y)
|
||||||
|
or self.board.board[index[0] + x][index[1] + y] != 0
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def place_stone(self, stone: list, color: int, *index: (int, int)) -> None:
|
||||||
|
for cell in stone:
|
||||||
|
x, y = cell
|
||||||
|
self.board.board[index[0] + x][index[1] + y] = color
|
||||||
|
|
||||||
|
def remove_stone(self, stone: list, *index: (int, int)) -> None:
|
||||||
|
for cell in stone:
|
||||||
|
x, y = cell
|
||||||
|
self.board.board[index[0] + x][index[1] + y] = 0
|
||||||
|
|
||||||
|
def save_solution(self, output_file: str) -> None:
|
||||||
|
with open(output_file, "w") as f:
|
||||||
|
for p in self.board.board:
|
||||||
|
for q in self.board.board[p]:
|
||||||
|
f.write("{} {} {}\n".format(p, q, self.board.board[p][q]))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
size: int = int(sys.argv[1])
|
||||||
|
gm: GridManager = GridManager(size)
|
||||||
|
stones: list = base.loadStones(sys.argv[2])
|
||||||
|
output_file: str = sys.argv[3]
|
||||||
|
placed_stones: list = []
|
||||||
|
tilesAmount: int = 0
|
||||||
|
totalSize: int = size**2
|
||||||
|
for stone in stones:
|
||||||
|
tilesAmount += len(stone)
|
||||||
|
if (
|
||||||
|
gm.place_stones(stones, placed_stones, output_file) == False
|
||||||
|
or tilesAmount != totalSize
|
||||||
|
):
|
||||||
|
with open(output_file, "w") as f:
|
||||||
|
f.write("NOSOLUTION")
|
||||||
|
else:
|
||||||
|
# gm.board.saveImage("img.png")
|
||||||
|
gm.save_solution(output_file)
|