[PRELIMINARY ROUND 2]
authorSam Moore <matches@ucc.asn.au>
Sat, 5 May 2012 13:10:31 +0000 (21:10 +0800)
committerSam Moore <matches@ucc.asn.au>
Sat, 5 May 2012 13:10:31 +0000 (21:10 +0800)
Finally.
BLERGH.

27 files changed:
agents/asmodeus/basic_python.pyc [new file with mode: 0644]
agents/asmodeus/path.pyc [new file with mode: 0644]
agents/basic_cpp/basic_cpp [new file with mode: 0755]
agents/basic_cpp/basic_cpp.o [new file with mode: 0644]
agents/celsius-v1.1.tar [new file with mode: 0644]
agents/celsius-v1.2.tar.gz [new file with mode: 0644]
agents/celsius1.1/celsius.py [new file with mode: 0755]
agents/celsius1.1/info [new file with mode: 0644]
agents/hunter/basic_python.pyc [new file with mode: 0644]
agents/peternlewis.zip [new file with mode: 0644]
agents/ramen.tar [new file with mode: 0644]
agents/ramen/28f56d3c_peternlewis.ramen [new file with mode: 0644]
agents/ramen/ramen [new file with mode: 0755]
agents/ramen/src/Makefile [new file with mode: 0644]
agents/ramen/src/ai.c [new file with mode: 0644]
agents/ramen/src/ai.o [new file with mode: 0644]
agents/ramen/src/ai.o.dep [new file with mode: 0644]
agents/ramen/src/ai_common.h [new file with mode: 0644]
agents/ramen/src/db.c [new file with mode: 0644]
agents/ramen/src/db.o [new file with mode: 0644]
agents/ramen/src/db.o.dep [new file with mode: 0644]
agents/ramen/src/interface.h [new file with mode: 0644]
agents/ramen/src/main.c [new file with mode: 0644]
agents/ramen/src/main.o [new file with mode: 0644]
agents/ramen/src/main.o.dep [new file with mode: 0644]
agents/vixen/basic_python.pyc [new file with mode: 0644]
agents/vixen/path.pyc [new file with mode: 0644]

