diff --git a/progcomp/agents/basic_python/basic_python.py b/progcomp/agents/basic_python/basic_python.py index 93e4100fc3e85a0c76dc3e149caa0c7eb08b07b3..919d1a2570cf8a6bc10f988ff67db76f3a53093b 100755 --- a/progcomp/agents/basic_python/basic_python.py +++ b/progcomp/agents/basic_python/basic_python.py @@ -73,6 +73,12 @@ class Piece: return 0 +def valuedRank(rank): + if ranks.count(rank) > 0: + return len(ranks) - 2 - ranks.index(rank) + else: + return 0 + class BasicAI: @@ -89,8 +95,13 @@ class BasicAI: self.board = [] self.units = [] self.enemyUnits = [] - self.alliedNumber = {'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.enemyNumber = {'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.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 Setup(self): @@ -230,6 +241,9 @@ class BasicAI: 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) @@ -242,8 +256,19 @@ class BasicAI: 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 @@ -255,35 +280,35 @@ class BasicAI: self.board[p[0]][p[1]] = attacker if defender.colour == self.colour: - self.alliedNumber[defender.rank] -= 1 + self.totalAllies[defender.rank] -= 1 self.units.remove(defender) elif defender.colour == oppositeColour(self.colour): - self.enemyNumber[defender.rank] -= 1 + self.totalEnemies[defender.rank] -= 1 self.enemyUnits.remove(defender) elif outcome == "DIES": if attacker.colour == self.colour: - self.alliedNumber[attacker.rank] -= 1 + self.totalAllies[attacker.rank] -= 1 self.units.remove(attacker) elif attacker.colour == oppositeColour(self.colour): - self.enemyNumber[attacker.rank] -= 1 + 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.alliedNumber[defender.rank] -= 1 + self.totalAllies[defender.rank] -= 1 self.units.remove(defender) elif defender.colour == oppositeColour(self.colour): - self.enemyNumber[defender.rank] -= 1 + self.totalEnemies[defender.rank] -= 1 self.enemyUnits.remove(defender) if attacker.colour == self.colour: - self.alliedNumber[attacker.rank] -= 1 + self.totalAllies[attacker.rank] -= 1 self.units.remove(attacker) elif attacker.colour == oppositeColour(self.colour): - self.enemyNumber[attacker.rank] -= 1 + self.totalEnemies[attacker.rank] -= 1 self.enemyUnits.remove(attacker) elif outcome == "FLAG": diff --git a/progcomp/agents/vixen/asmodeus.py b/progcomp/agents/vixen/asmodeus.py new file mode 120000 index 0000000000000000000000000000000000000000..1b1739c6fcc25808f2df7b3e4c4dad34d807b59b --- /dev/null +++ b/progcomp/agents/vixen/asmodeus.py @@ -0,0 +1 @@ +../asmodeus/asmodeus.py \ No newline at end of file diff --git a/progcomp/agents/vixen/basic_python.py b/progcomp/agents/vixen/basic_python.py new file mode 120000 index 0000000000000000000000000000000000000000..3d6b342f8b51abf097c49b50c3066ee247f72096 --- /dev/null +++ b/progcomp/agents/vixen/basic_python.py @@ -0,0 +1 @@ +../basic_python/basic_python.py \ No newline at end of file diff --git a/progcomp/agents/vixen/info b/progcomp/agents/vixen/info new file mode 100644 index 0000000000000000000000000000000000000000..424358b77a4b081613cb9d1ce7a397559b1fccab --- /dev/null +++ b/progcomp/agents/vixen/info @@ -0,0 +1 @@ +vixen.py diff --git a/progcomp/agents/vixen/path.py b/progcomp/agents/vixen/path.py new file mode 120000 index 0000000000000000000000000000000000000000..1d82284b102fcc1d8367eef2b82c62c866bcf397 --- /dev/null +++ b/progcomp/agents/vixen/path.py @@ -0,0 +1 @@ +../asmodeus/path.py \ No newline at end of file diff --git a/progcomp/agents/vixen/vixen.py b/progcomp/agents/vixen/vixen.py new file mode 100755 index 0000000000000000000000000000000000000000..fc13328e207279a37aeb75f1cce3565aacebdb79 --- /dev/null +++ b/progcomp/agents/vixen/vixen.py @@ -0,0 +1,171 @@ +#!/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. + +''' + vixen.py - A sample Stratego AI for the UCC Programming Competition 2012 + + 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 +''' + +from basic_python import * +from path import * + + + +class Vixen(BasicAI): + " Python based AI, improves upon Asmodeus by taking into account probabilities, and common paths " + def __init__(self): + #sys.stderr.write("Vixen initialised...\n") + BasicAI.__init__(self) + + + self.bombScores = {'1' : -0.9 , '2' : -0.8 , '3' : -0.5 , '4' : 0.1, '5' : 0.1, '6' : 0.3, '7' : 0.7, '8' : 1 , '9' : 0.6, 's' : 0} + self.suicideScores = {'1' : -0.5 , '2' : -0.4 , '3' : -0.35, '4' : -0.25, '5' : -0.2, '6' : 0.0, '7' : 0.1, '8' : -0.4 , '9' : 0.0, 's' : -0.4} + self.killScores = {'1' : 1.0 , '2' : 0.9 , '3' : 0.9 , '4' : 0.8, '5' : 0.8, '6' : 0.8, '7' : 0.8, '8' : 0.9 , '9' : 0.7, 's' : 0.9} + self.riskScores = {'1' : 0.0, '2' : 0.1, '3' : 0.2, '4': 0.4, '5': 0.6, '6': 0.7, '7':0.8, '8': 0.0, '9' : 1.0, 's' : 0.1} + + + + + + def MakeMove(self): + #sys.stderr.write("Vixen MakingMove...\n") + " Over-rides the default BasicAI.MakeMove function " + + moveList = [] + for unit in self.units: + if unit.mobile() == False: + continue + + scores = {"LEFT":0, "RIGHT":0, "UP":0, "DOWN":0} + + + 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)}) + #scores[path[0]] += self.CalculateScore(unit, target, path) + + #bestScore = sorted(scores.items(), key = lambda e : e[1], reverse=True)[0] + #moveList.append({"unit":unit, "direction":bestScore[0], "score":bestScore[1]}) + + + if len(moveList) == 0: + print "NO_MOVE" + return True + + moveList.sort(key = lambda e : e["score"], reverse=True) + sys.stderr.write("vixen - best move: " + str(moveList[0]["unit"].x) + " " + str(moveList[0]["unit"].y) + " " + moveList[0]["direction"] + " [ score = " + str(moveList[0]["score"]) + " ]\n") + if moveList[0]["score"] == 0: + print "NO_MOVE" + return True + + + print str(moveList[0]["unit"].x) + " " + str(moveList[0]["unit"].y) + " " + moveList[0]["direction"] + return True + + + def tailFactor(self, pathLength): + #if pathLength >= len(self.tailFactors) or pathLength <= 0: + # return 0.0 + #return self.tailFactors[pathLength] + #return 0.5 * (1.0 + pow(pathLength, 0.75)) + return 1.0 / pathLength + + + def CalculateScore(self, attacker, defender, path): + total = 0.0 + count = 0.0 + for rank in ranks: + prob = self.rankProbability(defender, rank) + if prob > 0.0: + #sys.stderr.write(" " + str(attacker.rank) + " vs. " + str(rank) + " [" + str(prob) + "] score " + str(self.combatScore(attacker.rank, rank, len(path))) + "\n") + total += prob * self.combatScore(attacker.rank, rank, len(path)) + count += 1 + + + #if count > 1: + # total = total / count + self.riskScore(attacker.rank) + + + total = total * self.tailFactor(len(path)) + #sys.stderr.write("Total score for " + str(attacker) + " vs. " + str(defender) + " is " + str(total) + "\n") + return total + + def combatScore(self, attackerRank, defenderRank, pathLength): + if defenderRank == 'F': + return 1.0 + elif defenderRank == 'B': + return self.bombScore(attackerRank) + elif defenderRank == 's' and attackerRank == '1' and pathLength == 2: + return self.suicideScore(attackerRank) + elif defenderRank == '1' and attackerRank == 's' and pathLength != 2: + return self.killScore(attackerRank) + + if valuedRank(attackerRank) > valuedRank(defenderRank): + return self.killScore(defenderRank) + elif valuedRank(attackerRank) < valuedRank(defenderRank): + return self.suicideScore(attackerRank) + return self.killScore(defenderRank) + self.suicideScore(attackerRank) + + def killScore(self, defenderRank): + return self.killScores[defenderRank] + + def bombScore(self, attackerRank): + return self.bombScores[attackerRank] + + def suicideScore(self, attackerRank): + return self.suicideScores[attackerRank] + + def riskScore(self, attackerRank): + return self.riskScores[attackerRank] + + 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): + """ Over-ride the basic AI interpret result so we can update probabilities """ + if BasicAI.InterpretResult(self) == False: + return False + + return True + + + + + +if __name__ == "__main__": + vixen = Vixen() + if vixen.Setup(): + while vixen.MoveCycle(): + pass + diff --git a/progcomp/judge/manager/game.cpp b/progcomp/judge/manager/game.cpp index d88f7590a3e1006fba7239428e0287df84e7b663..3d6dcc805ab091e57fac2121c64ee0bf2f1cf273 100644 --- a/progcomp/judge/manager/game.cpp +++ b/progcomp/judge/manager/game.cpp @@ -446,7 +446,7 @@ MovementResult Game::Play() while (!Board::HaltResult(result) && (turnCount < maxTurns || maxTurns < 0)) { - if (red->HumanController()) + if (red->HumanController() && blue->HumanController()) toReveal = Piece::RED; if (printBoard) { @@ -476,7 +476,7 @@ MovementResult Game::Play() else ReadUserCommand(); - if (blue->HumanController()) + if (blue->HumanController() && red->HumanController()) toReveal = Piece::BLUE; if (printBoard) {