169 lines
4.3 KiB
Python
169 lines
4.3 KiB
Python
#!/usr/bin/env python
|
|
|
|
import capnp
|
|
import state_capnp as game
|
|
|
|
|
|
class State():
|
|
|
|
def initBoard(self):
|
|
self.board = [[None]*6 for _ in range(6)]
|
|
|
|
for card in self.state.cardlist:
|
|
if (card.location.board):
|
|
x = card.location.board.x
|
|
y = card.location.board.y
|
|
self.board[x][y] = card
|
|
|
|
def __init__(self, state):
|
|
self.state = state
|
|
self.initBoard()
|
|
pass
|
|
|
|
def findVarys(self):
|
|
for card in self.state.cardlist:
|
|
if card.house == 'varys':
|
|
return card.location
|
|
|
|
def getPossibleMoves(self):
|
|
moves = []
|
|
|
|
for x in xrange(0, 5):
|
|
for y in xrange(0, 5):
|
|
|
|
if (self.isLegalMoveLocation(x, y)):
|
|
moves.append((x, y))
|
|
|
|
return moves
|
|
|
|
def isLegalMoveLocation(self, x, y):
|
|
varys = self.findVarys()
|
|
vx = varys.board.x
|
|
vy = varys.board.y
|
|
|
|
# Row/Column must match
|
|
if (vx == x and vy == y):
|
|
return False
|
|
if (vx == x):
|
|
# Generate all y between y and vy
|
|
# See if this is the furthest for this card type
|
|
# newCardType = self.board
|
|
if (vy > y):
|
|
l = [(x, i) for i in range(0, vy)]
|
|
else:
|
|
l = [(x, i) for i in range(vy+1, 6)]
|
|
l.reverse()
|
|
elif (vy == y):
|
|
# Generate all x between x and vx
|
|
if (vx > x):
|
|
l = [(i, y) for i in range(0, vx)]
|
|
else:
|
|
l = [(i, y) for i in range(vx+1, 6)]
|
|
l.reverse()
|
|
pass
|
|
else:
|
|
return False
|
|
|
|
seen = {}
|
|
|
|
for (xx, yy) in l:
|
|
house = self.board[xx][yy].house
|
|
if str(house) in seen:
|
|
return False
|
|
|
|
# We stop testing as soon as we reach the new location
|
|
if (x == xx and y == yy):
|
|
return True
|
|
seen[str(house)] = True
|
|
|
|
|
|
class GameNode(object):
|
|
"""docstring for GameNode"""
|
|
|
|
def __init__(self, state, parent):
|
|
super(GameNode, self).__init__()
|
|
self.state = state
|
|
self.parent = parent
|
|
|
|
self.hits = 0
|
|
self.misses = 0
|
|
self.totalTrials = 0
|
|
|
|
def backPropagate(self, simulation):
|
|
if (simulation > 0):
|
|
self.hits += 1
|
|
elif (simulation < 0):
|
|
self.misses += 1
|
|
self.totalTrials += 1
|
|
|
|
if self.parent:
|
|
self.parent.backPropagate(-simulation)
|
|
|
|
def childPotential(self, child):
|
|
w = child.misses
|
|
n = child.totalTrials
|
|
|
|
# Chosen empirically
|
|
c = math.sqrt(2)
|
|
t = self.totalTrials
|
|
|
|
return (w / n) + (c * math.sqrt(log(t) / n))
|
|
|
|
def runSimulation(self):
|
|
self.backPropagate(self.simulate())
|
|
|
|
def getChildren(self):
|
|
possibleMoves = self.state.getPossibleMoves()
|
|
children = []
|
|
|
|
for move in possibleMoves:
|
|
newState = self.state.playMove(move)
|
|
childNode = GameNode(newState, self.state)
|
|
children.append(childNode)
|
|
|
|
return children
|
|
|
|
def chooseChild(self):
|
|
# Define children nodes
|
|
if(not self.children):
|
|
self.children = self.getChildren()
|
|
|
|
# Run simulation on leaf nodes
|
|
if(len(self.children) == 0):
|
|
self.runSimulation()
|
|
else:
|
|
unexplored = []
|
|
|
|
# Get all unexplored nodes
|
|
for child in self.children:
|
|
if (child.totalTrials == 0):
|
|
unexplored.append(child)
|
|
|
|
# Pick a random unexplored node
|
|
# and run the simulation on it
|
|
if (len(unexplored) > 0):
|
|
random.choice(unexplored).runSimulation()
|
|
else:
|
|
# Find the best child
|
|
bestChild = self.children[0]
|
|
bestPotential = self.childPotential(bestChild)
|
|
|
|
for child in self.children:
|
|
potential = self.childPotential(child)
|
|
|
|
if (potential > bestPotential):
|
|
bestPotential = potential
|
|
bestChild = child
|
|
|
|
bestChild.chooseChild()
|
|
|
|
|
|
f = open('state.bin', 'rb')
|
|
initial_state = game.State.read_packed(f)
|
|
|
|
# print(initial_state)
|
|
s = State(initial_state)
|
|
print(s.getPossibleMoves())
|
|
|
|
# 3,2
|