Skip to content
Snippets Groups Projects
Commit ac335e7c authored by Sam Moore's avatar Sam Moore
Browse files

[PATCH] Remove arguments, patch vixen, add hunter AI

The arguments stuff has been causing errors for everyone.
No one uses arguments for their AI, so I removed it.

sulix now beats vixen, so I have patched it to not make illegal moves.

hunter uses the same sort of idea as vixen, but seems to do slightly better.

Enjoy
[SZM]
parent 7c42b4b7
Branches
Tags
No related merge requests found
......@@ -32,7 +32,7 @@ class PathFinder:
up = (start[0], start[1]-1)
down = (start[0], start[1]+1)
choices = [left, right, up, down]
choices.sort(key = lambda e : random.randint(0,5))
choices.sort(key = lambda e : (e[0] - end[0])**2.0 + (e[1] - end[1])**2.0 )
options = []
for point in choices:
option = [point, self.pathFind(point,end,board)]
......
#!/usr/bin/python -u
#NOTE: The -u option is required for unbuffered stdin/stdout.
# If stdin/stdout are buffered, the manager program will not recieve any messages and assume that the agent has timed out.
"""
basic_python.py - A sample Stratego AI for the UCC Programming Competition 2012
Written in python, the slithery language
Simply makes random moves, as long as possible
author Sam Moore (matches) [SZM]
website http://matches.ucc.asn.au/stratego
email progcomp@ucc.asn.au or matches@ucc.asn.au
git git.ucc.asn.au/progcomp2012.git
"""
import sys
import random
ranks = ['B','1','2','3','4','5','6','7','8','9','s','F', '?', '+']
def is_integer(s):
""" Using exceptions for this feels... wrong..."""
try:
int(s)
return True
except ValueError:
return False
def move(x, y, direction, multiplier):
""" Moves point (x,y) in direction, returns a pair """
if direction == "UP":
return (x,y-multiplier)
elif direction == "DOWN":
return (x,y+multiplier)
elif direction == "LEFT":
return (x-multiplier, y)
elif direction == "RIGHT":
return (x+multiplier, y)
return (x,y)
def oppositeColour(colour):
""" Returns the opposite colour to that given """
if colour == "RED":
return "BLUE"
elif colour == "BLUE":
return "RED"
else:
return "NONE"
class Piece:
""" Class representing a piece
Pieces have colour, rank and co-ordinates
"""
def __init__(self, colour, rank, x, y):
self.colour = colour
self.rank = rank
self.x = x
self.y = y
self.lastMoved = -1
self.beenRevealed = False
self.positions = [(x, y)]
def copy(self):
p = Piece(self.colour, self.rank, self.x, self.y)
p.lastMoved = self.lastMoved
p.beenRevealed = self.beenRevealed
p.positions = []
for pos in self.positions:
p.positions.append((pos[0], pos[1]))
return p
def mobile(self):
return self.rank != 'F' and self.rank != 'B' and self.rank != '?' and self.rank != '+'
def valuedRank(self):
if ranks.count(self.rank) > 0:
return len(ranks) - 2 - ranks.index(self.rank)
else:
return 0
def valuedRank(rank):
if ranks.count(rank) > 0 and rank != '?':
return len(ranks) - 2 - ranks.index(rank)
else:
return 0
class BasicAI:
"""
BasicAI class to play a game of stratego
Implements the protocol correctly. Stores the state of the board in self.board
Only makes random moves.
Override method "MakeMove" for more complex moves
"""
def __init__(self):
""" Constructs the BasicAI agent, and starts it playing the game """
#sys.stderr.write("BasicAI __init__ here...\n");
self.turn = 0
self.board = []
self.units = []
self.enemyUnits = []
self.totalAllies = {'B':6,'1':1,'2':1,'3':2,'4':3,'5':4,'6':4,'7':4,'8':5,'9':8,'s':1,'F':1}
self.totalEnemies = {'B':6,'1':1,'2':1,'3':2,'4':3,'5':4,'6':4,'7':4,'8':5,'9':8,'s':1,'F':1}
self.hiddenEnemies = {'B':6,'1':1,'2':1,'3':2,'4':3,'5':4,'6':4,'7':4,'8':5,'9':8,'s':1,'F':1}
self.hiddenAllies = {'B':6,'1':1,'2':1,'3':2,'4':3,'5':4,'6':4,'7':4,'8':5,'9':8,'s':1,'F':1}
self.lastMoved = None
def LegalPosition(self, x, y):
return x >= 0 and y >= 0 and x < len(self.board) and y < len(self.board[x])
def Setup(self):
""" Implements Setup part of protocol. Always uses the same setup. Override to create custom setups """
#sys.stderr.write("BasicAI Setup here...\n");
setup = sys.stdin.readline().split(' ')
if len(setup) != 4:
sys.stderr.write("BasicAI setup fails, expected 4 tokens, got " + str(len(setup)) + " "+str(setup) + "\n")
self.colour = setup[0]
self.opponentName = setup[1]
self.width = int(setup[2])
self.height = int(setup[3])
for x in range(0, self.width):
self.board.append([])
for y in range(0, self.height):
self.board[x].append(None)
if self.colour == "RED":
print "FB8sB479B8\nBB31555583\n6724898974\n967B669999"
elif self.colour == "BLUE":
print "967B669999\n6724898974\nBB31555583\nFB8sB479B8"
return True
def MoveCycle(self):
#sys.stderr.write("BasicAI MakeMove here...\n");
if self.InterpretResult() == False or self.ReadBoard() == False or self.MakeMove() == False:
return False
self.turn += 1
return self.InterpretResult()
def MakeMove(self):
""" Randomly moves any moveable piece, or prints "NO_MOVE" if there are none """
#TODO: Over-ride this function in base classes with more complex move behaviour
#sys.stderr.write("BasicAI MakeMove here...\n")
#self.debugPrintBoard()
if len(self.units) <= 0:
return False
index = random.randint(0, len(self.units)-1)
startIndex = index
directions = ("UP", "DOWN", "LEFT", "RIGHT")
while True:
piece = self.units[index]
if piece != None and piece.mobile():
dirIndex = random.randint(0, len(directions)-1)
startDirIndex = dirIndex
while True:
#sys.stderr.write("Trying index " + str(dirIndex) + "\n")
p = move(piece.x, piece.y, directions[dirIndex],1)
if p[0] >= 0 and p[0] < self.width and p[1] >= 0 and p[1] < self.height:
target = self.board[p[0]][p[1]]
if target == None or (target.colour != piece.colour and target.colour != "NONE" and target.colour != "BOTH"):
print str(piece.x) + " " + str(piece.y) + " "+directions[dirIndex]
return True
dirIndex = (dirIndex + 1) % len(directions)
if startDirIndex == dirIndex:
break
index = (index + 1) % len(self.units)
if startIndex == index:
print "NO_MOVE"
return True
def ReadBoard(self):
""" Reads in the board.
On the very first turn, sets up the self.board structure
On subsequent turns, the board is simply read, but the self.board structure is not updated here.
"""
#sys.stderr.write("BasicAI ReadBoard here...\n");
for y in range(0,self.height):
row = sys.stdin.readline().strip()
if len(row) < self.width:
sys.stderr.write("Row has length " + str(len(row)) + " vs " + str(self.width) + "\n")
return False
for x in range(0,self.width):
if self.turn == 0:
if row[x] == '.':
pass
elif row[x] == '#':
self.board[x][y] = Piece(oppositeColour(self.colour), '?',x,y)
self.enemyUnits.append(self.board[x][y])
elif row[x] == '+':
self.board[x][y] = Piece("NONE", '+', x, y)
else:
self.board[x][y] = Piece(self.colour, row[x],x,y)
self.units.append(self.board[x][y])
else:
pass
return True
def InterpretResult(self, string = None):
""" Interprets the result of a move, and updates the board.
The very first move is ignored.
On subsequent moves, the self.board structure is updated
"""
#sys.stderr.write("BasicAI InterpretResult here...\n")
if string == None:
string = sys.stdin.readline()
result = string.split(' ')
#sys.stderr.write(" Read status line \"" + str(result) + "\"\n")
if self.turn == 0:
return True
if result[0].strip() == "QUIT": #Make sure we exit when the manager tells us to!
return False
if result[0].strip() == "NO_MOVE": #No move was made, don't need to update anything
return True
if len(result) < 4: #Should be at least 4 tokens (X Y DIRECTION OUTCOME) in any other case
return False
x = int(result[0].strip())
y = int(result[1].strip())
#sys.stderr.write(" Board position " + str(x) + " " + str(y) + " is OK!\n")
direction = result[2].strip()
multiplier = 1
outcome = result[3].strip()
outIndex = 3
if is_integer(outcome):
multiplier = int(outcome)
outcome = result[4].strip()
outIndex = 4
p = move(x,y,direction, multiplier)
#Determine attacking piece
attacker = self.board[x][y]
self.board[x][y] = None
if attacker == None:
return False
lastMoved = attacker
defender = self.board[p[0]][p[1]]
#Update attacker's position (Don't overwrite the board yet though)
attacker.x = p[0]
attacker.y = p[1]
attacker.positions.insert(0, (attacker.x, attacker.y))
#Determine ranks of pieces if supplied
if len(result) >= outIndex + 3:
if defender == None:
return False
attacker.rank = result[outIndex+1].strip()
if attacker.beenRevealed == False:
if attacker.colour == self.colour:
self.hiddenAllies[attacker.rank] -= 1
elif attacker.colour == oppositeColour(self.colour):
self.hiddenEnemies[attacker.rank] -= 1
attacker.beenRevealed = True
defender.rank = result[outIndex+2].strip()
if defender.beenRevealed == False:
if defender.colour == self.colour:
self.hiddenAllies[defender.rank] -= 1
elif defender.colour == oppositeColour(self.colour):
self.hiddenEnemies[defender.rank] -= 1
defender.beenRevealed = True
if outcome == "OK":
self.board[p[0]][p[1]] = attacker
elif outcome == "KILLS":
self.board[p[0]][p[1]] = attacker
if defender.colour == self.colour:
self.totalAllies[defender.rank] -= 1
self.units.remove(defender)
elif defender.colour == oppositeColour(self.colour):
self.totalEnemies[defender.rank] -= 1
self.enemyUnits.remove(defender)
elif outcome == "DIES":
if attacker.colour == self.colour:
self.totalAllies[attacker.rank] -= 1
self.units.remove(attacker)
elif attacker.colour == oppositeColour(self.colour):
self.totalEnemies[attacker.rank] -= 1
self.enemyUnits.remove(attacker)
elif outcome == "BOTHDIE":
self.board[p[0]][p[1]] = None
if defender.colour == self.colour:
self.totalAllies[defender.rank] -= 1
self.units.remove(defender)
elif defender.colour == oppositeColour(self.colour):
self.totalEnemies[defender.rank] -= 1
self.enemyUnits.remove(defender)
if attacker.colour == self.colour:
self.totalAllies[attacker.rank] -= 1
self.units.remove(attacker)
elif attacker.colour == oppositeColour(self.colour):
self.totalEnemies[attacker.rank] -= 1
self.enemyUnits.remove(attacker)
elif outcome == "FLAG":
#sys.stderr.write(" Game over!\n")
return False
elif outcome == "ILLEGAL":
#sys.stderr.write(" Illegal move!\n")
return False
else:
#sys.stderr.write(" Don't understand outcome \"" + outcome + "\"!\n");
return False
#sys.stderr.write(" Completed interpreting move!\n");
return True
def debugPrintBoard(self):
""" For debug purposes only. Prints the board to stderr.
Does not indicate difference between allied and enemy pieces
Unknown (enemy) pieces are shown as '?'
"""
for y in range(0, self.height):
for x in range(0, self.width):
if self.board[x][y] == None:
sys.stderr.write(".");
else:
sys.stderr.write(str(self.board[x][y].rank));
sys.stderr.write("\n")
if __name__ == "__main__":
basicAI = BasicAI()
if basicAI.Setup():
while basicAI.MoveCycle():
pass
9 10 9 8 7 6 5 4 9 2 5 9
#!/usr/bin/python -u
#NOTE: The -u option is required for unbuffered stdin/stdout.
# If stdin/stdout are buffered, the manager program will not recieve any messages and assume that the agent has timed out.
'''
khaos.py - A sample Stratego AI for the UCC Programming Competition 2012
The name describes the state of this file :S
Written in python, the slithery language
author Sam Moore (matches) [SZM]
website http://matches.ucc.asn.au/stratego
email progcomp@ucc.asn.au or matches@ucc.asn.au
git git.ucc.asn.au/progcomp2012.git
'''
import os
from basic_python import *
from path import *
def OppositeDirection(direction):
if direction == "UP":
return "DOWN"
elif direction == "DOWN":
return "UP"
elif direction == "LEFT":
return "RIGHT"
elif direction == "RIGHT":
return "LEFT"
else:
assert(False)
return "ERROR"
class Hunter(BasicAI):
" Python based AI of DEATH "
def __init__(self, scoresFilename=None):
if scoresFilename == None:
scoresFilename = "default.scores"
BasicAI.__init__(self)
scoresFile = open(scoresFilename, "r")
self.scoreTable = []
for i in scoresFile.readline().strip().split(' '):
self.scoreTable.append(float(i))
scoresFile.close()
self.maxdepth = 1
self.recursiveConsider = {"allies" : 2, "enemies" : 2}
self.paths = {}
def PositionLegal(self, x, y, unit = None):
if x >= 0 and x < len(self.board) and y >= 0 and y < len(self.board[x]):
if unit == None:
return True
else:
return self.board[x][y] == None or self.board[x][y].colour == oppositeColour(unit.colour)
else:
return False
def BestMove(self, maxdepth = 1):
moveList = []
if maxdepth < self.maxdepth:
#sys.stderr.write("Recurse!\n")
considerAllies = self.recursiveConsider["allies"]
considerEnemies = self.recursiveConsider["enemies"]
else:
considerAllies = len(self.units)+1
considerEnemies = len(self.enemyUnits)+1
for enemy in self.enemyUnits[0:considerEnemies]:
for ally in self.units[0:considerAllies]:
moveList.append(self.DesiredMove(ally, enemy))
for desiredMove in moveList:
if desiredMove[0] == "NO_MOVE" or desiredMove[2] == None:
desiredMove[1] = -2.0
if maxdepth > 1:
for desiredMove in moveList:
if desiredMove[2] == None or desiredMove[1] < 0.0:
continue
p = move(desiredMove[3].x, desiredMove[3].y, desiredMove[2][0], 1)
if self.board[p[0]][p[1]] == None:
x = desiredMove[3].x
y = desiredMove[3].y
result = desiredMove[0] + " OK"
self.InterpretResult(result)
bestRecurse = self.BestMove(maxdepth-1)
if bestRecurse != None:
desiredMove[1] += bestRecurse[1]# / float(max(1.0, maxdepth))
self.board[desiredMove[3].x][desiredMove[3].y] = None
self.board[x][y] = desiredMove[3]
desiredMove[3].x = x
desiredMove[3].y = y
if len(moveList) <= 0:
return None
moveList.sort(key = lambda e : e[1], reverse = True)
return moveList[0]
def GetPath(self, ally, enemy):
#Attempts to do the minimum required work to reconstruct a path
return PathFinder().pathFind((ally.x, ally.y), (enemy.x, enemy.y), self.board)
if (ally in self.paths.keys()) == False:
self.paths.update({ally : {}})
#sys.stderr.write("Update keys are " + str(self.paths.keys()) + "\n")
#sys.stderr.write("Keys are " + str(self.paths.keys()) + "\n")
if (enemy in self.paths[ally].keys()) == False: #No path exists; compute a new one
path = PathFinder().pathFind((ally.x, ally.y), (enemy.x, enemy.y), self.board)
if path != False:
self.paths[ally].update({enemy : [path, (ally.x, ally.y), (enemy.x, enemy.y)]})
return path
oldPath = self.paths[ally][enemy]
if oldPath[1][0] != ally.x or oldPath[1][1] != ally.y or oldPath[2][0] != enemy.x or oldPath[2][1] != enemy.y:
#The pieces involved have moved. Recompute the path
path = PathFinder().pathFind((ally.x, ally.y), (enemy.x, enemy.y), self.board)
if path != False:
self.paths[ally][enemy] = [path, (ally.x, ally.y), (enemy.x, enemy.y)]
return path
if len(oldPath[0]) > 1:
#The pieces involved haven't moved, check to see if the path is blocked
p = move(ally.x, ally.y, oldPath[0][0], 1) #Look forward one move
if self.PositionLegal(p[0], p[1]) and self.board[p[0]][p[1]] != None: #If the position is blocked...
path = PathFinder().pathFind((ally.x, ally.y), (enemy.x, enemy.y), self.board) #Compute new path
if path != False:
self.paths[ally][enemy] = [path, (ally.x, ally.y), (enemy.x, enemy.y)]
return path
return False
def DesiredMove(self, ally, enemy):
""" Determine desired move of allied piece, towards or away from enemy, with score value """
scaleFactor = 1.0
if ally.rank == 'F' or ally.rank == 'B':
return ["NO_MOVE", 0, None, ally, enemy]
actionScores = {"ATTACK" : 0, "RETREAT" : 0}
if enemy.rank == '?':
for i in range(0, len(ranks)):
prob = self.rankProbability(enemy, ranks[i])
if prob > 0:
desiredAction = self.DesiredAction(ally, ranks[i])
actionScores[desiredAction[0]] += prob* (desiredAction[1] / 2.0)
if len(enemy.positions) <= 1 and ally.rank != '8':
scaleFactor *= (1.0 - float(valuedRank(ally.rank)) / float(valuedRank('1')))**2.0
elif len(enemy.positions) > 1 and ally.rank == '8':
scaleFactor *= 0.05
#elif len(enemy.positions) > 1:
# scaleFactor *= (1.0 - float(valuedRank(ally.rank)) / float(valuedRank('1')))**0.25
# scaleFactor = max(0.05, scaleFactor)
else:
desiredAction = self.DesiredAction(ally, enemy.rank)
actionScores[desiredAction[0]] += desiredAction[1]
desiredAction = sorted(actionScores.items(), key = lambda e : e[1], reverse = True)[0]
direction = None
path = self.GetPath(ally, enemy)
if path != False and len(path) > 0:
if desiredAction[0] == "RETREAT":
#sys.stderr.write("Recommend retreat! "+ally.rank + " from " + enemy.rank+"\n")
direction = OppositeDirection(path[0])
p = move(ally.x, ally.y, direction, 1)
if self.PositionLegal(p[0], p[1], ally) == False:
path = None
scaleFactor = 0.05 * scaleFactor
else:
direction = path[0]
if desiredAction[1] > 0.0 and path != None:
scaleFactor = scaleFactor / float(len(path))
return [str(ally.x) + " " + str(ally.y) + " " + direction, desiredAction[1] * scaleFactor, path, ally, enemy]
#directions = {"RIGHT" : enemy.x - ally.x, "LEFT" : ally.x - enemy.x, "DOWN" : enemy.y - ally.y, "UP" : ally.y - enemy.y}
#if desiredAction[0] == "RETREAT":
# for key in directions.keys():
# directions[key] = -directions[key]
#while direction == None:
# d = sorted(directions.items(), key = lambda e : e[1], reverse = True)
# p = move(ally.x, ally.y, d[0][0], 1)
# if self.PositionLegal(p[0], p[1]) and (self.board[p[0]][p[1]] == None or self.board[p[0]][p[1]] == enemy):
# direction = d[0][0]
# scaleFactor *= (1.0 - float(max(d[0][1], 0.0)) / 10.0)**2.0
# else:
# del directions[d[0][0]]
# if len(directions.keys()) <= 0:
# break
if abs(enemy.x - ally.x) >= abs(enemy.y - ally.y):
if enemy.x > ally.x:
direction = "RIGHT"
elif enemy.x < ally.x:
direction = "LEFT"
else:
if enemy.y > ally.y:
direction = "DOWN"
elif enemy.y < ally.y:
direction = "UP"
if direction == None:
return ["NO_MOVE", 0, [], ally, enemy]
return [str(ally.x) + " " + str(ally.y) + " " + direction, desiredAction[1], None, ally, enemy]
def DesiredAction(self, ally, enemyRank):
if enemyRank == 'F':
return ["ATTACK", 1.0]
if ally.rank == '8' and enemyRank == 'B':
return ["ATTACK", 0.9]
if ally.rank == '1' and enemyRank == 's':
return ["RETREAT", 0.9]
if ally.rank == 's' and enemyRank == '1':
return ["ATTACK", 0.6]
if enemyRank == 'B':
return ["RETREAT", 0.0]
if ally.rank == enemyRank:
return ["ATTACK", 0.1]
if valuedRank(ally.rank) > valuedRank(enemyRank):
return ["ATTACK", float(self.scoreTable[ranks.index(enemyRank)]) * (0.1 + 1.0/float(self.scoreTable[ranks.index(ally.rank)]))]
else:
return ["RETREAT", float(self.scoreTable[ranks.index(ally.rank)]) / 10.0]
def MakeMove(self):
if len(self.units) < 20:
self.maxdepth = 1
bestMove = self.BestMove(self.maxdepth)
if bestMove == None:
#sys.stderr.write("Khaos makes random move!\n")
return BasicAI.MakeMove(self)
#sys.stderr.write("Board state before move: \n")
#self.debugPrintBoard()
#sys.stderr.write("Best move is \"" + bestMove[0] + "\" with score " + str(bestMove[1]) + " as part of path " +str(bestMove[2]) + " ...\n")
#sys.stderr.write(" Ally with rank " + bestMove[3].rank + " is targeting unit at " + str((bestMove[4].x, bestMove[4].y)) + " rank " + bestMove[4].rank + "\n")
sys.stdout.write(bestMove[0] + "\n")
#self.paths[bestMove[3]][bestMove[4]].pop(0)
return True
def rankProbability(self, target, targetRank):
if targetRank == '+' or targetRank == '?':
return 0.0
if target.rank == targetRank:
return 1.0
elif target.rank != '?':
return 0.0
total = 0.0
for rank in ranks:
if rank == '+' or rank == '?':
continue
elif rank == 'F' or rank == 'B':
if target.lastMoved < 0:
total += self.hiddenEnemies[rank]
else:
total += self.hiddenEnemies[rank]
if total == 0.0:
return 0.0
return float(float(self.hiddenEnemies[targetRank]) / float(total))
def InterpretResult(self, string=None):
if BasicAI.InterpretResult(self, string) == False:
return False
if self.maxdepth > 1:
if self.lastMoved != None and self.lastMoved.colour == self.colour and self.lastMoved.alive == False:
self.units.sort(key = lambda e : valuedRank(e.rank), reverse = True)
elif self.lastMoved != None and self.lastMoved.colour == oppositeColour(self.colour) and self.lastMoved.alive == True:
oldRank = self.lastMoved.rank
self.lastMoved.rank = '1'
self.enemyUnits.sort(key = lambda e : valuedRank(e.rank), reverse = True)
self.lastMoved.rank = oldRank
return True
if __name__ == "__main__":
if len(sys.argv) > 1:
hunter = Hunter(sys.argv[1])
else:
string = ""
path = sys.argv[0].split('/')
for i in range(0, len(path)-1):
string += path[i] + "/"
string += "default.scores"
hunter = Hunter(string)
if hunter.Setup():
while hunter.MoveCycle():
pass
#!/usr/bin/python -u
#NOTE: The -u option is required for unbuffered stdin/stdout.
# If stdin/stdout are buffered, the manager program will not recieve any messages and assume that the agent has timed out.
'''
khaos.py - A sample Stratego AI for the UCC Programming Competition 2012
The name describes the state of this file :S
Written in python, the slithery language
author Sam Moore (matches) [SZM]
website http://matches.ucc.asn.au/stratego
email progcomp@ucc.asn.au or matches@ucc.asn.au
git git.ucc.asn.au/progcomp2012.git
'''
import os
from basic_python import *
from path import *
def OppositeDirection(direction):
if direction == "UP":
return "DOWN"
elif direction == "DOWN":
return "UP"
elif direction == "LEFT":
return "RIGHT"
elif direction == "RIGHT":
return "LEFT"
else:
assert(False)
return "ERROR"
class Hunter(BasicAI):
" Python based AI of DEATH "
def __init__(self, scoresFilename=None):
if scoresFilename == None:
scoresFilename = "default.scores"
BasicAI.__init__(self)
scoresFile = open(scoresFilename, "r")
self.scoreTable = []
for i in scoresFile.readline().strip().split(' '):
self.scoreTable.append(float(i))
scoresFile.close()
self.maxdepth = 1
self.recursiveConsider = {"allies" : 5, "enemies" : 5}
def PositionLegal(self, x, y, unit = None):
if x >= 0 and x < len(self.board) and y >= 0 and y < len(self.board[x]):
if unit == None:
return True
else:
return self.board[x][y] == None or self.board[x][y].colour == oppositeColour(unit.colour)
else:
return False
def BestMove(self, maxdepth = 1):
moveList = []
if maxdepth < self.maxdepth:
#sys.stderr.write("Recurse!\n")
considerAllies = self.recursiveConsider["allies"]
considerEnemies = self.recursiveConsider["enemies"]
else:
considerAllies = len(self.units)+1
considerEnemies = len(self.enemyUnits)+1
for enemy in self.enemyUnits[0:considerEnemies]:
for ally in self.units[0:considerAllies]:
moveList.append(self.DesiredMove(ally, enemy))
for desiredMove in moveList:
if desiredMove[0] == "NO_MOVE" or desiredMove[2] == None:
desiredMove[1] = -2.0
if maxdepth > 1:
for desiredMove in moveList:
if desiredMove[2] == None or desiredMove[1] < 0.0:
continue
p = move(desiredMove[3].x, desiredMove[3].y, desiredMove[2][0], 1)
if self.board[p[0]][p[1]] == None:
x = desiredMove[3].x
y = desiredMove[3].y
result = desiredMove[0] + " OK"
self.InterpretResult(result)
bestRecurse = self.BestMove(maxdepth-1)
if bestRecurse != None:
desiredMove[1] += bestRecurse[1]# / float(max(1.0, maxdepth))
self.board[desiredMove[3].x][desiredMove[3].y] = None
self.board[x][y] = desiredMove[3]
desiredMove[3].x = x
desiredMove[3].y = y
for desiredMove in moveList:
if desiredMove[1] > 0.0:
desiredMove[1] = desiredMove[1] / float(len(desiredMove[2]))
if len(moveList) <= 0:
return None
moveList.sort(key = lambda e : e[1], reverse = True)
return moveList[0]
def DesiredMove(self, ally, enemy):
""" Determine desired move of allied piece, towards or away from enemy, with score value """
scaleFactor = 1.0
if ally.rank == 'F' or ally.rank == 'B':
return ["NO_MOVE", 0, None, ally, enemy]
actionScores = {"ATTACK" : 0, "RETREAT" : 0}
if enemy.rank == '?':
for i in range(0, len(ranks)):
prob = self.rankProbability(enemy, ranks[i])
if prob > 0:
desiredAction = self.DesiredAction(ally, ranks[i])
actionScores[desiredAction[0]] += prob* (desiredAction[1] / 2.0)
if len(enemy.positions) <= 1 and ally.rank != '8':
scaleFactor *= (1.0 - float(valuedRank(ally.rank)) / float(valuedRank('1')))**2.0
elif len(enemy.positions) > 1 and ally.rank == '8':
scaleFactor *= 0.05
#elif len(enemy.positions) > 1:
# scaleFactor *= (1.0 - float(valuedRank(ally.rank)) / float(valuedRank('1')))**0.25
# scaleFactor = max(0.05, scaleFactor)
else:
desiredAction = self.DesiredAction(ally, enemy.rank)
actionScores[desiredAction[0]] += desiredAction[1]
desiredAction = sorted(actionScores.items(), key = lambda e : e[1], reverse = True)[0]
direction = None
#path = PathFinder().pathFind((ally.x, ally.y), (enemy.x, enemy.y), self.board)
#if path != False and len(path) > 0:
# if desiredAction[0] == "RETREAT":
#sys.stderr.write("Recommend retreat! "+ally.rank + " from " + enemy.rank+"\n")
# direction = OppositeDirection(path[0])
# p = move(ally.x, ally.y, direction, 1)
# if self.PositionLegal(p[0], p[1], ally) == False:
# path = None
# scaleFactor = 0.05 * scaleFactor
# else:
# direction = path[0]
# return [str(ally.x) + " " + str(ally.y) + " " + direction, desiredAction[1] * scaleFactor, path, ally, enemy]
directions = {"RIGHT" : enemy.x - ally.x, "LEFT" : ally.x - enemy.x, "DOWN" : enemy.y - ally.y, "UP" : ally.y - enemy.y}
if desiredAction[0] == "RETREAT":
for key in directions.keys():
directions[key] = -directions[key]
while direction == None:
d = sorted(directions.items(), key = lambda e : e[1], reverse = True)
p = move(ally.x, ally.y, d[0][0], 1)
if self.PositionLegal(p[0], p[1]) and (self.board[p[0]][p[1]] == None or self.board[p[0]][p[1]] == enemy):
direction = d[0][0]
scaleFactor *= (1.0 - float(max(d[0][1], 0.0)) / 10.0)**2.0
else:
del directions[d[0][0]]
if len(directions.keys()) <= 0:
break
#if abs(enemy.x - ally.x) >= abs(enemy.y - ally.y):
# if enemy.x > ally.x:
# direction = "RIGHT"
# elif enemy.x < ally.x:
#
#else:
# if enemy.y > ally.y:
# direction = "DOWN"
# elif enemy.y < ally.y:
# direction = "UP"
if direction == None:
return ["NO_MOVE", 0, [], ally, enemy]
return [str(ally.x) + " " + str(ally.y) + " " + direction, desiredAction[1], [direction], ally, enemy]
def DesiredAction(self, ally, enemyRank):
if enemyRank == 'F':
return ["ATTACK", 1.0]
if ally.rank == '8' and enemyRank == 'B':
return ["ATTACK", 0.9]
if ally.rank == '1' and enemyRank == 's':
return ["RETREAT", 0.9]
if ally.rank == 's' and enemyRank == '1':
return ["ATTACK", 0.6]
if enemyRank == 'B':
return ["RETREAT", 0.0]
if ally.rank == enemyRank:
return ["ATTACK", 0.1]
if valuedRank(ally.rank) > valuedRank(enemyRank):
return ["ATTACK", float(self.scoreTable[ranks.index(enemyRank)]) * (0.1 + 1.0/float(self.scoreTable[ranks.index(ally.rank)]))]
else:
return ["RETREAT", float(self.scoreTable[ranks.index(ally.rank)]) / 10.0]
def MakeMove(self):
if len(self.units) < 20:
self.maxdepth = 1
bestMove = self.BestMove(self.maxdepth)
if bestMove == None:
#sys.stderr.write("Khaos makes random move!\n")
return BasicAI.MakeMove(self)
#sys.stderr.write("Board state before move: \n")
#self.debugPrintBoard()
sys.stderr.write("Best move is \"" + bestMove[0] + "\" with score " + str(bestMove[1]) + " as part of path " +str(bestMove[2]) + " ...\n")
sys.stderr.write(" Ally with rank " + bestMove[3].rank + " is targeting unit at " + str((bestMove[4].x, bestMove[4].y)) + " rank " + bestMove[4].rank + "\n")
sys.stdout.write(bestMove[0] + "\n")
return True
def rankProbability(self, target, targetRank):
if targetRank == '+' or targetRank == '?':
return 0.0
if target.rank == targetRank:
return 1.0
elif target.rank != '?':
return 0.0
total = 0.0
for rank in ranks:
if rank == '+' or rank == '?':
continue
elif rank == 'F' or rank == 'B':
if target.lastMoved < 0:
total += self.hiddenEnemies[rank]
else:
total += self.hiddenEnemies[rank]
if total == 0.0:
return 0.0
return float(float(self.hiddenEnemies[targetRank]) / float(total))
def InterpretResult(self, string=None):
if BasicAI.InterpretResult(self, string) == False:
return False
if self.maxdepth > 1:
if self.lastMoved != None and self.lastMoved.colour == self.colour and self.lastMoved.alive == False:
self.units.sort(key = lambda e : valuedRank(e.rank), reverse = True)
elif self.lastMoved != None and self.lastMoved.colour == oppositeColour(self.colour) and self.lastMoved.alive == True:
oldRank = self.lastMoved.rank
self.lastMoved.rank = '1'
self.enemyUnits.sort(key = lambda e : valuedRank(e.rank), reverse = True)
self.lastMoved.rank = oldRank
return True
if __name__ == "__main__":
if len(sys.argv) > 1:
hunter = Hunter(sys.argv[1])
else:
string = ""
path = sys.argv[0].split('/')
for i in range(0, len(path)-1):
string += path[i] + "/"
string += "default.scores"
hunter = Hunter(string)
if hunter.Setup():
while hunter.MoveCycle():
pass
../asmodeus/path.py
\ No newline at end of file
File added
......@@ -44,20 +44,25 @@ class Vixen(BasicAI):
if unit.mobile() == False:
continue
scores = {"LEFT":0, "RIGHT":0, "UP":0, "DOWN":0}
scores = {"LEFT":None, "RIGHT":None, "UP":None, "DOWN":None}
for target in self.enemyUnits:
if target == unit:
continue
path = PathFinder().pathFind((unit.x, unit.y), (target.x, target.y), self.board)
if path == False or len(path) == 0:
continue
#moveList.append({"unit":unit, "direction":path[0], "score":self.CalculateScore(unit, target, path)})
if scores[path[0]] == None:
scores[path[0]] = 0
scores[path[0]] += self.CalculateScore(unit, target, path)
bestScore = sorted(scores.items(), key = lambda e : e[1], reverse=True)[0]
if bestScore[1] > -100.0:
for d in scores.keys():
if scores[d] == None:
del scores[d]
if len(scores.items()) > 0:
bestScore = sorted(scores.items(), key = lambda e : e[1], reverse=True)[0]
moveList.append({"unit":unit, "direction":bestScore[0], "score":bestScore[1]})
......
......@@ -32,7 +32,7 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
{
/*
vector<char*> args;
if (executablePath[0] != '"')
args.push_back((char*)executablePath);
......@@ -70,6 +70,7 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
for (unsigned int i=0; i < args.size(); ++i)
arguments[i] = args[i];
}
*/
//See if file exists and is executable...
if (access(executablePath, X_OK) != 0)
{
......@@ -100,7 +101,8 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
if (access(executablePath, X_OK) == 0) //Check we STILL have permissions to start the file
{
execv(executablePath,arguments); ///Replace process with desired executable
execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable
//execv(executablePath,arguments); ///Replace process with desired executable
}
perror("execv error:\n");
fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment