diff --git a/agents/celsius/celsius.py b/agents/celsius/celsius.py
index cc71b90ba8c936ce53e509d1a2fca455c9e5b5e8..c3e601771a27ee9bca15f4378ab2f25974a915d4 100755
--- a/agents/celsius/celsius.py
+++ b/agents/celsius/celsius.py
@@ -245,6 +245,8 @@ class SulixAI:
 		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.numEnemies = 6+1+1+2+3+4+4+4+5+8+1+1
+		self.numStillEnemies = 6+1
 		self.lastMoved = None
 
 		
@@ -318,7 +320,7 @@ class SulixAI:
 
 
 							if override == 1:
-								scare = 999
+								scare = 998
 							elif override == -1:
 								piece.turnCount = 0
 								print str(piece.x) + " " + str(piece.y) + " " + directions[dirIndex]
@@ -485,6 +487,11 @@ class SulixAI:
 			elif attacker.colour == oppositeColour(self.colour):
 				self.totalEnemies[attacker.rank] -= 1
 				self.enemyUnits.remove(attacker)
+			if attacker.rank == 'B':
+				self.numStillEnemies -= 1
+				#if self.numStillEnemies == 0: # There are no bombs left
+				for i in range(0,ranks['s']):
+					scaretable[i][ranks['?']] -= 2
 
 		elif outcome == "BOTHDIE":
 			self.board[p[0]][p[1]] = None
@@ -502,7 +509,6 @@ class SulixAI:
 			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
@@ -513,6 +519,9 @@ class SulixAI:
 			#sys.stderr.write("	Don't understand outcome \"" + outcome + "\"!\n");
 			return False
 
+
+		
+
 		#sys.stderr.write("	Completed interpreting move!\n");		
 		return True
 
diff --git a/agents/celsius/celsius.py~ b/agents/celsius/celsius.py~
new file mode 100755
index 0000000000000000000000000000000000000000..4af35229c080eea0daa42ec810c8752673b060c7
--- /dev/null
+++ b/agents/celsius/celsius.py~
@@ -0,0 +1,548 @@
+#!/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.numEnemies = 6+1+1+2+3+4+4+4+5+8+1+1
+		self.numStillEnemies = 6+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 = 998
+							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)
+			if attacker.rank == 'B':
+				self.numStillEnemies -= 1
+				#if self.numStillEnemies == 0: # There are no bombs left
+				for i in range(0,ranks['s']):
+					scaretable[i][ranks['?']] -= 5
+
+		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
+