From f74c2985f8082fffd45252f1349520449f689c46 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Tue, 20 Dec 2011 22:55:02 +0800 Subject: [PATCH] [RULE CHANGE] *Changed rule for Bombs*, tweaking vixen agent Previously, contact with a Bomb destroyed the Bomb even if the attacker was not a miner. Now, the only way to destroy a Bomb (ever) is to attack it with a miner. Yes, this means that if the enemy Flag is surrounded by Bombs and and AI has lost all its miners, it is impossible to win. This reflects the rules of the original game. My version is now identical to the original game. My original rule was intended to decrease the emphasis placed on Bombs and Miners. Having played a few games, I think the traditional Bomb rule is more interesting, even if it makes things harder for the AI. If there are any problems with this change, please email matches@ I will be happy to revert to the previous rules if there is demand. This also goes for the change to equivelant ranks combat (earlier commit today). Updated vixen agent's scoring to take into account the change. Yet to update asmodeus's scoring. The AI's seem to have a much harder time now that they have to take out Bombs Games often result in draws, because the Miners are easy targets and get killed whilst seeking out Bombs. The AI should probably defend certain pieces with stronger piece combinations nearby. But this is all getting rather complex for a "sample" :P TODO: Implement victory condition when opponent has no mobile pieces (Currently play continues until the player with mobile pieces ends up attacking Bombs because it has nothing else to do at which point the game is a draw because neither player has mobile pieces) --- progcomp/agents/basic_python/basic_python.py | 3 ++ progcomp/agents/vixen/vixen.py | 35 +++++++++++--------- progcomp/judge/manager/manual.txt | 13 ++++++-- progcomp/judge/manager/stratego.cpp | 9 +++++ 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/progcomp/agents/basic_python/basic_python.py b/progcomp/agents/basic_python/basic_python.py index 919d1a2..b384838 100755 --- a/progcomp/agents/basic_python/basic_python.py +++ b/progcomp/agents/basic_python/basic_python.py @@ -62,6 +62,7 @@ class Piece: self.y = y self.lastMoved = -1 self.beenRevealed = False + self.positions = [(x, y)] def mobile(self): return self.rank != 'F' and self.rank != 'B' and self.rank != '?' and self.rank != '+' @@ -247,8 +248,10 @@ class BasicAI: 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 diff --git a/progcomp/agents/vixen/vixen.py b/progcomp/agents/vixen/vixen.py index fc13328..3aa47cb 100755 --- a/progcomp/agents/vixen/vixen.py +++ b/progcomp/agents/vixen/vixen.py @@ -26,9 +26,10 @@ class Vixen(BasicAI): 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.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.bombScores = {'1' : -0.9 , '2' : -0.8 , '3' : -0.5 , '4' : -0.5, '5' : -0.4, '6' : -0.5, '7' : -0.2, '8' : 1.0 , '9' : -0.1, 's' : -0.2} + self.suicideScores = {'1' : -0.5 , '2' : -0.4 , '3' : -0.35, '4' : -0.25, '5' : -0.2, '6' : 0.0, '7' : 0.1, '8' : -1.0 , '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' : 1.0} 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} @@ -53,11 +54,11 @@ class Vixen(BasicAI): 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) + #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]}) + 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: @@ -65,7 +66,7 @@ class Vixen(BasicAI): 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") + #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 @@ -84,6 +85,9 @@ class Vixen(BasicAI): def CalculateScore(self, attacker, defender, path): + p = move(attacker.x, attacker.y, path[0], 1) + + total = 0.0 count = 0.0 for rank in ranks: @@ -99,6 +103,9 @@ class Vixen(BasicAI): total = total * self.tailFactor(len(path)) + #HACK - Prevent "oscillating" by decreasing the value of backtracks + if len(path) > 1 and len(attacker.positions) > 1 and attacker.positions[1][0] == p[0] and attacker.positions[1][1] == p[1]: + total = total / 100 #sys.stderr.write("Total score for " + str(attacker) + " vs. " + str(defender) + " is " + str(total) + "\n") return total @@ -122,7 +129,10 @@ class Vixen(BasicAI): return self.killScores[defenderRank] def bombScore(self, attackerRank): - return self.bombScores[attackerRank] + if attackerRank == '8': + return 1.0 + else: + return 0.0 def suicideScore(self, attackerRank): return self.suicideScores[attackerRank] @@ -152,12 +162,7 @@ class Vixen(BasicAI): 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 + diff --git a/progcomp/judge/manager/manual.txt b/progcomp/judge/manager/manual.txt index 120a6aa..239c6ac 100644 --- a/progcomp/judge/manager/manual.txt +++ b/progcomp/judge/manager/manual.txt @@ -94,11 +94,11 @@ GAME RULES 5 Captain 5 4 6 Lieutenant 6 4 7 Sergeant 7 4 - 8 Miner 8 5 Destroys Bombs without being killed + 8 Miner 8 5 Destroys Bombs 9 Scout 9 8 May move more through multiple empty squares s Spy 10 1 If the Spy attacks the Marshal, the Marshal dies - B Bomb NA 6 Immobile. If any piece (except a Miner) encounters an enemy Bomb, both pieces are destroyed - F Flag NA 1 Immobile. If any piece encounters the enemy Flag, the controlling player wins. + B Bomb NA 6 Immobile. If any piece (except a Miner) attacks an enemy Bomb, that piece is destroyed. + F Flag NA 1 Immobile. If any piece attacks the enemy Flag, the controlling player wins. Additional pieces, not controlled by the player: Piece Name Number Notes @@ -115,6 +115,9 @@ GAME RULES Each player's pieces are hidden from the other player. When two pieces encounter each other, the ranks will be revealed. The objective is to destroy all Enemy Pieces (#) or capture the Enemy Flag (also #). + + Since 20/12 Bombs reflect the traditional rules; they are only destroyed by Miners. + In previous versions contact of an attacker other than a Miner with a Bomb destroyed the Bomb as well as the attacking piece. PROTOCOL @@ -216,8 +219,12 @@ EXIT/OUTPUT BUGS + Occasionally the result is not printed at the end of the game. + So far this has only been observed to occur when RED wins the game by Flag capture. + stratego is still a work in progress. Report another bug to the AUTHOR (see below). + AUTHORS Sam Moore (for the UCC Programming Competition 2012) diff --git a/progcomp/judge/manager/stratego.cpp b/progcomp/judge/manager/stratego.cpp index 62da170..410b70a 100644 --- a/progcomp/judge/manager/stratego.cpp +++ b/progcomp/judge/manager/stratego.cpp @@ -390,6 +390,14 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m } else { + //Use this to destroy only the attacking piece, and not the bomb + RemovePiece(target); + delete target; + board[x][y] = NULL; + return MovementResult(MovementResult::DIES, attackerType, defenderType); + + /* + //Use this to destroy both the bomb and the attacking piece RemovePiece(defender); RemovePiece(target); delete defender; @@ -397,6 +405,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m board[x][y] = NULL; board[x2][y2] = NULL; return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType); + */ } } else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY) -- 2.20.1