Commit f74c2985 authored by Sam Moore's avatar Sam Moore

[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 [email protected]
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)
parent e063c97d
...@@ -62,6 +62,7 @@ class Piece: ...@@ -62,6 +62,7 @@ class Piece:
self.y = y self.y = y
self.lastMoved = -1 self.lastMoved = -1
self.beenRevealed = False self.beenRevealed = False
self.positions = [(x, y)]
def mobile(self): def mobile(self):
return self.rank != 'F' and self.rank != 'B' and self.rank != '?' and self.rank != '+' return self.rank != 'F' and self.rank != 'B' and self.rank != '?' and self.rank != '+'
...@@ -247,8 +248,10 @@ class BasicAI: ...@@ -247,8 +248,10 @@ class BasicAI:
defender = self.board[p[0]][p[1]] defender = self.board[p[0]][p[1]]
#Update attacker's position (Don't overwrite the board yet though) #Update attacker's position (Don't overwrite the board yet though)
attacker.x = p[0] attacker.x = p[0]
attacker.y = p[1] attacker.y = p[1]
attacker.positions.insert(0, (attacker.x, attacker.y))
#Determine ranks of pieces if supplied #Determine ranks of pieces if supplied
......
...@@ -26,9 +26,10 @@ class Vixen(BasicAI): ...@@ -26,9 +26,10 @@ class Vixen(BasicAI):
BasicAI.__init__(self) 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.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.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.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.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} 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): ...@@ -53,11 +54,11 @@ class Vixen(BasicAI):
path = PathFinder().pathFind((unit.x, unit.y), (target.x, target.y), self.board) path = PathFinder().pathFind((unit.x, unit.y), (target.x, target.y), self.board)
if path == False or len(path) == 0: if path == False or len(path) == 0:
continue continue
moveList.append({"unit":unit, "direction":path[0], "score":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) scores[path[0]] += self.CalculateScore(unit, target, path)
#bestScore = sorted(scores.items(), key = lambda e : e[1], reverse=True)[0] bestScore = sorted(scores.items(), key = lambda e : e[1], reverse=True)[0]
#moveList.append({"unit":unit, "direction":bestScore[0], "score":bestScore[1]}) moveList.append({"unit":unit, "direction":bestScore[0], "score":bestScore[1]})
if len(moveList) == 0: if len(moveList) == 0:
...@@ -65,7 +66,7 @@ class Vixen(BasicAI): ...@@ -65,7 +66,7 @@ class Vixen(BasicAI):
return True return True
moveList.sort(key = lambda e : e["score"], reverse=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: if moveList[0]["score"] == 0:
print "NO_MOVE" print "NO_MOVE"
return True return True
...@@ -84,6 +85,9 @@ class Vixen(BasicAI): ...@@ -84,6 +85,9 @@ class Vixen(BasicAI):
def CalculateScore(self, attacker, defender, path): def CalculateScore(self, attacker, defender, path):
p = move(attacker.x, attacker.y, path[0], 1)
total = 0.0 total = 0.0
count = 0.0 count = 0.0
for rank in ranks: for rank in ranks:
...@@ -99,6 +103,9 @@ class Vixen(BasicAI): ...@@ -99,6 +103,9 @@ class Vixen(BasicAI):
total = total * self.tailFactor(len(path)) 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") #sys.stderr.write("Total score for " + str(attacker) + " vs. " + str(defender) + " is " + str(total) + "\n")
return total return total
...@@ -122,7 +129,10 @@ class Vixen(BasicAI): ...@@ -122,7 +129,10 @@ class Vixen(BasicAI):
return self.killScores[defenderRank] return self.killScores[defenderRank]
def bombScore(self, attackerRank): def bombScore(self, attackerRank):
return self.bombScores[attackerRank] if attackerRank == '8':
return 1.0
else:
return 0.0
def suicideScore(self, attackerRank): def suicideScore(self, attackerRank):
return self.suicideScores[attackerRank] return self.suicideScores[attackerRank]
...@@ -152,12 +162,7 @@ class Vixen(BasicAI): ...@@ -152,12 +162,7 @@ class Vixen(BasicAI):
return 0.0 return 0.0
return float(float(self.hiddenEnemies[targetRank]) / float(total)) 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
......
...@@ -94,11 +94,11 @@ GAME RULES ...@@ -94,11 +94,11 @@ GAME RULES
5 Captain 5 4 5 Captain 5 4
6 Lieutenant 6 4 6 Lieutenant 6 4
7 Sergeant 7 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 9 Scout 9 8 May move more through multiple empty squares
s Spy 10 1 If the Spy attacks the Marshal, the Marshal dies 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 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 encounters the enemy Flag, the controlling player wins. F Flag NA 1 Immobile. If any piece attacks the enemy Flag, the controlling player wins.
Additional pieces, not controlled by the player: Additional pieces, not controlled by the player:
Piece Name Number Notes Piece Name Number Notes
...@@ -115,6 +115,9 @@ GAME RULES ...@@ -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. 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 #). 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 PROTOCOL
...@@ -216,8 +219,12 @@ EXIT/OUTPUT ...@@ -216,8 +219,12 @@ EXIT/OUTPUT
BUGS 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). stratego is still a work in progress. Report another bug to the AUTHOR (see below).
AUTHORS AUTHORS
Sam Moore (for the UCC Programming Competition 2012) <[email protected]> Sam Moore (for the UCC Programming Competition 2012) <[email protected]>
......
...@@ -390,6 +390,14 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m ...@@ -390,6 +390,14 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
} }
else 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(defender);
RemovePiece(target); RemovePiece(target);
delete defender; delete defender;
...@@ -397,6 +405,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m ...@@ -397,6 +405,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
board[x][y] = NULL; board[x][y] = NULL;
board[x2][y2] = NULL; board[x2][y2] = NULL;
return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType); return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
*/
} }
} }
else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY) else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
......
Markdown is supported
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