diff --git a/agents/asmodeus/basic_python.pyc b/agents/asmodeus/basic_python.pyc
new file mode 100644 (file)
index 0000000..4338c88
Binary files /dev/null and b/agents/asmodeus/basic_python.pyc differ
diff --git a/agents/asmodeus/path.pyc b/agents/asmodeus/path.pyc
new file mode 100644 (file)
index 0000000..73e171a
Binary files /dev/null and b/agents/asmodeus/path.pyc differ
diff --git a/agents/basic_cpp/basic_cpp b/agents/basic_cpp/basic_cpp
new file mode 100755 (executable)
index 0000000..70af5d6
Binary files /dev/null and b/agents/basic_cpp/basic_cpp differ
diff --git a/agents/basic_cpp/basic_cpp.o b/agents/basic_cpp/basic_cpp.o
new file mode 100644 (file)
index 0000000..d3c66dd
Binary files /dev/null and b/agents/basic_cpp/basic_cpp.o differ
diff --git a/agents/celsius-v1.1.tar b/agents/celsius-v1.1.tar
new file mode 100644 (file)
index 0000000..e0dec59
Binary files /dev/null and b/agents/celsius-v1.1.tar differ
diff --git a/agents/celsius-v1.2.tar.gz b/agents/celsius-v1.2.tar.gz
new file mode 100644 (file)
index 0000000..7e220da
Binary files /dev/null and b/agents/celsius-v1.2.tar.gz differ
diff --git a/agents/celsius1.1/celsius.py b/agents/celsius1.1/celsius.py
new file mode 100755 (executable)
index 0000000..cc71b90
--- /dev/null
@@ -0,0 +1,539 @@
+#!/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.
+
+
+import sys
+import random
+
+ranks = ['B','1','2','3','4','5','6','7','8','9','s','F', '?', '!', '+']
+
+"""
+The scaretable lists how `scary' pieces are to each other; pieces will move
+in the least scary direction.
+"""
+
+#               B   1  2  3  4  5  6  7  8  9  s  F  ?  !  +
+scaretable = [[  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #B
+              [  0,  0,-8,-8,-7,-6,-5,-4,-3,-2, 5,-9, 0,-7, 0], #1
+             [  0,  4, 0,-7,-6,-5,-4,-3,-2,-1,-2,-9,-3,-6, 0], #2
+             [  0,  4, 2, 0,-6,-5,-4,-3,-2,-1,-2,-9,-2,-5, 0], #3
+             [  0,  3, 2, 2, 0,-5,-4,-3,-2,-1,-2,-9,-1,-3, 0], #4 
+             [  0,  3, 2, 2, 2, 0,-4,-3,-2,-1,-2,-9, 0,-2, 0], #5
+             [  0,  3, 2, 2, 2, 2, 0,-3,-2,-1,-2,-9, 1,-1, 0], #6
+             [  0,  3, 2, 2, 2, 2, 2, 0,-2,-1,-2,-9,-1, 0, 0], #7
+             [-40,  3, 2, 2, 2, 2, 2, 2, 0,-2,-2,-9,-1, 1, 0], #8
+             [  0,  3, 2, 2, 2, 2, 2, 2, 2, 0,-2,-9,-2, 2, 0], #9
+             [  0, -5, 3, 3, 3, 3, 3, 3, 3, 3,-1,-9, 5, 3, 0], #s
+             [  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #F
+             [  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #?
+             [  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #!
+             [  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] #+
+
+"""
+The override table allows moves to be forced or prevented, thus ensuring
+that sacrifices are not made.
+"""
+#              B  1  2  3  4  5  6  7  8  9  s  F  ?  !  +
+overrides  = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #B
+              [ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,-1,-1, 0, 0, 1], #1
+             [ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 1], #2
+             [ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 1], #3
+             [ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 1], #4 
+             [ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,-1, 0, 0, 1], #5
+             [ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,-1, 0, 0, 1], #6
+             [ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,-1, 0, 0, 1], #7
+             [-1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,-1, 0, 0, 1], #8
+             [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,-1, 0, 0, 1], #9
+             [ 1,-1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1, 0, 0, 1], #s
+             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #F
+             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #?
+             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], #!
+             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] #+
+
+
+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)]
+               
+
+
+               self.heatmap = []
+               self.turnCount = 0
+
+       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 scariness(self, other):
+               scare = scaretable[ranks.index(self.rank)][ranks.index(other.rank)]
+               if scare > 0:
+                       scare = scare * 1
+               return scare
+
+       def getOverride(self, other):
+               return overrides[ranks.index(self.rank)][ranks.index(other.rank)]
+
+       def getHeatmap(self, x,y,w,h):
+               if (x < 0) or (x >= w) or (y < 0) or (y >= h):
+                       return 10
+               else:
+                       return self.heatmap[x][y]
+
+       def validSquare(self, x, y, width, height, board):
+               if x < 0:
+                       return False
+               if y < 0:
+                       return False
+               if x >= width:
+                       return False
+               if y >= height:
+                       return False
+               if board[x][y] != None and board[x][y].colour == self.colour:
+                       return False
+               if board[x][y] != None and board[x][y].rank == '#':
+                       return False
+               return True
+
+       def generateHeatmap(self, width, height, board):
+               self.heatmap = []
+               newmap = []
+               for x in range(0,width):
+                       self.heatmap.append([])
+                       newmap.append([])
+                       for y in range(0,height):
+                               self.heatmap[x].append(0)
+                               newmap[x].append(0)
+                               if board[x][y] == None:
+                                       self.heatmap[x][y] = 0
+                                       continue
+                               if board[x][y].colour == self.colour:
+                                       if board[x][y].rank == 'F':
+                                               self.heatmap[x][y] = -5 # + self.valuedRank()           # Defend our flag
+                               else:
+                                       self.heatmap[x][y] = self.scariness(board[x][y])
+
+               # Make pieces prefer to stay where they are
+               #self.heatmap[self.x][self.y] = -0.5
+
+               for i in range(0,min(30,len(self.positions))):
+                       p = self.positions[len(self.positions)-1-i]
+                       if board[p[0]][p[1]] != None:
+                               self.heatmap[p[0]][p[1]] += 0.2 * ((50 - i)/50)
+                               
+
+
+               for n in range(0,8):
+                       for x in range(0,width):
+                               for y in range(0,height):
+                                       if self.heatmap[x][y] != 0:
+                                               newmap[x][y] = self.heatmap[x][y]
+                                               continue
+                                       newmap[x][y] = 0 #self.heatmap[x][y] * 0.2
+                                       if self.validSquare(x-1,y,width,height,board):
+                                               newmap[x][y] += self.heatmap[x-1][y] * 0.2
+                                       else:
+                                               newmap[x][y] += 0 #self.heatmap[x][y] * 0.1
+                                       if self.validSquare(x+1,y,width,height,board):
+                                               newmap[x][y] += self.heatmap[x+1][y] * 0.2
+                                       else:
+                                               newmap[x][y] += 0 #self.heatmap[x][y] * 0.1
+                                       if self.validSquare(x,y-1,width,height,board):
+                                               newmap[x][y] += self.heatmap[x][y-1] * 0.2
+                                       else:
+                                               newmap[x][y] += 0 #self.heatmap[x][y] * 0.1
+                                       if self.validSquare(x,y+1,width,height,board):
+                                               newmap[x][y] += self.heatmap[x][y+1] * 0.2
+                                       else:
+                                               newmap[x][y] += 0 #self.heatmap[x][y] * 0.1
+                       self.heatmap = newmap
+
+       def debugPrintHeat(self,w,h):
+               """ For debug purposes only. Prints the board to stderr.
+                       Does not indicate difference between allied and enemy pieces
+                       Unknown (enemy) pieces are shown as '?'
+               """
+               sys.stderr.write("Pos: " + str(self.x) + ", " + str(self.y) + " -- rank: " + str(self.rank) + "\n")
+               for y in range(0, h):
+                       for x in range(0, w):
+                               if (self.heatmap[x][y] - self.heatmap[self.x][self.y] > 0.0):
+                                       sys.stderr.write("O")
+                               elif (self.heatmap[x][y] - self.heatmap[self.x][self.y] == 0.0):
+                                       sys.stderr.write("X")
+                               elif (self.heatmap[x][y] - self.heatmap[self.x][self.y] < 0.0):
+                                       sys.stderr.write(".")
+                               else:
+                                       sys.stderr.write(" ")
+                       sys.stderr.write("\n")
+               sys.stderr.write("\n")
+                               
+
+       
+
+def valuedRank(rank):
+       if ranks.count(rank) > 0:
+               return len(ranks) - 2 - ranks.index(rank)
+       else:
+               return 0
+
+
+
+class SulixAI:
+       """
+               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.total_turns = 0
+
+               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):
+               """ 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 "FB8sB979B8\nBB99555583\n6724898974\nB314676699"
+               elif self.colour == "BLUE":
+                       print "B314676699\n6724898974\nBB99555583\nFB8sB979B8"
+               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("Sulix's AI makes a move...\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")
+               bestdir = 0
+               bestScare = 999
+               bestpiece = None
+               while True:
+                       piece = self.units[index]
+
+                       if piece != None and piece.mobile():
+                               dirIndex = random.randint(0, len(directions)-1)
+                               startDirIndex = dirIndex
+                               piece.generateHeatmap(self.width, self.height, self.board)              
+                               currentScary = piece.getHeatmap(piece.x, piece.y, self.width, self.height) * 0 + piece.turnCount*0 #Perhaps just look for the best move
+                               piece.turnCount = piece.turnCount + 1
+                               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"):   
+                                                       scare = piece.getHeatmap(p[0], p[1],self.width, self.height) - currentScary
+                                                       override = 0
+                                                       if target != None:
+                                                               override = piece.getOverride(target)
+                                                       
+                                                       if (self.total_turns % 250 < 15) and (self.total_turns > 250):
+                                                               scare += random.randint(0, 5)
+
+
+                                                       if override == 1:
+                                                               scare = 999
+                                                       elif override == -1:
+                                                               piece.turnCount = 0
+                                                               print str(piece.x) + " " + str(piece.y) + " " + directions[dirIndex]
+                                                               return True
+
+
+                                                       
+
+                                                       if scare < bestScare:
+                                                               bestdir = dirIndex
+                                                               bestScare = scare
+                                                               bestpiece = piece
+
+                                       dirIndex = (dirIndex + 1) % len(directions)
+                                       if startDirIndex == dirIndex:
+                                               break
+
+
+                       index = (index + 1) % len(self.units)
+                       if startIndex == index:
+                               if bestScare != 999:
+                                       bestpiece.turnCount = 0
+                                       print str(bestpiece.x) + " " + str(bestpiece.y) + " "+directions[bestdir]
+#                                      bestpiece.debugPrintHeat(self.width, self.height)
+                                       return True
+                               else:
+                                       print "SURRENDER"
+                                       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):
+               """ 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
+               """
+
+               self.total_turns = self.total_turns + 1
+
+               #sys.stderr.write("BasicAI InterpretResult here...\n")
+               result = sys.stdin.readline().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())
+
+
+               # The piece moved! It's not a bomb
+               if self.board[x][y].rank == '?':
+                       self.board[x][y].rank = '!'
+               #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)
+
+               # It's a scout! I saw it move.
+               if multiplier > 1:
+                       self.board[x][y].rank = '9'
+
+               #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__":
+       sulixAI = SulixAI()
+       if sulixAI.Setup():
+               while sulixAI.MoveCycle():
+                       pass
+
diff --git a/agents/celsius1.1/info b/agents/celsius1.1/info
new file mode 100644 (file)
index 0000000..aedb008
--- /dev/null
@@ -0,0 +1,4 @@
+celsius.py
+David Gow
+python
+Generates a heatmap of the board, and uses this to control pieces.
diff --git a/agents/hunter/basic_python.pyc b/agents/hunter/basic_python.pyc
new file mode 100644 (file)
index 0000000..158229f
Binary files /dev/null and b/agents/hunter/basic_python.pyc differ
diff --git a/agents/peternlewis.zip b/agents/peternlewis.zip
new file mode 100644 (file)
index 0000000..45848bc
Binary files /dev/null and b/agents/peternlewis.zip differ
diff --git a/agents/ramen.tar b/agents/ramen.tar
new file mode 100644 (file)
index 0000000..69a5119
Binary files /dev/null and b/agents/ramen.tar differ
diff --git a/agents/ramen/28f56d3c_peternlewis.ramen b/agents/ramen/28f56d3c_peternlewis.ramen
new file mode 100644 (file)
index 0000000..cd917d2
Binary files /dev/null and b/agents/ramen/28f56d3c_peternlewis.ramen differ
diff --git a/agents/ramen/ramen b/agents/ramen/ramen
new file mode 100755 (executable)
index 0000000..c583e66
Binary files /dev/null and b/agents/ramen/ramen differ
diff --git a/agents/ramen/src/Makefile b/agents/ramen/src/Makefile
new file mode 100644 (file)
index 0000000..06068b3
--- /dev/null
@@ -0,0 +1,25 @@
+
+OBJ = main.o ai.o db.o
+BIN = ../ramen
+
+CFLAGS = -Wall -Wextra -g -std=gnu99
+LINKFLAGS = -g -lm
+
+DEPFILES = $(OBJ:%=%.dep)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       $(RM) $(BIN) $(OBJ) $(DEPFILES)
+
+$(BIN): $(OBJ)
+       $(CC) -o $@ $(OBJ) $(LINKFLAGS)
+
+%.o: %.c
+       $(CC) -o $@ -c $< $(CFLAGS) $(CPPFLAGS)
+       $(CPP) $(CPPFLAGS) $< -MM -o $@.dep
+
+-include $(DEPFILES)
+
diff --git a/agents/ramen/src/ai.c b/agents/ramen/src/ai.c
new file mode 100644 (file)
index 0000000..6625d24
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * UCC 2012 Programming Competition Entry
+ * - "Ramen"
+ *
+ * By John Hodge [TPG]
+ */
+#define ENABLE_DEBUG   0
+#define SHOW_TARGET_MAP        0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include "interface.h"
+#include "ai_common.h"
+
+// === CONSTANTS ===
+//! \brief Maximum recusion depth
+#define MAX_SEARCH_DEPTH       5
+
+//! \brief Threshold before repeat modifier is applied
+#define REPEAT_THRESHOLD       3
+//! \brief Modifier applied to a repeated move
+#define REPEAT_MOVE_MODIFY(score)      do{score /= (giNumRepeatedMove <= 5 ? 2 : 10); score -= giNumRepeatedMove*10;}while(0);
+
+//! \brief Number of moves by this AI before the defensive modifier kicks in
+#define DEFENSIVE_THRESHOLD    20
+//! \brief Modifier applied to offensive moves when > DEFENSIVE_THRESHOLD defensive moves have been done in a row
+#define DEFENSIVE_MODIFY(score)        do{score *= 1+(giTurnsSinceLastTake/15);}while(0)
+/**
+ * \name AI move outcome scores
+ * \{
+ */
+#define OC_LOSE        -100
+#define OC_DRAW        0
+#define OC_UNK 40
+#define OC_WIN 100
+#define OC_FLAG        150
+/**
+ * \}
+ */
+
+// === PROTOTYPES ===
+// - Wrapper and Initialisation
+void   AI_Initialise(enum eColours Colour, const char *Opponent);
+void   AI_HandleMove(int bMyMove, const tMove *Move);
+void   UpdateStates(const tMove *OpponentMove);
+void   AI_DoMove(tMove *MyMove);
+// - Management
+tPiece *GetPieceByPos(int X, int Y);
+void   MovePieceTo(tPiece *Piece, int X, int Y);
+void   UpdateRank(tPiece *Piece, char RankChar);
+void   PieceExposed(tPiece *Piece);
+void   RemovePiece(tPiece *Piece);
+// -- AI Core 
+ int   GetBestMove(tPlayerStats *Attacker, tPlayerStats *Defender, tMove *Move, int Level);
+ int   GetPositionScore(tPlayerStats *Attacker, tPlayerStats *Defender, int Level, int X, int Y, tPiece *Piece);
+ int   GetScore(tPiece *This, tPiece *Target);
+ int   GetRawScore(tPiece *This, tPiece *Target);
+// -- Helpers
+static inline int      GetOutcome(int Attacker, int Defender);
+static inline int      ABS(int Val);
+static inline int      RANGE(int Min, int Val, int Max);
+
+// === GLOBALS ===
+enum eColours  gMyColour;
+tPiece gBlockPiece = {.Team = 2};
+ int   giGameStateSize;
+tGameState     *gpCurrentGameState;
+BOOL   gbFirstTurn = true;
+//tPiece       **gaBoardPieces;
+const char *gsOpponentDbFilename;
+// -- State variables to avoid deadlocking
+ int   giNumRepeatedMove;
+ int   giTurnsSinceLastTake;
+tMove  gLastMove;
+tPiece *gLastMove_Target, *gLastMove_Piece;
+
+// === CODE ===
+void AI_Initialise(enum eColours Colour, const char *Opponent)
+{
+       gMyColour = Colour;
+
+       // TODO: Get opponent filename
+       gsOpponentDbFilename = DB_GetOpponentFile(Opponent);
+       
+       // Select setup
+//     setup_id = rand() % 3;
+       int setup_id = 1;
+       switch( setup_id )
+       {
+//     case 0: // Bomb-off (dick move)
+//             // 39 pieces, bombs blocking gates, high level pieces backing up
+//             {
+//             const char *setup[] = {
+//                     "8.88979993\n",
+//                     "6689995986\n",
+//                     "F72434s174\n",
+//                     "BB56BB55BB\n"
+//                     };
+//             if( Colour == COLOUR_RED )
+//                     for(int i = 0; i < 4; i ++ )    printf(setup[i]);
+//             else
+//                     for(int i = 4; i --; )          printf(setup[i]);
+//             break;
+//             }
+       case 1:
+               {
+               const char *setup[] = {
+                       "FB8sB479B8\n",
+                       "BB31555583\n",
+                       "6724898974\n",
+                       "967B669999\n"
+                       };
+               if( Colour == COLOUR_RED )
+                       for(int i = 0; i < 4; i ++ )    printf(setup[i]);
+               else
+                       for(int i = 4; i --; )          printf(setup[i]);
+               }
+               break ;
+       default:
+               exit(1);
+       }
+
+
+       giGameStateSize = sizeof(tGameState) + giBoardHeight*giBoardWidth*sizeof(tPieceRef);
+       gpCurrentGameState = calloc( giGameStateSize, 1 );
+       gpCurrentGameState->Opponent.Colour = !Colour;
+       gpCurrentGameState->MyExposed.Colour = Colour;
+       gpCurrentGameState->MyActual.Colour = Colour;
+//     gaBoardPieces = calloc( giBoardHeight*giBoardWidth, sizeof(tPiece*) );
+}
+
+void AI_int_InitialiseBoardState(void)
+{
+        int    piece_index = 0;
+        int    my_piece_index = 0;
+       for( int y = 0; y < giBoardHeight; y ++ )
+       {
+               for( int x = 0; x < giBoardWidth; x ++ )
+               {
+                       tPiece  *p;
+                       char b;
+                       
+                       b = gaBoardState[y*giBoardWidth+x];
+       
+                       if( b == '.' )  continue ;
+                       if( b == '+' )
+                       {
+                               gpCurrentGameState->BoardState[ y*giBoardWidth+x ].Team = 3;
+                               continue ;
+                       }
+
+                       if( b == '#' )
+                       {
+                               if( piece_index >= N_PIECES ) {
+                                       piece_index ++;
+                                       continue ;
+                               }
+                               p = &gpCurrentGameState->Opponent.Pieces[piece_index++];
+                               p->Rank = RANK_UNKNOWN;
+                               p->X = x;       p->StartX = x;
+                               p->Y = y;       p->StartY = y;
+                               p->bHasMoved = false;
+                               p->Team = !gMyColour;
+                               gpCurrentGameState->BoardState[ y*giBoardWidth+x ].Team = 2;
+                               gpCurrentGameState->BoardState[ y*giBoardWidth+x ].Index = piece_index - 1;
+                               DEBUG("Enemy at %i,%i", x, y);
+                       }
+                       else
+                       {
+                               if( my_piece_index >= N_PIECES ) {
+                                       my_piece_index ++;
+                                       continue ;
+                               }
+                               p = &gpCurrentGameState->MyActual.Pieces[my_piece_index++];
+                               p->X = x;
+                               p->Y = y;
+                               p->Team = gMyColour;
+                               UpdateRank(p, b);
+                               gpCurrentGameState->MyActual.nRanks[p->Rank] ++;
+                               gpCurrentGameState->BoardState[ y*giBoardWidth+x ].Team = 1;
+                               gpCurrentGameState->BoardState[ y*giBoardWidth+x ].Index = my_piece_index - 1;
+                       }
+
+                       
+               }
+       }
+       gpCurrentGameState->Opponent.nPieces = piece_index;
+       if( piece_index > N_PIECES )
+               DEBUG("GAH! Too many opposing pieces (%i > 40)", piece_index);
+       if( my_piece_index > N_PIECES )
+               DEBUG("GAH! Too many of my pieces (%i > 40)", my_piece_index);
+
+       // Catch for if I don't put enough pieces out (shouldn't happen)
+       while( my_piece_index < N_PIECES ) {
+               gpCurrentGameState->MyActual.Pieces[my_piece_index].bDead = true;
+               gpCurrentGameState->MyActual.Pieces[my_piece_index].Rank = RANK_UNKNOWN;
+               my_piece_index ++;
+       }
+
+       // Load guesses at what each piece is
+       DB_LoadGuesses(gsOpponentDbFilename, !gMyColour);
+       gpCurrentGameState->Opponent.bGuessValid = true;
+}
+
+void AI_HandleMove(int bMyMove, const tMove *Move)
+{
+       if( gbFirstTurn )
+       {
+               gbFirstTurn = false;
+               
+               AI_int_InitialiseBoardState();
+
+               // Reverse the first move
+               if( Move->dir != DIR_INVAL )
+               {
+                       tPiece  *p;
+                       switch(Move->dir)
+                       {
+                       case DIR_INVAL: ASSERT(Move->dir != DIR_INVAL); break;
+                       case DIR_LEFT:  p = GetPieceByPos( Move->x-1, Move->y );        break ;
+                       case DIR_RIGHT: p = GetPieceByPos( Move->x+1, Move->y );        break ;
+                       case DIR_UP:    p = GetPieceByPos( Move->x, Move->y-1 );        break ;
+                       case DIR_DOWN:  p = GetPieceByPos( Move->x, Move->y+1 );        break ;
+                       }
+                       MovePieceTo( p, Move->x, Move->y );
+                       p->StartX = Move->x;
+                       p->StartY = Move->y;
+               }
+       }
+
+       if(Move->result == RESULT_VICTORY)
+       {
+               // TODO: Distiguish between victory conditions?
+               // - Note flag location?
+
+               // TODO: Save back initial board state
+               DB_WriteBackInitialState(gsOpponentDbFilename, !gMyColour, gpCurrentGameState->Opponent.Pieces);
+       }
+
+       if( !bMyMove )
+       {
+               if( Move->dir != DIR_INVAL )
+                       UpdateStates(Move);
+       }
+       else
+       {
+               tPiece  *p = GetPieceByPos(Move->x, Move->y);
+               ASSERT(p);
+
+               int newx = p->X, newy = p->Y;
+               switch(Move->dir)
+               {
+               case DIR_INVAL: break;
+               case DIR_LEFT:  newx -= Move->dist;     break;
+               case DIR_RIGHT: newx += Move->dist;     break;
+               case DIR_UP:    newy -= Move->dist;     break;
+               case DIR_DOWN:  newy += Move->dist;     break;
+               }
+               tPiece  *target = GetPieceByPos(newx, newy);
+
+               switch(Move->result)
+               {
+               case RESULT_ILLEGAL:    break;
+               case RESULT_INVAL:      break;
+               case RESULT_OK:
+                       MovePieceTo(p, newx, newy);
+                       break;
+               case RESULT_KILL:
+                       UpdateRank(target, Move->defender);
+                       RemovePiece(target);
+                       MovePieceTo(p, newx, newy);
+                       PieceExposed(p);        // TODO: Update oponent's view
+                       giTurnsSinceLastTake = 0;
+                       break;
+               case RESULT_DIES:
+               case RESULT_VICTORY:
+                       UpdateRank(target, Move->defender);
+                       PieceExposed(p);
+                       RemovePiece(p);
+                       giTurnsSinceLastTake = 0;
+                       break;
+               case RESULT_BOTHDIE:
+                       UpdateRank(target, Move->defender);
+                       PieceExposed(p);
+                       RemovePiece(p);
+                       RemovePiece(target);
+                       giTurnsSinceLastTake = 0;
+                       break;
+               }
+       }
+}
+
+void UpdateStates(const tMove *OpponentMove)
+{
+       // --- Get moved piece, update position ---
+       tPiece  *moved_piece = GetPieceByPos(OpponentMove->x, OpponentMove->y);
+       // - Sanity
+       ASSERT( moved_piece );
+       ASSERT( moved_piece->Team == !gMyColour );
+       // - Only scouts can move multiple squares
+       if( moved_piece->Rank == RANK_UNKNOWN && OpponentMove->dist > 1 )
+               UpdateRank(moved_piece, '9');
+       // - Update position
+        int newx = moved_piece->X, newy = moved_piece->Y;
+       switch(OpponentMove->dir)
+       {
+       case DIR_INVAL: break;
+       case DIR_LEFT:  newx -= OpponentMove->dist;     break;
+       case DIR_RIGHT: newx += OpponentMove->dist;     break;
+       case DIR_UP:    newy -= OpponentMove->dist;     break;
+       case DIR_DOWN:  newy += OpponentMove->dist;     break;
+       }
+       tPiece  *my_piece = GetPieceByPos(newx, newy);
+       
+       // Check if one of my pieces has been taken
+       switch( OpponentMove->result )
+       {
+       case RESULT_ILLEGAL:    break;
+       case RESULT_INVAL:      break;
+       case RESULT_OK:
+               MovePieceTo(moved_piece, newx, newy);
+               break;
+       case RESULT_KILL:
+       case RESULT_VICTORY:
+               UpdateRank(moved_piece, OpponentMove->attacker);
+               PieceExposed(my_piece);
+               RemovePiece(my_piece);
+               MovePieceTo(moved_piece, newx, newy);
+               break;
+       case RESULT_DIES:
+               UpdateRank(moved_piece, OpponentMove->attacker);
+               PieceExposed(my_piece);
+               RemovePiece(moved_piece);
+               break;
+       case RESULT_BOTHDIE:
+               UpdateRank(moved_piece, OpponentMove->attacker);
+               RemovePiece(moved_piece);
+               PieceExposed(my_piece);
+               RemovePiece(my_piece);
+               break;
+       }
+
+       // Update rank if revealed
+       if( moved_piece->Rank == RANK_UNKNOWN )
+               UpdateRank(moved_piece, gaBoardState[moved_piece->Y*giBoardWidth+moved_piece->X]);
+
+       // - Update piece states
+       DEBUG("Updating piece states");
+       for( int y = 0; y < giBoardHeight; y ++ )
+       {
+               for( int x = 0; x < giBoardWidth; x ++ )
+               {
+                       char    c = gaBoardState[y*giBoardWidth+x];
+                       if( c == '.' )  continue;
+                       if( c == '+' )  continue;
+                       tPiece *p = GetPieceByPos(x, y);
+                       if(!p) DEBUG("c = %c", c);
+                       ASSERT(p);
+                       if( p->Team == gMyColour )      continue ;
+                       if( p->Rank == RANK_UNKNOWN && c != '#' )
+                               UpdateRank(p, c);
+               }
+       }
+}
+
+void AI_DoMove(tMove *MyMove)
+{
+#if 1
+       // Sanity checks
+       for( int i = 0; i < N_PIECES; i ++ )
+       {
+               tPiece  *p = &gpCurrentGameState->MyActual.Pieces[i];
+               if(p->bDead)    continue;
+
+               if( p != GetPieceByPos(p->X, p->Y) ) {
+                       DEBUG("Piece %p(%i,%i R%i) not at stated position",
+                               p, p->X, p->Y, p->Rank);
+               }
+       }
+#endif
+
+       DEBUG("Deciding on move");
+       GetBestMove(&gpCurrentGameState->MyActual, &gpCurrentGameState->Opponent, MyMove, 0);
+}
+
+tPiece *GetPieceByPos(int X, int Y)
+{
+       tPieceRef       *pr = &gpCurrentGameState->BoardState[Y*giBoardWidth+X];
+       switch( pr->Team )
+       {
+       case 0: return NULL;
+       case 1: return &gpCurrentGameState->MyActual.Pieces[ (int)pr->Index ];
+       case 2: return &gpCurrentGameState->Opponent.Pieces[ (int)pr->Index ];
+       case 3: return &gBlockPiece;
+       }
+       return NULL;
+}
+
+void MovePieceTo(tPiece *Piece, int X, int Y)
+{
+       DEBUG("Moved %p(%i,%i) to (%i,%i)",
+               Piece, Piece->X, Piece->Y, X, Y);
+       
+       gpCurrentGameState->BoardState[Y*giBoardWidth + X]
+               = gpCurrentGameState->BoardState[Piece->Y*giBoardWidth + Piece->X];
+       gpCurrentGameState->BoardState[Piece->Y*giBoardWidth + Piece->X].Team = 0;
+
+       Piece->X = X;
+       Piece->Y = Y;
+
+       if( !Piece->bHasMoved )
+       {
+               if( Piece->Team == gMyColour )
+               {
+                       gpCurrentGameState->MyExposed.nMoved ++;
+               }
+               else
+               {
+                       gpCurrentGameState->Opponent.nMoved ++;
+               }
+       }
+       
+       Piece->bHasMoved = true;
+}
+
+void UpdateRank(tPiece *Piece, char RankChar)
+{
+       enum eRanks rank;
+
+       rank = CharToRank(RankChar);
+
+       if( Piece->Rank == rank )
+               return ;
+
+       if( Piece->Rank != RANK_UNKNOWN )
+       {
+               if(Piece->Rank != rank )
+               {
+                       DEBUG("Rank of piece %p(%i,%i) has changed, was %i now %i",
+                               Piece, Piece->X, Piece->Y, Piece->Rank, rank);
+                       Piece->Rank = rank;
+               }
+               return ;
+       }
+
+       if( Piece->Team == !gMyColour && rank != RANK_UNKNOWN )
+       {
+               if( gpCurrentGameState->Opponent.nRanks[rank] >= MAX_RANK_COUNTS[rank] ) {
+                       DEBUG("ERROR: Bookkeeping failed, >%i units of rank %i on board",
+                               MAX_RANK_COUNTS[rank], rank);
+               }
+               DEBUG("Found a %i", rank);
+               gpCurrentGameState->Opponent.nRanks[rank] ++;
+               if( gpCurrentGameState->Opponent.nIdentified == gpCurrentGameState->Opponent.nPieces ) {
+                       DEBUG("ERROR: Bookkeeping failed, >%i units identified",
+                               gpCurrentGameState->Opponent.nPieces);
+               }
+               gpCurrentGameState->Opponent.nIdentified ++;
+
+               if( Piece->GuessedRank != RANK_UNKNOWN && Piece->GuessedRank != rank )
+               {
+                       fprintf(stderr, "Assumption failed, saved %c != act %c",
+                               cRANK_CHARS[Piece->GuessedRank], cRANK_CHARS[rank]);
+                       gpCurrentGameState->Opponent.bGuessValid = false;
+               }
+
+       }
+       Piece->Rank = rank;
+       if( Piece->Team == !gMyColour )
+       {
+               // Expensive? What's that?
+               DB_WriteBackInitialState(gsOpponentDbFilename, !gMyColour, gpCurrentGameState->Opponent.Pieces);
+       }
+}
+
+void PieceExposed(tPiece *Piece)
+{
+       ASSERT(Piece->Team == gMyColour);
+       if( Piece->bExposed == false )
+       {
+               gpCurrentGameState->MyExposed.nRanks[Piece->Rank] ++;
+               gpCurrentGameState->MyExposed.nIdentified ++;
+               Piece->bExposed = true;
+       }
+}
+
+/**
+ * \brief Remove a piece from the board
+ */
+void RemovePiece(tPiece *Piece)
+{
+       tPlayerStats    *owner;
+       gpCurrentGameState->BoardState[Piece->Y*giBoardWidth + Piece->X].Team = 0;
+       if( Piece->Team == !gMyColour ) {
+               owner = &gpCurrentGameState->Opponent;
+       }
+       else {
+               owner = &gpCurrentGameState->MyExposed;
+               gpCurrentGameState->MyActual.nRanks[Piece->Rank] --;
+       }
+       owner->nKilledRanks[Piece->Rank] ++;
+       owner->nRanks[Piece->Rank] --;
+       owner->nIdentified --;
+       owner->nPieces --;
+       Piece->bDead = true;
+}
+
+// ----------------------------------------------------------------------------
+// - AI Core
+// ----------------------------------------------------------------------------
+#define TARGET_GRID_W  10
+#define TARGET_GRID_H  10
+#define TARGET_GRID_SIZE       (TARGET_GRID_W*TARGET_GRID_H)
+typedef struct sGridSlot {
+       tPiece  *p;
+       char    dist;
+       char    complexity;
+       enum eDirections        firstdir;
+       char    firstdist;
+       char    bDirect;
+} tTargetGrid[TARGET_GRID_SIZE];
+int GetTargetsFrom(tPiece *Piece, tTargetGrid *grid)
+{
+        int    n_targets;
+       
+       memset(*grid, 0, sizeof(*grid));
+
+       int cur_dist = 1;
+       int b_updates = 0;
+
+       void _check_dir(struct sGridSlot *pgs, struct sGridSlot *gs, int x, int y, enum eDirections dir)
+       {
+               if( !gs )       return ;
+               if( gs->dist )  return ;
+               if( pgs->p )    return ;
+
+               tPiece *p = GetPieceByPos(x, y);
+               if( p && (p == &gBlockPiece || p->Team == Piece->Team) )
+                       p = (void*)-1;
+               gs->dist = cur_dist + 1;
+               gs->p = p;
+               DEBUG("%p at %i,%i %i away", p, x, y, cur_dist);
+               if( pgs->firstdir == DIR_INVAL || (pgs->firstdir == dir && pgs->bDirect) ) {
+                       gs->bDirect = 1;
+                       gs->firstdir = dir;
+                       gs->firstdist = pgs->firstdist + 1;
+               }
+               else {
+                       gs->firstdist = pgs->firstdist;
+                       gs->firstdir = pgs->firstdir;
+                       gs->bDirect = 0;
+               }
+               b_updates = 1;
+       }
+
+       (*grid)[ Piece->X + Piece->Y * TARGET_GRID_W ].dist = -1;
+
+       do {
+               b_updates = 0;
+               for( int i = 0; i < TARGET_GRID_SIZE; i ++ )
+               {
+                       int x = i % TARGET_GRID_W;
+                       int y = i / TARGET_GRID_H;
+                       struct sGridSlot        *gs = &(*grid)[i];
+
+                       struct sGridSlot        *gs_u = NULL, *gs_d = NULL;
+                       struct sGridSlot        *gs_l = NULL, *gs_r = NULL;
+
+                       if( !gs->dist ) continue ;
+
+                       // Get adjacent cells
+                       if( y > 0 )
+                               gs_u = &(*grid)[i - TARGET_GRID_W];
+                       if( x > 0 )
+                               gs_l = &(*grid)[i - 1];
+                       if( y < TARGET_GRID_H - 1 )
+                               gs_d = &(*grid)[i + TARGET_GRID_W];
+                       if( x < TARGET_GRID_W - 1 )
+                               gs_r = &(*grid)[i + 1];
+                       
+                       _check_dir(gs, gs_u, x, y-1, DIR_UP);
+                       _check_dir(gs, gs_d, x, y+1, DIR_DOWN);
+                       _check_dir(gs, gs_l, x-1, y, DIR_LEFT);
+                       _check_dir(gs, gs_r, x+1, y, DIR_RIGHT);
+               }
+
+               cur_dist ++;
+       } while(b_updates);
+
+#if SHOW_TARGET_MAP
+       fprintf(stderr, "%p Type %c\n", Piece, cRANK_CHARS[Piece->Rank]);
+       for( int i = 0; i < 10*10; i ++ )
+       {
+               tPiece  *np = (*grid)[i].p;
+               if( i == Piece->X + Piece->Y * TARGET_GRID_W )
+                       fprintf(stderr, "?");
+               else if( (*grid)[i].dist == 0 )
+                       fprintf(stderr, "#");   // Unreachable
+               else if( !np )
+                       fprintf(stderr, " ");   // Empty
+               else if( np == (void*)-1 )
+                       fprintf(stderr, ".");   // My team/block
+               else
+                       fprintf(stderr, "X");   // Viable target!
+               if( i % 10 == 9 )
+                       fprintf(stderr, "\n");
+       }
+#endif
+
+       DEBUG("Getting targets");
+       n_targets = 0;
+       for( int i = 0; i < TARGET_GRID_SIZE; i ++ )
+       {
+               if( (*grid)[i].p == (void*)-1 )
+                       (*grid)[i].p = NULL;
+               if( (*grid)[i].p ) {
+                       DEBUG("Target (%i,%i) %p %i dist",
+                               i%10, i/10, (*grid)[i].p, (*grid)[i].dist);
+                       (*grid)[i].dist -= 1;
+                       n_targets ++;
+               }
+       }
+
+       return n_targets;
+}
+
+int GetBestMove(tPlayerStats *Attacker, tPlayerStats *Defender, tMove *Move, int Level)
+{
+       // Avoid infinite recursion
+       if( Level == MAX_SEARCH_DEPTH ) return 1;
+
+        int    best_score = INT_MIN;
+       tMove   best_move;
+       tPiece  *best_p = NULL;
+       tPiece  *best_target = NULL;
+       tTargetGrid     grid;
+
+       // - Check possible moves
+       for( int i = 0; i < N_PIECES; i ++ )
+       {
+               tPiece  *p = &Attacker->Pieces[i];
+                int    p_score = 0;    // Piece score
+               struct sGridSlot        *bt_gs = NULL;
+                int    bt_score;       // Best target score
+
+               // Dead, ignore
+               if( p->bDead )
+                       continue ;
+               // These cannot move
+               if( p->Rank == RANK_BOMB || p->Rank == RANK_FLAG )
+                       continue ;
+
+               // Get what pieces are able to be attacked from this piece
+               int nt = GetTargetsFrom(p, &grid);
+               DEBUG("(%i,%i) %i targets", p->X, p->Y, nt);
+               if( nt <= 0 )   continue ;
+
+               // Find the best target of those
+               for( int j = 0; j < TARGET_GRID_SIZE; j ++ )
+               {
+                       struct sGridSlot *gs = &grid[j];
+                       if( !gs->p )    continue ;
+
+                       int t_score = GetScore(p, gs->p);
+
+#if 1
+                       if( gs->p == gLastMove_Target && p == gLastMove_Piece && giNumRepeatedMove > REPEAT_THRESHOLD)
+                       {
+                               REPEAT_MOVE_MODIFY(t_score);
+                       }
+#endif
+
+                       // TODO: For scouts, use gs->complexity
+                       // TODO: Don't use a linear relationship on distance
+                       p_score += t_score / (gs->dist < 2 ? 1 : 2);
+
+                       // Best target
+                       if( !bt_gs || t_score > bt_score ) {
+                               bt_score = t_score;
+                               bt_gs = gs;
+                       }
+               }
+
+               DEBUG("p_score = %i, bt_score = %i", p_score, bt_score);
+
+               // Best move is towards that piece
+               if( best_move.dir == DIR_INVAL || best_score < p_score )
+               {
+                       best_move.dir = bt_gs->firstdir;
+                       best_move.x = p->X;
+                       best_move.y = p->Y;
+                       best_move.dist = (p->Rank == RANK_SCOUT) ? bt_gs->firstdist : 1;
+                       best_score = p_score;
+                       best_p = p;
+                       best_target = bt_gs->p;
+               }
+       }
+
+
+       if( Move )
+       {
+               ASSERT(best_move.dir != DIR_INVAL);
+               *Move = best_move;
+               
+               if( ((Move->dir-1)^1) == gLastMove.dir-1 && Move->dist == gLastMove.dist
+               && Move->x == gLastMove.x && Move->y == gLastMove.y )
+               {
+                       giNumRepeatedMove ++;
+                       DEBUG("Up to %i repititions", giNumRepeatedMove);
+               }
+               else
+                       giNumRepeatedMove = 0;
+
+               // TODO: Recurse once on this to determine what the other team will do
+               // Record that move, then check when the move is performed to see if we were right.
+
+               gLastMove = *Move;
+               gLastMove_Target = best_target;
+               gLastMove_Piece = best_p;
+               giTurnsSinceLastTake ++;
+       }
+
+       DEBUG("best_score = %i", best_score);
+
+       return best_score;
+}
+
+/**
+ * \brief 
+ */
+int GetScore(tPiece *This, tPiece *Target)
+{
+       tPlayerStats    *attacker, *defender;
+       int score;
+
+       if( This->Team == gMyColour ) {
+               defender = &gpCurrentGameState->Opponent;
+               attacker = &gpCurrentGameState->MyExposed;
+       }
+       else {
+               attacker = &gpCurrentGameState->Opponent;
+               defender = &gpCurrentGameState->MyExposed;
+       }
+
+       score = GetRawScore(This, Target);
+
+       if( This->Team == gMyColour )
+       {
+               switch( This->Rank )
+               {
+               case RANK_MARSHAL:      // Marshal has balls of steel if the spy and enemy marshal are dead
+                       if( defender->nKilledRanks[RANK_MARSHAL] && defender->nKilledRanks[RANK_SPY] )
+                               score *= 2;
+                       break;
+               case RANK_GENERAL:      // General always attacks!
+                       score *= 2;
+                       break;
+               case RANK_SCOUT:
+                       score = score * gpCurrentGameState->MyActual.nRanks[RANK_SCOUT] / MAX_RANK_COUNTS[RANK_SCOUT] + score;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return score;
+}
+
+int GetRawScore(tPiece *This, tPiece *Target)
+{
+       tPlayerStats    *this_team, *target_team;
+       
+       ASSERT( This->Team != Target->Team );
+
+       if( This->Team == gMyColour ) {
+               target_team = &gpCurrentGameState->Opponent;
+               this_team = &gpCurrentGameState->MyExposed;
+       }
+       else {
+               this_team = &gpCurrentGameState->Opponent;
+               target_team = &gpCurrentGameState->MyExposed;
+       }
+
+       // Both ranks known, used fixed rules
+       if( This->Rank != RANK_UNKNOWN && Target->Rank != RANK_UNKNOWN )
+       {
+               return GetOutcome(This->Rank, Target->Rank);
+       }
+       // If it's our move, and the guesses are valid, then use the guess
+       else if( This->Team == gMyColour
+               && gpCurrentGameState->Opponent.bGuessValid
+               && Target->GuessedRank != RANK_UNKNOWN
+               )
+       {
+               return GetOutcome(This->Rank, Target->GuessedRank);
+       }
+       else
+       {
+                int    sum = 0;
+                int    max = Target->bHasMoved ? RANK_SPY : RANK_FLAG;
+                int    count = 0;
+
+               if( target_team->nIdentified >= target_team->nPieces ) {
+                       DEBUG("%i >= %i, what the fsck",
+                               target_team->nIdentified, target_team->nPieces);
+               }
+               ASSERT(target_team->nPieces > target_team->nIdentified);
+
+               for( int i = RANK_MARSHAL; i <= max; i ++ )
+               {
+                        int    n_unk = MAX_RANK_COUNTS[i] - (target_team->nRanks[i] + target_team->nKilledRanks[i]);
+                       if( n_unk == 0 )
+                               continue ;
+                       ASSERT( n_unk > 0 );
+
+                       // TODO: Fiddle with outcome score depending on respective ranks
+                       sum += n_unk * GetOutcome(This->Rank, i);
+                       count += n_unk;
+               }
+
+//             if( Target->bHasMoved )
+//                     sum /= target_team->nPieces - target_team->nMoved;
+//             else
+//                     sum /= target_team->nPieces - target_team->nIdentified;
+               sum /= count;
+
+               if( sum > OC_FLAG ) {
+                       fprintf(stderr, "sum (%i) > OC_WIN (%i) -- nUnIdent=%i\n",
+                               sum, OC_WIN, target_team->nPieces - target_team->nIdentified);
+                       ASSERT( sum <= OC_FLAG );
+               }
+
+               return sum - ABS(sum) / 10;
+       }
+}
+
+static inline int GetOutcome(int Attacker, int Defender)
+{
+       if( Attacker == 0 )     return OC_UNK;
+       if( Defender == 0 )     return OC_UNK;
+
+       if( Defender == RANK_FLAG )
+               return OC_FLAG;
+
+       if( Attacker != RANK_MINER && Defender == RANK_BOMB )
+               return OC_LOSE;
+       if( Attacker == RANK_MINER && Defender == RANK_BOMB )
+               return OC_WIN;
+
+       if( Attacker == RANK_SPY && Defender == RANK_MARSHAL )
+               return OC_WIN;
+
+       if( Attacker == Defender )
+               return OC_DRAW;
+
+       if( Attacker < Defender )
+               return OC_WIN;
+       else
+               return OC_LOSE;
+}
+
+
+static inline int ABS(int Val)
+{
+       return Val < 0 ? -Val : Val;
+}
+
+static inline int RANGE(int Min, int Val, int Max)
+{
+       return Min <= Val && Val <= Max;
+}
+
diff --git a/agents/ramen/src/ai.o b/agents/ramen/src/ai.o
new file mode 100644 (file)
index 0000000..39db28e
Binary files /dev/null and b/agents/ramen/src/ai.o differ
diff --git a/agents/ramen/src/ai.o.dep b/agents/ramen/src/ai.o.dep
new file mode 100644 (file)
index 0000000..ed132fc
--- /dev/null
@@ -0,0 +1 @@
+ai.o: ai.c interface.h ai_common.h
diff --git a/agents/ramen/src/ai_common.h b/agents/ramen/src/ai_common.h
new file mode 100644 (file)
index 0000000..0793659
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * UCC 2012 Programming Competition Entry
+ * - "Ramen"
+ *
+ * By John Hodge [TPG]
+ */
+#ifndef _AI_COMMON_H_
+#define _AI_COMMON_H_
+
+#include "interface.h"
+
+#define N_PIECES       40
+
+enum eRanks
+{
+       RANK_UNKNOWN,   //  0
+       RANK_MARSHAL,   //  1
+       RANK_GENERAL,   //  2
+       RANK_COLONEL,   //  3
+       RANK_MAJOR,     //  4
+       RANK_CAPTAIN,   //  5
+       RANK_LIEUTENANT,//  6
+       RANK_SERGEANT,  //  7
+       RANK_MINER,     //  8
+       RANK_SCOUT,     //  9
+       RANK_SPY,       // 10
+       RANK_BOMB,      // 11
+       RANK_FLAG,      // 12
+       N_RANKS
+};
+static const int MAX_RANK_COUNTS[N_RANKS] = {
+       40, 1, 1, 2, 3, 4, 4, 4, 5, 8, 1, 6, 1
+};
+static const char cRANK_CHARS[N_RANKS] = "#123456789sBF";
+static inline enum eRanks CharToRank(char ch)
+{
+       switch(ch)
+       {
+       case '1':       return RANK_MARSHAL;
+       case '2':       return RANK_GENERAL;
+       case '3':       return RANK_COLONEL;
+       case '4':       return RANK_MAJOR;
+       case '5':       return RANK_CAPTAIN;
+       case '6':       return RANK_LIEUTENANT;
+       case '7':       return RANK_SERGEANT;
+       case '8':       return RANK_MINER;
+       case '9':       return RANK_SCOUT;
+       case 's':       return RANK_SPY;
+       case 'B':       return RANK_BOMB;
+       case 'F':       return RANK_FLAG;
+       case '#':       return RANK_UNKNOWN;
+       default:
+               // Wut. Unkown
+               DEBUG("Unknown character '%c'", ch);
+               return RANK_UNKNOWN;
+       }
+}
+
+/**
+ */
+typedef struct sPiece
+{
+        int    X, Y;
+       BOOL    bDead;
+       enum eRanks     Rank;   // -1 = unknown
+       BOOL    bHasMoved;
+       enum eColours   Team;
+       // TODO: Keep last moved
+       
+       BOOL    bExposed;       // Marks when the piece is known by the other team
+
+        int    StartX, StartY; // Used to save initial layout
+       enum eRanks     GuessedRank;    // Only used it bGuessValid is set
+} tPiece;
+
+typedef struct sPlayerStats
+{
+       enum eColours   Colour;
+        int    nPieces;
+        int    nMoved;
+        int    nIdentified;
+        int    nRanks[N_RANKS];
+        int    nKilledRanks[N_RANKS];
+       tPiece  Pieces[N_PIECES];
+       BOOL    bGuessValid;
+} tPlayerStats;
+
+typedef struct sPieceRef
+{
+       char    Index;  // Index into tPlayerStats.Pieces
+       char    Team;   // 0 = Empty, 1 = Me, 2 = Opponent, 3 = Block
+} tPieceRef;
+
+typedef struct sGameState
+{
+       tPlayerStats    Opponent;
+       tPlayerStats    MyExposed;
+       tPlayerStats    MyActual;
+       tPieceRef       BoardState[];   // 
+} tGameState;
+
+// --- Database
+extern char    *DB_GetOpponentFile(const char *Opponent);
+extern void    DB_LoadGuesses(const char *DBFile, enum eColours Colour);
+extern void    DB_WriteBackInitialState(const char *DBFile, enum eColours Colour, tPiece *Pieces);
+
+#endif
+
diff --git a/agents/ramen/src/db.c b/agents/ramen/src/db.c
new file mode 100644 (file)
index 0000000..a62d44a
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * UCC 2012 Programming Competition Entry
+ * - "Ramen"
+ *
+ * By John Hodge [TPG]
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "ai_common.h"
+#include <stdint.h>
+#include <string.h>
+
+#define TAG_BOARDSTATE 0x7342
+
+typedef struct sTag
+{
+       uint16_t        Tag;
+       uint16_t        Length;
+} tTag;
+
+typedef struct sSavedBoardState
+{
+       uint8_t         W, H;
+       uint16_t        Count;
+       char    NormalisedBoard[];
+} tSavedBoardState;
+
+// === PROTOTYPES ===
+tSavedBoardState       *DB_int_ReadState(FILE *fp, off_t *offset);
+void   DB_int_AppendTag(FILE *fp, uint16_t Tag, uint16_t Size, void *Data);
+
+// === CODE ===
+char *DB_GetOpponentFile(const char *Opponent)
+{
+       uint32_t        checksum = 0;
+
+       {
+                int    ofs = 0;
+               const char *str = Opponent;
+               while( *str )
+               {
+                       checksum ^= *str << ofs;
+                       str ++;
+                       ofs += 5;
+                       ofs %= 32 - 5;
+               }
+       }
+       
+       const char      *filename = NULL;
+        int    filenamelen = 0;
+       {
+               const char *last_slash = NULL;
+               const char *last_dot = NULL;
+               const char *str = Opponent;
+               while( *str )
+               {
+                       if(*str == '/') last_slash = str;
+                       if(*str == '.') last_dot = str;
+                       str ++;
+               }
+               filename = last_slash + 1;
+               if( last_slash > last_dot )
+                       filenamelen = str - filename;
+               else
+                       filenamelen = last_dot - filename;
+       }
+
+       int len = snprintf(NULL, 0, "%08x_%.*s.ramen", checksum, filenamelen, filename);
+       char *ret = malloc(len+1);
+       snprintf(ret, len+1, "%08x_%.*s.ramen", checksum, filenamelen, filename);
+//     fprintf(stderr, "DB File = '%s'\n", ret);
+       return ret;
+}
+
+void DB_LoadGuesses(const char *DBFile, enum eColours Colour)
+{
+       FILE    *fp;
+       off_t   offset = 0;
+       tSavedBoardState        *saved_board = NULL;
+
+       fp = fopen(DBFile, "r+");
+       if(!fp) return ;
+
+       // Read board states, checking for a same state
+       while( (saved_board = DB_int_ReadState(fp, &offset)) )
+       {
+               if( saved_board->W != giBoardWidth )
+                       continue ;
+               if( saved_board->H != giBoardHeight )
+                       continue ;
+               break;
+       }
+
+       // TODO: Combine counts of how many times a state has been played
+
+       if( saved_board )
+       {
+               char    bs[giBoardWidth*4];
+                int    ofs = 0;
+
+
+               if( Colour != COLOUR_RED )
+               {
+                       ofs = giBoardHeight-4;
+                       char    *bs2 = saved_board->NormalisedBoard;
+                       memcpy(bs + giBoardWidth*0, bs2 + giBoardWidth*(4-1), giBoardWidth);
+                       memcpy(bs + giBoardWidth*1, bs2 + giBoardWidth*(4-2), giBoardWidth);
+                       memcpy(bs + giBoardWidth*2, bs2 + giBoardWidth*(4-3), giBoardWidth);
+                       memcpy(bs + giBoardWidth*3, bs2 + giBoardWidth*(4-4), giBoardWidth);
+               }
+               else
+               {
+                       memcpy(bs, saved_board->NormalisedBoard, giBoardWidth*4);
+               }
+//             for( int i = 0; i < 4; i ++ ) {
+//                     fprintf(stderr, "%.*s\n", giBoardWidth, bs + giBoardWidth*i);
+//             }
+
+               // Set guessed ranks
+               for( int i = 0; i < giBoardWidth*4; i ++ )
+               {
+                       tPiece  *p = GetPieceByPos(i % giBoardWidth, i/giBoardWidth + ofs );
+//                     fprintf(stderr, "%c", bs[i]);
+//                     if(i % giBoardWidth == giBoardWidth-1)
+//                             fprintf(stderr, "\n");
+                       if( bs[i] == '\0' && p )
+                               break;
+                       if( bs[i] != '\0' && !p )
+                               break;
+                       if( p )
+                               p->GuessedRank = CharToRank(bs[i]);
+               }
+       }
+
+       fclose(fp);
+}
+
+void DB_WriteBackInitialState(const char *DBFile, enum eColours Colour, tPiece *Pieces)
+{
+       char    bs[giBoardHeight*giBoardWidth];
+       memset(bs, 0, sizeof(bs));
+
+       for( int i = 0; i < N_PIECES; i ++ )
+       {
+               if( Pieces[i].StartY < 0 )      continue ;
+               char    *bp = &bs[ Pieces[i].StartY*giBoardWidth + Pieces[i].StartX ];
+
+               if( *bp != '\0' )
+               {
+                       // Oops?
+               }
+               else
+               {
+                       *bp = cRANK_CHARS[ Pieces[i].Rank ];
+               }
+       }
+
+       // Normalise board to RED
+       if( Colour != COLOUR_RED )
+       {
+               memcpy(bs + giBoardWidth*0, bs + giBoardWidth*(giBoardHeight-1), giBoardWidth);
+               memcpy(bs + giBoardWidth*1, bs + giBoardWidth*(giBoardHeight-2), giBoardWidth);
+               memcpy(bs + giBoardWidth*2, bs + giBoardWidth*(giBoardHeight-3), giBoardWidth);
+               memcpy(bs + giBoardWidth*3, bs + giBoardWidth*(giBoardHeight-4), giBoardWidth);
+       }
+
+
+       off_t   offset;
+       tSavedBoardState        *saved_board;
+       FILE *fp = fopen(DBFile, "r+");
+       if( !fp ) {
+               fp = fopen(DBFile, "w");
+       }
+
+       // Read board states, checking for a same state
+       while( (saved_board = DB_int_ReadState(fp, &offset)) )
+       {
+//             fprintf(stderr, "DBG: %i == %i? and %i == %i\n",
+//                     saved_board->W, giBoardWidth, saved_board->H, giBoardHeight
+//                     );
+
+               if( saved_board->W != giBoardWidth )
+                       continue ;
+               if( saved_board->H != giBoardHeight )
+                       continue ;
+
+               BOOL    b_different = false;
+
+               for( int i = 0; i < 4*giBoardWidth; i ++ )
+               {
+                       if( saved_board->NormalisedBoard[i] == '#' || bs[i] == '#' )
+                               continue ;
+                       if( saved_board->NormalisedBoard[i] != bs[i] ) {
+                               fprintf(stderr, "DBG: '%c' != '%c'\n", saved_board->NormalisedBoard[i], bs[i]);
+                               b_different = true;
+                               break;
+                       }
+               }
+
+               if( b_different )       continue ;
+
+               break;
+       }
+
+       if( saved_board )
+       {
+               saved_board->Count ++;
+               fseek(fp, offset, SEEK_SET);
+               // Merge
+               for( int i = 0; i < 4*giBoardWidth; i ++ )
+               {
+                       if( saved_board->NormalisedBoard[i] == '#' )
+                               saved_board->NormalisedBoard[i] = bs[i];
+               }
+               // Write back
+               fwrite(saved_board, sizeof(*saved_board) + giBoardWidth*4, 1, fp);
+       }
+       else
+       {
+               saved_board = malloc( sizeof(*saved_board) + giBoardWidth*4 );
+               saved_board->W = giBoardWidth;
+               saved_board->H = giBoardHeight;
+               saved_board->Count = 1;
+               memcpy(saved_board->NormalisedBoard, bs, 4*giBoardWidth);
+               DB_int_AppendTag(fp, TAG_BOARDSTATE, sizeof(*saved_board) + giBoardWidth*4, saved_board);
+       }
+       free(saved_board);
+
+       fclose(fp);
+}
+
+tSavedBoardState *DB_int_ReadState(FILE *fp, off_t *offset)
+{
+       tTag    tag;
+       tSavedBoardState        *ret = NULL;
+
+       do {
+               if( fread(&tag, sizeof(tag), 1, fp) != 1 )
+                       break ;
+               if( tag.Tag == TAG_BOARDSTATE )
+               {
+                       *offset = ftell(fp);
+                       ret = malloc(tag.Length);
+                       fread(ret, tag.Length, 1, fp);
+               }
+               fseek(fp, tag.Length, SEEK_CUR);
+       } while(!ret);
+
+       return ret;
+}
+
+void DB_int_AppendTag(FILE *fp, uint16_t Tag, uint16_t Size, void *Data)
+{
+       fseek(fp, 0, SEEK_END);
+       fwrite(&Tag, sizeof(uint16_t), 1, fp);
+       fwrite(&Size, sizeof(uint16_t), 1, fp);
+       fwrite(Data, Size, 1, fp);
+}
diff --git a/agents/ramen/src/db.o b/agents/ramen/src/db.o
new file mode 100644 (file)
index 0000000..28ca7ce
Binary files /dev/null and b/agents/ramen/src/db.o differ
diff --git a/agents/ramen/src/db.o.dep b/agents/ramen/src/db.o.dep
new file mode 100644 (file)
index 0000000..f0eb37c
--- /dev/null
@@ -0,0 +1 @@
+db.o: db.c ai_common.h interface.h
diff --git a/agents/ramen/src/interface.h b/agents/ramen/src/interface.h
new file mode 100644 (file)
index 0000000..cb7e949
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * UCC 2012 Programming Competition Entry
+ * - "Ramen"
+ *
+ * By John Hodge [TPG]
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#if ENABLE_DEBUG
+# define DEBUG(s, a...)        fprintf(stderr, "DEBUG: "s"\n" ,## a)
+#else
+# define DEBUG(...)    do{}while(0)
+#endif
+#define ASSERT(val)    do{if(!(val)){fprintf(stderr, "ASSERTION FAILED - " #val " at %s:%i\n", __FILE__, __LINE__);exit(-1);} }while(0)
+
+
+#define true   1
+#define false  0
+typedef char   BOOL;
+
+typedef struct sMove   tMove;
+
+enum eDirections
+{
+       DIR_INVAL,
+       DIR_LEFT,
+       DIR_RIGHT,
+       DIR_UP,
+       DIR_DOWN
+};
+
+enum eColours
+{
+       COLOUR_RED,
+       COLOUR_BLUE
+};
+
+enum eResult
+{
+       RESULT_INVAL,
+       RESULT_ILLEGAL,
+       RESULT_OK,
+       RESULT_KILL,
+       RESULT_DIES,
+       RESULT_BOTHDIE,
+       RESULT_VICTORY
+};
+
+struct sMove
+{
+       char    x, y;
+       enum eDirections        dir;    // eDirections
+       char    dist;
+
+       enum eResult    result;
+       char    attacker;
+       char    defender;
+};
+
+extern int     giBoardWidth;
+extern int     giBoardHeight;
+extern char    *gaBoardState;
+
+extern void    AI_Initialise(enum eColours Colour, const char *Opponent);
+extern void    AI_HandleMove(int bMyMove, const tMove *Move);
+extern void    AI_DoMove(tMove *MyMove);
+
+#endif
+
diff --git a/agents/ramen/src/main.c b/agents/ramen/src/main.c
new file mode 100644 (file)
index 0000000..a9a2d71
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * UCC 2012 Programming Competition Entry
+ * - "Ramen"
+ *
+ * By John Hodge [TPG]
+ */
+#define ENABLE_DEBUG   0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include "interface.h"
+
+// === CONSTANTS ===
+static const char *DIR_NAMES[] = {"INVL", "LEFT", "RIGHT", "UP", "DOWN"};
+
+// === PROTOTYPES ===
+ int   main(int argc, char *argv[]);
+void   GetMove(char *line, tMove *Move);
+void   ReadBoardState(FILE *stream, char *dest);
+ int   RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage);
+void   CompileRegex(regex_t *regex, const char *pattern, int flags);
+
+// === GLOBALS ===
+regex_t        gRegex_move;
+regex_t        gRegex_res;
+ int   giBoardWidth;
+ int   giBoardHeight;
+char   *gaBoardState;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       setbuf(stdin, NULL);
+       setbuf(stdout, NULL);
+
+       // $X $Y $DIRECTION [$MULTIPLIER=1] $OUTCOME
+       CompileRegex(&gRegex_move, "([0-9]+) ([0-9]+) ([A-Z]+)( [0-9]+)? (.*)", REG_EXTENDED);
+       // (KILLS|DIES|BOTHDIE) $ATTACKER_RANK $DEFENDER_RANK
+       CompileRegex(&gRegex_res, "([A-Z_]+) (.) (.)", REG_EXTENDED);
+
+       {
+                int    colour_id;
+               char    colour[6];
+               char    opponent[128];
+               fscanf(stdin, "%s %s %i %i", colour, opponent, &giBoardWidth, &giBoardHeight);
+
+               if( strcmp(colour, "RED") == 0 )
+                       colour_id = COLOUR_RED;
+               else if( strcmp(colour, "BLUE") == 0 )
+                       colour_id = COLOUR_BLUE;
+               else {
+                       fprintf(stderr, "Oops... nutty manager, colour = %s\n", colour);
+                       colour_id = COLOUR_RED;
+               }
+
+               DEBUG("colour=%i, opponent='%s', dims = %ix%i", colour_id, opponent, giBoardWidth, giBoardHeight);
+
+               AI_Initialise(colour_id, opponent);
+       }
+       
+       gaBoardState = malloc(giBoardWidth*giBoardHeight);
+
+       for( ;; )
+       {
+               tMove   mymove, opponent_move;
+               char    line[32];
+
+//             DEBUG("Waiting for move");
+               ASSERT( fgets(line, sizeof(line), stdin) != NULL );
+//             DEBUG("pm line = '%s'", line);
+
+               if( strcmp(line, "\n") == 0 )
+                       continue ;
+
+               if( strcmp(line, "START\n") == 0 )
+               {
+//                     DEBUG("New game");
+                       ReadBoardState(stdin, gaBoardState);
+                       // TODO: Check if this hasn't happened before
+                       opponent_move.x = 0;
+                       opponent_move.y = 0;
+                       opponent_move.dist = 0;
+                       opponent_move.dir = 0;
+               }
+               else if( strncmp(line, "QUIT", 4) == 0 )
+               {
+                       // TODO: Result?
+                       break ;
+               }
+               else if( strcmp(line, "VICTORY_FLAG\n") == 0 )
+               {
+                       // I win!
+                       break;
+               }
+               else
+               {
+//                     DEBUG("GetMove");
+                       GetMove(line, &opponent_move);
+//                     DEBUG("Read board state");
+                       ReadBoardState(stdin, gaBoardState);
+               }
+               DEBUG("Opposing move %i,%i dir %i dist %i",
+                       opponent_move.x, opponent_move.y, opponent_move.dir, opponent_move.dist);
+
+               // Silly opponent, you lost
+               if( opponent_move.result == RESULT_VICTORY )
+                       break;
+
+               // Determine move
+               AI_HandleMove(0, &opponent_move);
+               AI_DoMove(&mymove);
+               DEBUG("Chose move %i,%i %i %i", mymove.x, mymove.y, mymove.dir, mymove.dist);
+               printf("%i %i %s %i\n", mymove.x, mymove.y, DIR_NAMES[mymove.dir], mymove.dist);
+
+               // Get result of the move
+               ASSERT( fgets(line, sizeof(line), stdin) != NULL );
+//             DEBUG("res line = '%s'", line);
+//
+               GetMove(line, &mymove);
+               AI_HandleMove(1, &mymove);
+
+               // I WON!
+               if( mymove.result == RESULT_VICTORY )
+                       break;
+
+//             DEBUG("Move over");
+       }
+
+       return 0;
+}
+
+void GetMove(char *line, tMove *Move)
+{
+       regmatch_t      matches[1+5];
+
+       // regex (\d+) (\d+) ([A-Z]*)(?: (\d+))?
+       RunRegex(&gRegex_move, line, 1+5, matches, "Move line");
+
+       char *xstr = line + matches[1].rm_so;
+       char *ystr = line + matches[2].rm_so;
+       char *dirstr = line + matches[3].rm_so;
+
+       Move->x = atoi(xstr);
+       Move->y = atoi(ystr);
+//     DEBUG("(%i,%i)", Move->x, Move->y);
+       // Direction
+            if( strncmp(dirstr, "UP",    2) == 0 )
+               Move->dir = DIR_UP;
+       else if( strncmp(dirstr, "DOWN",  4) == 0 )
+               Move->dir = DIR_DOWN;
+       else if( strncmp(dirstr, "LEFT",  4) == 0 )
+               Move->dir = DIR_LEFT;
+       else if( strncmp(dirstr, "RIGHT", 5) == 0 )
+               Move->dir = DIR_RIGHT;
+       else {
+               fprintf(stderr, "Is the manager nuts? Dir = %.*s unk\n",
+                       matches[3].rm_eo + matches[3].rm_so, dirstr
+                       );
+               fprintf(stderr, "line = '%s'\n", line);
+               Move->dir = DIR_INVAL;
+       }
+       if( matches[4].rm_so >= 0 )
+               Move->dist = atoi(line + matches[4].rm_so + 1);
+       else
+               Move->dist = 1;
+       
+       // Outcome
+       char    *outcome = line + matches[5].rm_so;
+       if( strncmp(outcome, "OK", 2) == 0 )
+               Move->result = RESULT_OK;
+       else if( strncmp(outcome, "ILLEGAL", 7) == 0 )
+               Move->result = RESULT_ILLEGAL;
+       else if( strncmp(outcome, "VICTORY_FLAG", 12) == 0 )
+               Move->result = RESULT_VICTORY;
+       else if( strncmp(outcome, "VICTORY_ATTRITION", 17) == 0 )
+               Move->result = RESULT_VICTORY;
+       else
+       {
+               regmatch_t res_matches[3+1];
+               RunRegex(&gRegex_res, outcome, 3+1, res_matches, "Result portion");
+
+               char *res_str = outcome + res_matches[1].rm_so;
+                    if( strncmp(res_str, "KILLS ", 6) == 0 )
+                       Move->result = RESULT_KILL;
+               else if( strncmp(res_str, "DIES ", 5) == 0 )
+                       Move->result = RESULT_DIES;
+               else if( strncmp(res_str, "BOTHDIE ", 8) == 0 )
+                       Move->result = RESULT_BOTHDIE;
+               else {
+                       fprintf(stderr, "Is the manager nuts? Result = %.*s\n",
+                               res_matches[1].rm_eo + res_matches[1].rm_so, res_str
+                              );
+                       Move->result = RESULT_INVAL;
+               }
+
+               Move->attacker = *(outcome + res_matches[2].rm_so);
+               Move->defender = *(outcome + res_matches[3].rm_so);
+       }
+}
+
+void ReadBoardState(FILE *stream, char *dest)
+{
+       for( int i = 0; i < giBoardHeight; i ++ )
+       {
+               char    tmp[giBoardWidth+2];
+               fgets(tmp, sizeof(tmp), stream);
+               DEBUG("BS %.*s", giBoardWidth, tmp);
+               memcpy(dest+i*giBoardWidth, tmp, giBoardWidth);
+       }
+}
+
+int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
+{
+        int    ret;
+       
+       ret = regexec(regex, string, nMatches, matches, 0);
+       if( ret ) {
+               size_t  len = regerror(ret, regex, NULL, 0);
+               char    errorStr[len];
+               regerror(ret, regex, errorStr, len);
+               fprintf(stderr, "string = '%s'\n", string);
+               fprintf(stderr, "%s\n%s", errorMessage, errorStr);
+               exit(-1);
+       }
+       
+       return ret;
+}
+
+void CompileRegex(regex_t *regex, const char *pattern, int flags)
+{
+        int    ret = regcomp(regex, pattern, flags);
+       if( ret ) {
+               size_t  len = regerror(ret, regex, NULL, 0);
+               char    errorStr[len];
+               regerror(ret, regex, errorStr, len);
+               fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
+               exit(-1);
+       }
+}
diff --git a/agents/ramen/src/main.o b/agents/ramen/src/main.o
new file mode 100644 (file)
index 0000000..2c66953
Binary files /dev/null and b/agents/ramen/src/main.o differ
diff --git a/agents/ramen/src/main.o.dep b/agents/ramen/src/main.o.dep
new file mode 100644 (file)
index 0000000..b832325
--- /dev/null
@@ -0,0 +1 @@
+main.o: main.c interface.h
diff --git a/agents/vixen/basic_python.pyc b/agents/vixen/basic_python.pyc
new file mode 100644 (file)
index 0000000..4b3cf00
Binary files /dev/null and b/agents/vixen/basic_python.pyc differ
diff --git a/agents/vixen/path.pyc b/agents/vixen/path.pyc
new file mode 100644 (file)
index 0000000..9d84840
Binary files /dev/null and b/agents/vixen/path.pyc differ

UCC git Repository :: git.ucc.asn.au