From 2120cc40abf9e3fd763c84a1e09b61064bb40be6 Mon Sep 17 00:00:00 2001
From: Sam Moore <matches@ucc.asn.au>
Date: Wed, 7 Dec 2011 12:32:56 +0800
Subject: [PATCH] Modified manager output/protocol, added "basic" AI, made
 Asmodeus better

Thats all
---
 manager/controller.cpp                |  12 +-
 manager/controller.h                  |   2 +-
 manager/game.cpp                      | 108 +++--
 manager/game.h                        |   3 +-
 manager/main.cpp                      | 140 ++++---
 manager/manual.txt                    |  89 ++--
 manager/movementresult.h              |   2 +-
 manager/program.cpp                   |  45 ++-
 manager/program.h                     |   1 +
 manager/stratego.cpp                  |  84 +++-
 manager/stratego.h                    |  21 +-
 samples/asmodeus/asmodeus.py          | 239 +++--------
 samples/asmodeus/asmodeus.pyc         | Bin 0 -> 3232 bytes
 samples/asmodeus/basic_python.py      |   1 +
 samples/asmodeus/basic_python.pyc     | Bin 0 -> 9110 bytes
 samples/asmodeus/info                 |   2 +-
 samples/asmodeus/path.py              |  57 +++
 samples/asmodeus/path.pyc             | Bin 0 -> 2085 bytes
 samples/asmodeus/run.py               |   8 +
 samples/basic_cpp/Makefile            |  30 ++
 samples/basic_cpp/basic_cpp           | Bin 0 -> 144981 bytes
 samples/basic_cpp/basic_cpp.cpp       | 560 ++++++++++++++++++++++++++
 samples/basic_cpp/basic_cpp.h         | 145 +++++++
 samples/basic_cpp/info                |   1 +
 samples/basic_python/basic_python.py  | 292 ++++++++++++++
 samples/basic_python/basic_python.pyc | Bin 0 -> 9170 bytes
 samples/basic_python/info             |   1 +
 samples/basic_python/run.py           |   8 +
 simulator/Makefile                    |  15 +
 simulator/simulate.py                 | 111 ++---
 30 files changed, 1615 insertions(+), 362 deletions(-)
 mode change 100755 => 100644 samples/asmodeus/asmodeus.py
 create mode 100644 samples/asmodeus/asmodeus.pyc
 create mode 120000 samples/asmodeus/basic_python.py
 create mode 100644 samples/asmodeus/basic_python.pyc
 create mode 100644 samples/asmodeus/path.py
 create mode 100644 samples/asmodeus/path.pyc
 create mode 100755 samples/asmodeus/run.py
 create mode 100644 samples/basic_cpp/Makefile
 create mode 100755 samples/basic_cpp/basic_cpp
 create mode 100644 samples/basic_cpp/basic_cpp.cpp
 create mode 100644 samples/basic_cpp/basic_cpp.h
 create mode 100644 samples/basic_cpp/info
 create mode 100644 samples/basic_python/basic_python.py
 create mode 100644 samples/basic_python/basic_python.pyc
 create mode 100644 samples/basic_python/info
 create mode 100755 samples/basic_python/run.py
 create mode 100644 simulator/Makefile

diff --git a/manager/controller.cpp b/manager/controller.cpp
index b7ab105..e68c1dc 100644
--- a/manager/controller.cpp
+++ b/manager/controller.cpp
@@ -80,6 +80,16 @@ MovementResult Controller::MakeMove(string & buffer)
 	if (query != MovementResult::OK)
 		return query;
 
+	if (buffer == "NO_MOVE")
+	{
+		buffer += " OK";
+		return MovementResult::OK;
+	}
+	if (buffer == "SURRENDER")
+	{
+		buffer += " OK";
+		return MovementResult::SURRENDER;
+	}
 	
 	int x; int y; string direction="";
 	stringstream s(buffer);
@@ -149,7 +159,7 @@ MovementResult Controller::MakeMove(string & buffer)
 	}
 
 	if (Game::theGame->allowIllegalMoves && !Board::LegalResult(moveResult))
-		return MovementResult::OK; //HACK - Legal results returned!
+		return MovementResult::OK; //HACK - Illegal results returned as legal!
 	else
 		return moveResult; 	
 
diff --git a/manager/controller.h b/manager/controller.h
index 1a8ce02..24f0c0d 100644
--- a/manager/controller.h
+++ b/manager/controller.h
@@ -21,7 +21,7 @@ class Controller
 
 
 
-		void Message(std::string & buffer) {Message(buffer.c_str());}
+		void Message(const std::string & buffer) {Message(buffer.c_str());}
 		virtual void Message(const char * string) = 0;
 
 		virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]) = 0;
diff --git a/manager/game.cpp b/manager/game.cpp
index 49c2c90..b4fcc62 100644
--- a/manager/game.cpp
+++ b/manager/game.cpp
@@ -74,7 +74,16 @@ Game::~Game()
 		fclose(input);
 }
 
-bool Game::Setup(const char * redName, const char * blueName)
+/**
+ * Attempts to setup the board and controllers
+ * @param redName the name of the red AI
+ * @param blueName the name of the blue AI
+ * @returns A colour, indicating if there were any errors
+	Piece::NONE indicates no errors
+	Piece::BOTH indicates errors with both AI
+	Piece::RED / Piece::BLUE indicates an error with only one of the two AI
+ */
+Piece::Colour Game::Setup(const char * redName, const char * blueName)
 {
 
 	if (!red->Valid())
@@ -85,8 +94,16 @@ bool Game::Setup(const char * redName, const char * blueName)
 	{
 		logMessage("Controller for Player BLUE is invalid!\n");
 	}
-	if (!red->Valid() || !blue->Valid())
-		return false;
+	if (!red->Valid())
+	{
+		if (!blue->Valid())
+			return Piece::BOTH;
+		return Piece::RED;
+	}
+	else if (!blue->Valid())
+	{
+		return Piece::BLUE;
+	}
 
 	for (int y = 4; y < 6; ++y)
 	{
@@ -104,35 +121,38 @@ bool Game::Setup(const char * redName, const char * blueName)
 	MovementResult redSetup = red->Setup(blueName);
 	MovementResult blueSetup = blue->Setup(redName);
 
+
+	Piece::Colour result = Piece::NONE;
 	if (redSetup != MovementResult::OK)
 	{	
 		if (blueSetup != MovementResult::OK)
 		{
 			logMessage("BOTH players give invalid setup!\n");
-			red->Message("ILLEGAL");
-			blue->Message("ILLEGAL");
+			result = Piece::BOTH;
 		}
 		else
 		{
 			logMessage("Player RED gave an invalid setup!\n");
-			red->Message("ILLEGAL");
-			blue->Message("DEFAULT");
+			result = Piece::RED;
 		}
-		return false;
+		
 	}
 	else if (blueSetup != MovementResult::OK)
 	{
 		logMessage("Player BLUE gave an invalid setup!\n");
-		red->Message("DEFAULT");
-		blue->Message("ILLEGAL");	
-		return false;
+		result = Piece::BLUE;
 	}
 
 	logMessage("%s RED SETUP\n", red->name.c_str());
 	for (int y=0; y < 4; ++y)
 	{
 		for (int x=0; x < theBoard.Width(); ++x)
-			logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
+		{
+			if (theBoard.GetPiece(x, y) != NULL)
+				logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
+			else
+				logMessage(".");
+		}
 		logMessage("\n");
 	}	
 
@@ -145,7 +165,7 @@ bool Game::Setup(const char * redName, const char * blueName)
 	}	
 
 	
-	return true;
+	return result;
 
 }
 
@@ -241,18 +261,25 @@ void Game::HandleBrokenPipe(int sig)
 
 void Game::PrintEndMessage(const MovementResult & result)
 {
-	if (turn == Piece::RED)
-	{
-		logMessage("Game ends on RED's turn - REASON: ");	
-	}
-	else if (turn == Piece::BLUE)
+	if (turnCount == 0)
 	{
-		logMessage("Game ends on BLUE's turn - REASON: ");
+		logMessage("Game ends in the SETUP phase - REASON: ");
 	}
 	else
 	{
-		logMessage("Game ends on ERROR's turn - REASON: ");
+		if (turn == Piece::RED)
+		{
+			logMessage("Game ends on RED's turn - REASON: ");	
+		}
+		else if (turn == Piece::BLUE)
+		{
+			logMessage("Game ends on BLUE's turn - REASON: ");
+		}
+		else
+		{
+			logMessage("Game ends on ERROR's turn - REASON: ");
 			
+		}
 	}
 	switch (result.type)
 	{
@@ -287,7 +314,7 @@ void Game::PrintEndMessage(const MovementResult & result)
 			logMessage("Selected unit cannot move that way\n");
 			break;
 		case MovementResult::POSITION_FULL:
-			logMessage("Attempted move into square occupied by allied piece\n");
+			logMessage("Attempted move into square occupied by neutral or allied piece\n");
 			break;
 		case MovementResult::VICTORY:
 			logMessage("Captured the flag\n");
@@ -304,9 +331,32 @@ void Game::PrintEndMessage(const MovementResult & result)
 		case MovementResult::ERROR:
 			logMessage("Internal controller error - Unspecified ERROR\n");
 			break;
-		case MovementResult::DRAW:
+		case MovementResult::DRAW_DEFAULT:
 			logMessage("Game declared a draw after %d turns\n", turnCount);
 			break;
+		case MovementResult::DRAW:
+			logMessage("Game declared a draw because neither player has mobile pieces\n");
+			break;
+		case MovementResult::SURRENDER:
+			logMessage("This player has surrendered!\n");
+			break;
+		case MovementResult::BAD_SETUP:
+			switch (turn)
+			{
+				case Piece::RED:
+					logMessage("An illegal setup was made by RED\n");
+					break;
+				case Piece::BLUE:
+					logMessage("An illegal setup was made by BLUE\n");
+					break;
+				case Piece::BOTH:
+					logMessage("An illegal setup was made by BOTH players\n");
+					break;
+				case Piece::NONE:
+					logMessage("Unknown internal error.\n");
+					break;
+			}
+			break;
 
 	}
 
@@ -350,7 +400,7 @@ void Game::PrintEndMessage(const MovementResult & result)
 
 MovementResult Game::Play()
 {
-	
+
 	MovementResult result = MovementResult::OK;
 	turnCount = 1;
 	string buffer;
@@ -359,7 +409,7 @@ MovementResult Game::Play()
 
 	red->Message("START");
 	//logMessage("START\n");
-	while (Board::LegalResult(result) && (turnCount < maxTurns || maxTurns < 0))
+	while (!Board::HaltResult(result) && (turnCount < maxTurns || maxTurns < 0))
 	{
 
 		
@@ -369,7 +419,7 @@ MovementResult Game::Play()
 		red->Message(buffer);
 		blue->Message(buffer);
 		logMessage( "%s\n", buffer.c_str());
-		if (!Board::LegalResult(result))
+		if (Board::HaltResult(result))
 			break;
 		if (graphicsEnabled)
 			theBoard.Draw(reveal);
@@ -389,7 +439,7 @@ MovementResult Game::Play()
 		red->Message(buffer);
 		logMessage( "%s\n", buffer.c_str());
 
-		if (!Board::LegalResult(result))
+		if (Board::HaltResult(result))
 			break;
 
 		
@@ -406,13 +456,15 @@ MovementResult Game::Play()
 
 		Wait(stallTime);
 		
+		if (theBoard.MobilePieces(Piece::BOTH) == 0)
+			result = MovementResult::DRAW;
+
 		++turnCount;
 	}
 
 	if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
 	{
-		result = MovementResult::DRAW;
-		turn = Piece::BOTH;
+		result = MovementResult::DRAW_DEFAULT;
 	}
 
 	
diff --git a/manager/game.h b/manager/game.h
index f6d7b6b..48926ea 100644
--- a/manager/game.h
+++ b/manager/game.h
@@ -21,7 +21,7 @@ class Game
 
 		void Wait(double wait); 
 
-		bool Setup(const char * redName, const char * blueName);
+		Piece::Colour Setup(const char * redName, const char * blueName);
 		MovementResult Play();
 		void PrintEndMessage(const MovementResult & result);
 		
@@ -30,6 +30,7 @@ class Game
 		
 		
 		const Piece::Colour Turn() const {return turn;}
+		void ForceTurn(const Piece::Colour & newTurn) {turn = newTurn;}
 		int TurnCount() const {return turnCount;}
 
 		static Game * theGame;
diff --git a/manager/main.cpp b/manager/main.cpp
index 01a7fab..44f8fd3 100644
--- a/manager/main.cpp
+++ b/manager/main.cpp
@@ -10,9 +10,9 @@
 
 using namespace std;
 
-void CreateGame(int argc, char ** argv);
+Piece::Colour SetupGame(int argc, char ** argv);
 void DestroyGame();
-void PrintResults(const MovementResult & result);
+void PrintResults(const MovementResult & result, string & buffer);
 
 int main(int argc, char ** argv)
 {
@@ -26,22 +26,40 @@ int main(int argc, char ** argv)
 		exit(EXIT_SUCCESS);
 		
 	}
-	CreateGame(argc, argv);
-	if (Game::theGame == NULL)
+	
+
+	Piece::Colour setupError = SetupGame(argc, argv);
+	MovementResult result = MovementResult::OK;
+	if (setupError == Piece::NONE)
 	{
-		fprintf(stderr, "ERROR: Couldn't create a game!\n");
-		exit(EXIT_FAILURE);
+		result = Game::theGame->Play();
 	}
-
-	MovementResult result = Game::theGame->Play();
+	else
+	{
+		result = MovementResult::BAD_SETUP;
+		Game::theGame->ForceTurn(setupError);
+	}
+	
 	Game::theGame->PrintEndMessage(result);
-	PrintResults(result);
+
+	string buffer = "";
+	PrintResults(result, buffer);
+
+	//Message the AI's the quit message
+	Game::theGame->red->Message("QUIT " + buffer);
+	Game::theGame->blue->Message("QUIT " + buffer);
+
+	//Log the message
+	if (Game::theGame->GetLogFile() != stdout)
+		Game::theGame->logMessage("%s\n", buffer.c_str());
+
+	fprintf(stdout, "%s\n", buffer.c_str());
 
 	exit(EXIT_SUCCESS);
 	return 0;
 }
 
-void CreateGame(int argc, char ** argv)
+Piece::Colour SetupGame(int argc, char ** argv)
 {
 	char * red = NULL; char * blue = NULL; double timeout = 0.00001; bool graphics = false; bool allowIllegal = false; FILE * log = NULL;
 	Piece::Colour reveal = Piece::BOTH; char * inputFile = NULL; int maxTurns = 5000; bool printBoard = false;
@@ -54,7 +72,7 @@ void CreateGame(int argc, char ** argv)
 				case 't':
 					if (argc - ii <= 1)
 					{
-						fprintf(stderr, "Expected timeout value after -t switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected timeout value after -t switch!\n");
 						exit(EXIT_FAILURE);
 					}
 					timeout = atof(argv[ii+1]);
@@ -73,12 +91,12 @@ void CreateGame(int argc, char ** argv)
 				case 'o':
 					if (argc - ii <= 1)
 					{
-						fprintf(stderr, "Expected filename or \"stdout\" after -o switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected filename or \"stdout\" after -o switch!\n");
 						exit(EXIT_FAILURE);
 					}
 					if (log != NULL)
 					{
-						fprintf(stderr, "Expected at most ONE -o switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected at most ONE -o switch!\n");
 						exit(EXIT_FAILURE);
 					}
 					if (strcmp(argv[ii+1], "stdout") == 0)
@@ -105,10 +123,10 @@ void CreateGame(int argc, char ** argv)
 				case 'm':
 					if (argc - ii <= 1)
 					{
-						fprintf(stderr, "Expected max_turns value after -m switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected max_turns value after -m switch!\n");
 						exit(EXIT_FAILURE);
 					}
-					if (strcmp(argv[ii+1], "inf"))
+					if (strcmp(argv[ii+1], "inf") == 0)
 						maxTurns = -1;
 					else
 						maxTurns = atoi(argv[ii+1]);
@@ -117,12 +135,12 @@ void CreateGame(int argc, char ** argv)
 				case 'f':
 					if (argc - ii <= 1)
 					{
-						fprintf(stderr, "Expected filename after -f switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected filename after -f switch!\n");
 						exit(EXIT_FAILURE);
 					}
 					if (log != NULL)
 					{
-						fprintf(stderr, "Expected at most ONE -f switch!\n");
+						fprintf(stderr, "ARGUMENT_ERROR - Expected at most ONE -f switch!\n");
 						exit(EXIT_FAILURE);
 					}
 					red = (char*)("file");
@@ -144,7 +162,7 @@ void CreateGame(int argc, char ** argv)
 					}
 					else
 					{
-						fprintf(stderr, "Unrecognised switch \"%s\"...\n", argv[ii]);
+						fprintf(stderr, "ARGUMENT_ERROR - Unrecognised switch \"%s\"...\n", argv[ii]);
 						exit(EXIT_FAILURE);
 					}
 			}
@@ -158,67 +176,93 @@ void CreateGame(int argc, char ** argv)
 				blue = argv[ii];
 			else
 			{
-				fprintf(stderr, "Unexpected argument \"%s\"...\n", argv[ii]);
+				fprintf(stderr, "ARGUMENT_ERROR - Unexpected argument \"%s\"...\n", argv[ii]);
 				exit(EXIT_FAILURE);
 			}
 		}
 	}
 
+
+
 	if (inputFile == NULL)
 	{
+		if (red == NULL || blue == NULL) //Not enough arguments
+		{
+			fprintf(stderr, "ARGUMENT_ERROR - Did not recieve enough players (did you mean to use the -f switch?)\n");	
+			exit(EXIT_FAILURE);	
+		}
 		Game::theGame = new Game(red,blue, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard);
 	}
 	else
 	{
 		Game::theGame = new Game(inputFile, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard);
 	}
-	if (!Game::theGame->Setup(red, blue))
+
+	if (Game::theGame == NULL)
 	{
-		fprintf(stdout, "NONE %d\n",Game::theGame->TurnCount());
-		exit(EXIT_SUCCESS);
+		fprintf(stderr,"INTERNAL_ERROR - Error creating Game!\n");
+		exit(EXIT_FAILURE);
 	}
-	
 	atexit(DestroyGame);
+	
+	return Game::theGame->Setup(red, blue);
+	
 
 }
 
-void PrintResults(const MovementResult & result)
+void PrintResults(const MovementResult & result, string & buffer)
 {
-	Piece::Colour winner = Game::theGame->Turn();
-	if (Board::LegalResult(result))
-	{
-		if (winner == Piece::BOTH)
-			winner = Piece::NONE;
-		else
-		{
-			if (winner == Piece::RED)
-				winner = Piece::BLUE;
-			else
-				winner = Piece::RED;
-		}
-	}
-	
-
-	switch (winner)
+	stringstream s("");
+	switch (Game::theGame->Turn())
 	{
 		case Piece::RED:
-			fprintf(stdout, "%s RED %d\n", Game::theGame->red->name.c_str(),Game::theGame->TurnCount());	
-			Game::theGame->logMessage("%s RED %d\n", Game::theGame->red->name.c_str(),Game::theGame->TurnCount());
+			s << Game::theGame->red->name << " RED ";
 			break;
 		case Piece::BLUE:
-			fprintf(stdout, "%s BLUE %d\n", Game::theGame->blue->name.c_str(),Game::theGame->TurnCount());	
-			Game::theGame->logMessage("%s BLUE %d\n", Game::theGame->blue->name.c_str(),Game::theGame->TurnCount());
+			s << Game::theGame->blue->name << " BLUE ";
 			break;
 		case Piece::BOTH:
-			fprintf(stdout, "DRAW %d\n",Game::theGame->TurnCount());
-			Game::theGame->logMessage("DRAW %d\n",Game::theGame->TurnCount());	
+			s << "neither BOTH ";
 			break;
 		case Piece::NONE:
-			fprintf(stdout, "NONE %d\n",Game::theGame->TurnCount());	
-			Game::theGame->logMessage("NONE %d\n",Game::theGame->TurnCount());
+			s << "neither NONE ";
 			break;
+	}
 
+	if (!Board::LegalResult(result) && result != MovementResult::BAD_SETUP)
+		s << "ILLEGAL ";
+	else if (!Board::HaltResult(result))
+		s << "INTERNAL_ERROR ";
+	else
+	{
+		switch (result.type)
+		{
+			case MovementResult::VICTORY:
+				s <<  "VICTORY ";
+				break;
+			case MovementResult::SURRENDER:
+				s << "SURRENDER ";
+				break;
+			case MovementResult::DRAW:
+				s << "DRAW ";
+				break;
+			case MovementResult::DRAW_DEFAULT:
+				s << "DRAW_DEFAULT ";
+				break;
+			case MovementResult::BAD_SETUP:
+				s << "BOTH_ILLEGAL ";
+				break;	
+			default:
+				s << "INTERNAL_ERROR ";
+				break;	
+		}
 	}
+	
+	s << Game::theGame->TurnCount() << " " << Game::theGame->theBoard.TotalPieceValue(Piece::RED) << " " << Game::theGame->theBoard.TotalPieceValue(Piece::BLUE);
+
+	buffer = s.str();
+	
+
 }
 
 void DestroyGame()
diff --git a/manager/manual.txt b/manager/manual.txt
index 55a8f05..e7a15d1 100644
--- a/manager/manual.txt
+++ b/manager/manual.txt
@@ -64,7 +64,7 @@ OPTIONS
 		
 
 GAME RULES
-		Each player sets up 40 pieces on the Board. The pieces consist of the following:
+		Each player controls up to 40 pieces on the Board. The pieces consist of the following:
 
 		Piece	Name		Rank	Number	Abilities
 		1	Marshal		1	1	Dies if attacked by Spy
@@ -77,16 +77,24 @@ GAME RULES
 		8	Miner		8	5	Destroys Bombs without being killed
 		9	Scout		9	8	May move more through multiple empty squares
 		s	Spy		10	1	If the Spy attacks the Marshal, the Marshal dies
-		B	Bomb		NA	6	Immobile. If an enemy piece (except a Miner) encounters a Bomb, both pieces are destroyed
-		F	Flag		NA	1	Immobile. If any enemy piece encounters the Flag, the controlling player wins.
+		B	Bomb		NA	6	Immobile. If any piece (except a Miner) encounters an enemy Bomb, both pieces are destroyed
+		F	Flag		NA	1	Immobile. If any piece encounters the enemy Flag, the controlling player wins.
+
+		Additional pieces, not controlled by the player:
+		Piece	Name			Number	Notes
+		+	Obstacle		8	Immobile. Do not belong to either player. Can't be passed through.
+		#	Enemy Piece		0 - 40	Indicates that the position on the board is occupied by an enemy piece.
+		.	Empty			NA	Indicates that the position on the board is empty.
+		
+		Players take turns to move their pieces. RED begins the game.
 
-		Pieces may move one square horizontally or vertically unless otherwise stated.
-		Pieces may not move through squares occupied by allied pieces.
-		Pieces may move into squares occupied by enemy pieces, in which case the piece with the lower rank (higher number) is destroyed.
+		Pieces may only move one square horizontally or vertically unless otherwise stated.
+		Pieces may not move through squares occupied by allied pieces, or Obstacle (+) pieces.
+		Pieces may move into squares occupied by Enemy Pieces (#), in which case the piece with the lower rank (higher number) is destroyed.
 
 		Each player's pieces are hidden from the other player. When two pieces encounter each other, the ranks will be revealed.
 
-		The objective is to destroy all enemy pieces or capture the Flag.
+		The objective is to destroy all Enemy Pieces (#) or capture the Enemy Flag (also #).
 		
 
 PROTOCOL
@@ -100,32 +108,46 @@ PROTOCOL
 		RESPONSE: 4 lines, each of length BOARD_WIDTH, of characters. Each character represents a piece. The characters are shown above.
 
 	2. TURN
-		QUERY: START | CONFIRMATION
+		QUERY: 	START | CONFIRMATION
+			BOARD_STATE
+
 			On the first turn, "START" is printed to the Red player.
 			On subsequent turns, the CONFIRMATION of the opponent's last turn is printed (see below).
 
-		RESPONSE: X Y DIRECTION [MULTIPLIER=1]
+			BOARD_STATE consists of a BOARD_HEIGHT lines of length BOARD_WIDTH characters, each of which represents a single piece
+			as described in the GAME_RULES section. Each line ends with the newline character.
+			
+
+		RESPONSE: X Y DIRECTION [MULTIPLIER=1] | NO_MOVE
 			X and Y are the coords (starting from 0) of the piece to move
 			DIRECTION is either UP, DOWN, LEFT or RIGHT
 			MULTIPLIER is optional and only valid for units of type Scout. Scouts may move through any number of unblocked squares
 			in one direction.
 
-		CONFIRMATION: X Y DIRECTION [MULTIPLIER=1] OUTCOME
+			The AI program should print "NO_MOVE" if it is unable to determine a move.
+			This will typically occur when the only pieces belonging to the AI program are Bombs and the Flag.
+
+		CONFIRMATION: X Y DIRECTION [MULTIPLIER=1] OUTCOME | NO_MOVE | QUIT RESULT
 			OUTCOME may be either OK, ILLEGAL, KILLS or DIES
 				OK - Move was successful
 				ILLEGAL - Move was not allowed. If stratego was not started with the -i switch, the game will end.
 				KILLS ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and killed the defender.
 				DIES ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and was killed by the defender.
 
+			A confirmation of "NO_MOVE" occurs when the AI program made no move for a legitimate reason.
+			"NO_MOVE ILLEGAL" is printed if the AI program made no move for an illegitimate reason.
+
+			If both AI programs successively make a "NO_MOVE" response, then the game will end.
+			The player with the highest piece value will win, or a draw will be declared if the values are equal.
+
+
 	3. END GAME
-		QUERY: VICTORY | DEFEAT | ILLEGAL | DEFAULT
-			VICTORY - This player won the game
-			DEFEAT - The other player won the game
-			ILLEGAL - Game ended because this player made a bad response or timed out
-				(NOTE: Even if the -i option is provided, the game may end with an ILLEGAL signal if a bad response is made)
-			DEFAULT - Game ended because the other player made a bad response.
-
-			No response is necessary; the program should exit or it will be sent a SIGKILL signal.
+		If the CONFIRMATION line is of the form:
+			QUIT RESULT
+		Then the game is about to end.
+	
+		If present, RESULT will be a direct copy of the message to stdout described in the EXIT/OUTPUT section below.
+		
 	
 	4. TIMEOUTS
 		If a program fails to respond to a query within 2 (two) seconds, the game will end and that AI will be sent the ILLEGAL result.
@@ -136,15 +158,30 @@ PROTOCOL
 EXIT/OUTPUT
 	If the game ends due to a player either winning, or making an illegal move, stratego will print one of the following result messages to stdout.
 
-	1.
-		WINNING_NAME WINNING_COLOUR TURNS
-	2.
-		DRAW TURNS
-		When the result was a draw
+	NAME COLOUR OUTCOME TURN_NUMBER OUTCOME RED_PIECE_VALUE BLUE_PIECE_VALUE
+
+	Where:
+		NAME is the name of the player on whose turn the game ended,
+		COLOUR is the colour of that player,
+		OUTCOME is one of the following:
+			VICTORY - The indicated player won
+			DEFEAT - The indicated player lost
+			SURRENDER - The indicated player surrendered
+			DRAW - The game ended in a draw because neither player moved
+			DRAW_DEFAULT - The game ended in a draw because the maximum number of moves was exceeded
+			ILLEGAL - The indicated player loses due to an Illegal move/response
+			DEFAULT - The indicated player wins by default due to the other player making an Illegal move/response
+			BOTH_ILLEGAL - Both players made an Illegal move/response. Usually occurs due to simultaneous setup errors, or bad executable paths.
+			INTERNAL_ERROR - The game ended, even though it shouldn't have.
+			
+		TURN_NUMBER is the number of turns that elapsed before the game ended
+
+		RED_PIECE_VALUE and BLUE_PIECE_VALUE are the summed piece values of the pieces of RED and BLUE respectively.
+		Bombs and Flags are worth zero, and the ranked pieces (Spys -> Marshal) are worth (11 - rank).
+		So the Spy is worth 1 point, ... the Marshal is worth 10.
 
-	3.
-		NONE TURNS
-		When for some reason both the AI programs failed to respond or crashed.
+		(The initial piece values can be determined by running with -m 0)
+		
 
 	stratego will then return exit code 0.
 
diff --git a/manager/movementresult.h b/manager/movementresult.h
index 695a1e2..5a2aed6 100644
--- a/manager/movementresult.h
+++ b/manager/movementresult.h
@@ -13,7 +13,7 @@ class Piece;
 class MovementResult
 {
 	public:
-		typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR, DRAW} Type;
+		typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, SURRENDER, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR, DRAW_DEFAULT, DRAW, BAD_SETUP} Type;
 
 		MovementResult(const Type & result = OK, const Piece::Type & newAttackerRank = Piece::NOTHING, const Piece::Type & newDefenderRank = Piece::NOTHING)
 			: type(result), attackerRank(newAttackerRank), defenderRank(newDefenderRank) {}
diff --git a/manager/program.cpp b/manager/program.cpp
index acf501e..3fca369 100644
--- a/manager/program.cpp
+++ b/manager/program.cpp
@@ -22,8 +22,18 @@ using namespace std;
  */
 Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0)
 {
+	//See if file exists...
+	FILE * file = fopen(executablePath, "r");
+	if (file != NULL)
+	{
+		fclose(file);
+	}
+	else
+	{
+		pid = -1;
+		return;
+	}
 	
-
 	int readPipe[2]; int writePipe[2];
 	assert(pipe(readPipe) == 0);
 	assert(pipe(writePipe) == 0);
@@ -47,8 +57,8 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
 
 
 		execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable
-		fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
-		exit(EXIT_FAILURE); //We will probably have to terminate the whole program if this happens
+		//fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
+		//exit(EXIT_FAILURE); //We will probably have to terminate the whole program if this happens
 	}
 	else
 	{
@@ -69,17 +79,28 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
  */
 Program::~Program()
 {
-	if (kill(pid, 0) == 0) //Check if the process created is still running...
+	if (Running()) //Check if the process created is still running...
 	{
 		fputc(EOF, output); //If it was, tell it to stop with EOF
-		usleep(500000); //Give it 1/2 a second to respond...
-		if (kill(pid, 0) == 0) //Check if its still running
+
+		TimerThread timer(2); //Wait for 2 seconds
+		timer.Start();		
+		while (!timer.Finished())
 		{
-			kill(pid, 9); //Slay the infidel mercilessly!
+			if (!Running())
+			{
+				timer.Stop();
+				break;
+			}
 		}
+		timer.Stop();
+		kill(pid, SIGKILL);
+	}
+	if (pid > 0)
+	{
+		fclose(input);
+		fclose(output);
 	}
-	fclose(input);
-	fclose(output);
 	
 }
 
@@ -95,7 +116,7 @@ Program::~Program()
  */
 bool Program::SendMessage(const char * print, ...)
 {
-	if (kill(pid, 0) != 0) //Is the process running...
+	if (!Running()) //Is the process running...
 		return false; 
 
 	va_list ap;
@@ -123,7 +144,7 @@ bool Program::SendMessage(const char * print, ...)
  */
 bool Program::GetMessage(string & buffer, double timeout)
 {
-	if (kill(pid, 0) != 0)
+	if (!Running())
 		return false;
 
 	assert(&buffer != NULL);
@@ -164,7 +185,7 @@ bool Program::GetMessage(string & buffer, double timeout)
  */
 bool Program::Running() const
 {
-	return (kill(pid,0) == 0);
+	return (pid > 0 && kill(pid,0) == 0);
 }
 
 
diff --git a/manager/program.h b/manager/program.h
index bddde0f..8fef696 100644
--- a/manager/program.h
+++ b/manager/program.h
@@ -32,6 +32,7 @@ class Program
 
 	private:
 		pid_t pid; //Process ID of the program wrapped
+		
 };
 
 #endif //PROGRAM_H
diff --git a/manager/stratego.cpp b/manager/stratego.cpp
index d84819f..ed38e35 100644
--- a/manager/stratego.cpp
+++ b/manager/stratego.cpp
@@ -65,7 +65,7 @@ Piece::Type Piece::GetType(char fromToken)
  * @param newWidth - the width of the board
  * @param newHeight - the height of the board
  */
-Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL)
+Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL), pieces()
 {
 	board = new Piece**[width];
 	for (int x=0; x < width; ++x)
@@ -269,6 +269,8 @@ bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Col
 
 	Piece * piece = new Piece(newType, newColour);
 	board[x][y] = piece;
+
+	pieces.push_back(piece);
 	return true;
 }
 
@@ -374,7 +376,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 		{
 			if (target->type == Piece::MINER)
 			{
-
+				RemovePiece(defender);
 				delete defender;
 				board[x][y] = NULL;
 				board[x2][y2] = target;
@@ -382,6 +384,8 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 			}
 			else
 			{
+				RemovePiece(defender);
+				RemovePiece(target);
 				delete defender;
 				delete target;
 				board[x][y] = NULL;
@@ -391,6 +395,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 		}
 		else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
 		{
+			RemovePiece(defender);
 			delete defender;
 			board[x][y] = NULL;
 			board[x2][y2] = target;
@@ -398,6 +403,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 		}
 		else if (target->operator > (*defender))
 		{
+			RemovePiece(defender);
 			delete defender;
 			board[x][y] = NULL;
 			board[x2][y2] = target;
@@ -405,6 +411,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 		}
 		else if (target->operator==(*defender) && rand() % 2 == 0)
 		{
+			RemovePiece(defender);
 			delete defender;
 			board[x][y] = NULL;
 			board[x2][y2] = target;	
@@ -412,6 +419,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 		}
 		else
 		{
+			RemovePiece(target);
 			delete target;
 			board[x][y] = NULL;
 			return MovementResult(MovementResult::DIES, attackerType, defenderType);
@@ -424,5 +432,77 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
 	return MovementResult(MovementResult::OK);
 }	
 
+/**
+ * Removes a piece from the board
+ * @param piece The piece to remove
+ * @returns true iff the piece actually existed
+ */
+bool Board::RemovePiece(Piece * piece)
+{
+	bool result = false;
+	for (int x = 0; x < width; ++x)
+	{
+		for (int y = 0; y < height; ++y)	
+		{
+			if (board[x][y] == piece)
+			{
+				result = true;
+				board[x][y] = NULL;
+			}
+		}
+	}
+
+	vector<Piece*>::iterator i = pieces.begin();
+	while (i != pieces.end())
+	{
+		if ((*i) == piece)
+		{
+			i = pieces.erase(i);
+			result = true;
+			continue;
+		}
+		++i;
+	}
+	return result;
+}
+
+/**
+ * Returns the total value of pieces belonging to colour
+ * @param colour the colour
+ * @returns the total value of pieces belonging to colour.
+ *	(Redundant repetition <3)
+ */
+int Board::TotalPieceValue(const Piece::Colour & colour) const
+{
+	int result = 0;
+	for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
+	{
+		if ((*i)->colour == colour || colour == Piece::BOTH)
+		{
+			result += (*i)->PieceValue();
+		}
+	}
+	return result;
+}
+
+/**
+ * Returns the total number of mobile pieces belonging to colour
+ * @param colour the colour
+ * @returns the total value of mobile pieces belonging to colour.
+ *	(Redundant repetition <3)
+ */
+int Board::MobilePieces(const Piece::Colour & colour) const
+{
+	int result = 0;
+	for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
+	{
+		if ((*i)->colour == colour || colour == Piece::BOTH)
+		{
+			if ((*i)->type <= Piece::MARSHAL && (*i)->type >= Piece::SPY)
+				result++;
+		}
+	}
+	return result;
+}
 
 
diff --git a/manager/stratego.h b/manager/stratego.h
index 39e8873..929f870 100644
--- a/manager/stratego.h
+++ b/manager/stratego.h
@@ -10,6 +10,7 @@
 	#include "graphics.h"
 	#include "array.h"
 
+#include <vector>
 
 /**
  * Contains classes for a game of Stratego
@@ -25,9 +26,10 @@ class Piece
 		typedef enum {ERROR=14,BOMB=13,MARSHAL=12, GENERAL=11, COLONEL=10, MAJOR=9, CAPTAIN=8, LIEUTENANT=7, SERGEANT=6, MINER=5, SCOUT=4, SPY=3, FLAG=2,BOULDER=1, NOTHING=0} Type; //Type basically defines how strong the piece is
 		
 
+	
 		typedef enum {RED=0, BLUE=1, NONE=2, BOTH=3} Colour; //Used for the allegiance of the pieces - terrain counts as NONE.
 
-		Piece(const Type & newType, const Colour & newColour) : type(newType), colour(newColour) {}
+		Piece(const Type & newType, const Colour & newColour) : type(newType), colour(newColour), beenRevealed(false) {}
 		virtual ~Piece() {}
 
 
@@ -46,11 +48,14 @@ class Piece
 
 		static Type GetType(char fromToken);
 
+		int PieceValue() const {if (type == BOMB || type == FLAG) {return 0;} return (int)(type) - (int)(SPY) + 1;}
 
 		//Attributes of the piece
 		const Type type; 
 		const Colour colour;
 
+		bool beenRevealed;
+
 		public:
 
 			class TextureManager : public Graphics::TextureManager<LUint>, private Array<Texture*>
@@ -118,8 +123,13 @@ class Board
 		
 		static bool LegalResult(const MovementResult & result)
 		{
-			return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE || result == MovementResult::VICTORY || result == MovementResult::DRAW);
-		}	
+			return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE || result == MovementResult::VICTORY || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER);
+		}
+
+		static bool HaltResult(const MovementResult & result)
+		{
+			return (result == MovementResult::VICTORY || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER || !LegalResult(result));
+		}		
 
 		MovementResult MovePiece(int x, int y, const Direction & direction, int multiplier=1,const Piece::Colour & colour=Piece::NONE); //Move piece from position in direction
 	
@@ -128,10 +138,15 @@ class Board
 
 		int Width() const {return width;}
 		int Height() const {return height;}
+
+		int MobilePieces(const Piece::Colour & colour) const;
+		int TotalPieceValue(const Piece::Colour & colour) const;
+		bool RemovePiece(Piece * piece);
 	private:
 		int width;
 		int height;
 		Piece ** * board;
+		std::vector<Piece*> pieces;
 };
 
 #endif //STRATEGO_H
diff --git a/samples/asmodeus/asmodeus.py b/samples/asmodeus/asmodeus.py
old mode 100755
new mode 100644
index 2f83db6..29c50a2
--- a/samples/asmodeus/asmodeus.py
+++ b/samples/asmodeus/asmodeus.py
@@ -14,201 +14,68 @@
  git git.ucc.asn.au/progcomp2012.git
 '''
 
-import sys
-import random
-
-ranks = ('B','1','2','3','4','5','6','7','8','9','s','F', '?', '+')
-
-def move(x, y, direction):
-	if direction == "UP":
-		return (x,y-1)
-	elif direction == "DOWN":
-		return (x,y+1)
-	elif direction == "LEFT":
-		return (x-1, y)
-	elif direction == "RIGHT":
-		return (x+1, y)
-	print "Error in move!"
-	return (x,y)
-
-def oppositeColour(colour):
-	if colour == "RED":
-		return "BLUE"
-	elif colour == "BLUE":
-		return "RED"
-	else:
-		return "NONE"
-
-class Piece:
-	def __init__(self, colour, rank, x, y):
-		self.colour = colour
-		self.rank = rank
-		self.x = x
-		self.y = y
-	
-
-
-
-class Asmodeus:
-	def __init__(self):
-		#sys.stderr.write("Asmodeus __init__ here...\n");
-		self.turn = 0
-		self.board = []
-		self.units = []
-		if self.Setup():
-			while self.MoveCycle(): #derp derp derp
-				pass
-		
+from basic_python import *
+from path import *
+
 
-	def Setup(self):
-		#sys.stderr.write("Asmodeus Setup here...\n");
-		setup = sys.stdin.readline().split(' ')
-		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 "FB8sB479B8\nBB31555583\n6724898974\n967B669999"
-		elif self.colour == "BLUE":
-			print "967B669999\n6724898974\nBB31555583\nFB8sB479B8"
-		return True
-
-	def MoveCycle(self):
-		#sys.stderr.write("Asmodeus MakeMove here...\n");
-		if self.InterpretResult() == False or self.ReadBoard() == False or self.MakeMove() == False:
-			return False
-		self.turn += 1
-		return self.InterpretResult()
+
+class Asmodeus(BasicAI):
+	" A slightly more advanced python based AI who calculates the optimum score for each move "
+	def __init__(self):
+		#sys.stderr.write("Asmodeus initialised...\n")
+		BasicAI.__init__(self)
+		self.riskScores = {'1' : 0.01 , '2' : 0.05 , '3' : 0.15 , '4' : 0.2, '5' : 0.2, '6' : 0.25, '7' : 0.25, '8' : 0.01 , '9' : 0.4, 's' : 0.01}
+		self.bombScores = {'1' : 0.0 , '2' : 0.0 , '3' : 0.05 , '4' : 0.1, '5' : 0.3, '6' : 0.4, '7' : 0.5, '8' : 1 , '9' : 0.6, 's' : 0.1}
+		self.flagScores = {'1' : 1.0 , '2' : 1.0 , '3' : 1.0 , '4' : 1.0, '5' : 1.0, '6' : 1.0, '7' : 1, '8' : 1.0 , '9' : 1.0, 's' : 1.0}
+		self.suicideScores = {'1' : 0.0 , '2' : 0.0 , '3' : 0.0, '4' : 0.0, '5' : 0.0, '6' : 0.05, '7' : 0.1, '8' : 0.0 , '9' : 0.0, 's' : 0.0}
+		self.killScores = {'1' : 1.0 , '2' : 0.9 , '3' : 0.8 , '4' : 0.5, '5' : 0.5, '6' : 0.5, '7' : 0.4, '8' : 0.9 , '9' : 0.6, 's' : 0.9}	
 
 	def MakeMove(self):
-		#TODO: Over-ride this function in base classes with more complex move behaviour
-
-		#sys.stderr.write("Asmodeus MakeMove here...\n")
-		#self.debugPrintBoard()
-		while True:
-			if len(self.units) <= 0:
-				return False
-			piece = random.choice(self.units)
-			if piece == None:
-				continue
-			if piece.rank == '?' or piece.rank == 'B' or piece.rank == 'F':
-				continue
+		#sys.stderr.write("Asmodeus MakingMove...\n")
+		"Over-rides the default BasicAI.MakeMove function"
 
-			direction = random.choice(("UP", "DOWN", "LEFT", "RIGHT"))
-			p = move(piece.x, piece.y, direction)
-			if p[0] >= 0 and p[0] < self.width and p[1] >= 0 and p[1] < self.height:
-				if self.board[p[0]][p[1]] == None or self.board[p[0]][p[1]].colour == oppositeColour(self.colour):
-					print str(piece.x) + " " + str(piece.y) + " " + direction
-					break
-		return True
-							
-			
-	def ReadBoard(self):
-		#sys.stderr.write("Asmodeus ReadBoard here...\n");
-		for y in range(0,self.height):
-			row = sys.stdin.readline()
-			for x in range(0,len(row)-1):
-				if self.turn == 0:
-					if row[x] == '.':
-						pass
-					elif row[x] == '#':
-						self.board[x][y] = Piece(oppositeColour(self.colour), '?',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
-		
+		moveList = []
+
+		for unit in self.units:
+			if unit.mobile() == False:
+				continue
 
-	def InterpretResult(self):
-		#sys.stderr.write("Asmodeus InterpretResult here...\n")
-		result = sys.stdin.readline().split(' ')
-		#sys.stderr.write("	Read status line \"" + str(result) + "\"\n")
-		if self.turn == 0:
-			return True
+			for enemy in self.enemyUnits:
+				if enemy == unit:
+					continue
+				path = PathFinder().pathFind((unit.x, unit.y), (enemy.x, enemy.y), self.board)
 
-		x = int(result[0].strip())
-		y = int(result[1].strip())
+				#sys.stderr.write("Computed path: " + str(path) + "\n")
+				if path == False or len(path) <= 0:
+					continue
+				score = self.CalculateScore(unit, enemy)
 
+				score = float(score / float(len(path) + 1))
+				moveList.append([unit, path, enemy, score])
 
-		#sys.stderr.write("	Board position " + str(x) + " " + str(y) + " is OK!\n")		
 
-		direction = result[2].strip()
-		outcome = result[3].strip()
 		
-		p = move(x,y,direction)
-
-		if outcome == "OK":
-			self.board[p[0]][p[1]] = self.board[x][y]
-			self.board[x][y].x = p[0]
-			self.board[x][y].y = p[1]
-
-			self.board[x][y] = None
-		elif outcome == "KILLS":
-			if self.board[p[0]][p[1]] == None:
-				return False
-
-			if self.board[p[0]][p[1]].colour == self.colour:
-				self.units.remove(self.board[p[0]][p[1]])
-			self.board[x][y].x = p[0]
-			self.board[x][y].y = p[1]
-
-
-			self.board[p[0]][p[1]] = self.board[x][y]
-			self.board[x][y].rank = result[4]
-
-			self.board[x][y] = None
-			
-		elif outcome == "DIES":
-			if self.board[p[0]][p[1]] == None:
-				return False
-
-			if self.board[x][y].colour == self.colour:
-				self.units.remove(self.board[x][y])
-
-			self.board[p[0]][p[1]].rank = result[5]
-			self.board[x][y] = None
-		elif outcome == "BOTHDIE":
-			if self.board[p[0]][p[1]] == None:
-				return False
-
-
-			if self.board[x][y].colour == self.colour:
-				self.units.remove(self.board[x][y])
-			if self.board[p[0]][p[1]].colour == self.colour:
-				self.units.remove(self.board[p[0]][p[1]])
-			self.board[p[0]][p[1]] = None
-			self.board[x][y] = None
-		elif outcome == "FLAG":
-			#sys.stderr.write("	Game over!\n")
-			return False
-		elif outcome == "ILLEGAL":
-			#sys.stderr.write("	Illegal move!\n")
-			return False
+		if len(moveList) <= 0:
+			#sys.stderr.write("NO Moves!\n")
+			return BasicAI.MakeMove(self)
+
+		moveList.sort(key = lambda e : e[len(e)-1], reverse=True)
+
+		#sys.stderr.write("Chosen move is: " + str(moveList[0][0].x) + " " + str(moveList[0][0].y) + " " + moveList[0][1][0] + " (targeting enemy with rank " + moveList[0][2].rank + " at position " + str(moveList[0][2].x) + " " + str(moveList[0][2].y) + " (my rank " + moveList[0][0].rank+")\n")
+		print str(moveList[0][0].x) + " " + str(moveList[0][0].y) + " " + moveList[0][1][0]
+		return True	
+
+	def CalculateScore(self, attacker, defender):
+		if defender.rank == '?':
+			return self.riskScores[attacker.rank]
+		elif defender.rank == 'B':
+			return self.bombScores[attacker.rank]
+		elif defender.rank == 'F':
+			return self.flagScores[attacker.rank]
+		elif defender.valuedRank() < attacker.valuedRank() or defender.rank == '1' and attacker.rank == 's':
+			return self.killScores[defender.rank]
 		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 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")
-				
-			
-
-asmodeus = Asmodeus()
+			return self.suicideScores[attacker.rank]
+		
+
 
diff --git a/samples/asmodeus/asmodeus.pyc b/samples/asmodeus/asmodeus.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2555c0f6e33c16ef94c60fb495b7ecc98f699e1b
GIT binary patch
literal 3232
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
V-6LCg>{(pp+by`HARoMH`9A}w!9xH5

literal 0
HcmV?d00001

diff --git a/samples/asmodeus/basic_python.py b/samples/asmodeus/basic_python.py
new file mode 120000
index 0000000..3d6b342
--- /dev/null
+++ b/samples/asmodeus/basic_python.py
@@ -0,0 +1 @@
+../basic_python/basic_python.py
\ No newline at end of file
diff --git a/samples/asmodeus/basic_python.pyc b/samples/asmodeus/basic_python.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bca3a0a3baebd8bdaddb05519ab823bbbd0dce26
GIT binary patch
literal 9110
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
R+3)PnoXZpr6beHl{{|1aFtz{y

literal 0
HcmV?d00001

diff --git a/samples/asmodeus/info b/samples/asmodeus/info
index da91d83..2ce2124 100644
--- a/samples/asmodeus/info
+++ b/samples/asmodeus/info
@@ -1 +1 @@
-asmodeus.py
+run.py
diff --git a/samples/asmodeus/path.py b/samples/asmodeus/path.py
new file mode 100644
index 0000000..3f08979
--- /dev/null
+++ b/samples/asmodeus/path.py
@@ -0,0 +1,57 @@
+
+import sys
+import random
+
+
+class PathFinder:
+	def __init__(self):
+		self.visited = []
+
+		pass
+
+	def pathFind(self, start, end, board):
+		if start[0] == end[0] and start[1] == end[1]:
+			#sys.stderr.write("Got to destination!\n")
+			return []
+
+		if self.visited.count(start) > 0:
+			#sys.stderr.write("Back track!!\n")
+			return False
+		if start[0] < 0 or start[0] >= len(board) or start[1] < 0 or start[1] >= len(board[start[0]]):
+			#sys.stderr.write("Out of bounds!\n")
+			return False
+		if len(self.visited) > 0 and board[start[0]][start[1]] != None:
+			#sys.stderr.write("Full position!\n")
+			return False
+
+
+		
+		self.visited.append(start)
+		left = (start[0]-1, start[1])
+		right = (start[0]+1, start[1])
+		up = (start[0], start[1]-1)
+		down = (start[0], start[1]+1)
+		choices = [left, right, up, down]
+		choices.sort(key = lambda e : random.randint(0,5))
+		options = []
+		for point in choices:
+			option = [point, self.pathFind(point,end,board)]
+			if option[1] != False:
+				options.append(option)	
+
+		options.sort(key = lambda e : len(e[1]))
+		if len(options) == 0:
+			#sys.stderr.write("NO options!\n")
+			return False
+		else:
+			if options[0][0] == left:
+				options[0][1].insert(0,"LEFT")
+			elif options[0][0] == right:
+				options[0][1].insert(0,"RIGHT")
+			elif options[0][0] == up:
+				options[0][1].insert(0,"UP")
+			elif options[0][0] == down:
+				options[0][1].insert(0,"DOWN")
+		#sys.stderr.write("PathFind got path " + str(options[0]) + "\n")
+		return options[0][1]
+		
diff --git a/samples/asmodeus/path.pyc b/samples/asmodeus/path.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3afa749ec31f6cbd9142a8b8d5e47a6e4a028ad8
GIT binary patch
literal 2085
zcmb_d&2G~`5T147{ImrDRYg-OA;Bf$K%ktEstQ3VAW*0r5KswO#@;4Q6We4rK&AB5
zJ_66gofqICcmeokHc88&Cz^QHyYutS&+e>${=T%Z{_9sers>be`w_^rFeG>s9T4r!
z=Zf|eB_1VZN=kG>bWHSN4{Jr8CL5=J@N3%zOm`#O+ex!TkLK_S?8hLphCu@uV8k#E
zf+r;kI!zDan3b7$@dRWpVdxS~h(Zad(`0d5Mq9=7OKMW96UQjCi5~1X@g^C}L(E#e
ze5hL{8n(9ccs$gZHLYTlcjJ6mY}~uQ!J=ZIO)E0PJkeuFk;mQQ(AHobhG~}CFl29r
zJ&>w<F;A926_7;w12IpKo1(@<iqq(Ol&_IurstS=G1Di7oH`0wrFazE9gAtdEK=*S
z)PVu8PgFc}KtQ)8nv__-?^AJajz87AIcGS%DN4iXvugoop?E*_dkdD}I<F0WBiu$p
z)GwV0%7yGtL!Jle(dyJ<-=m}Q3<eO_&+x@eD&){1US<8tOn<7&X3VeB1W>SoLY2B@
zI;zp6MrnmlBF^IpA4bK+JgU>Tmn_@<_=JuYXo3f!0ss?F3Ra>nAQx$}D4C%QoY+-l
zU8fX27P+SC^NC`5$4uwOpSj_h)n^;!w$W`=U3OjaDid$;x_~l+Ynawpo>b`ABb9wW
zmGM#W&o`(#gZN*A%J~L0XRz_FLG^qCWWymLZ6r1ex6|ZKZsTOi*(5^VL<jmXo^>a$
zJ0NofgB2|t6W9aIHL^42%R&0ua+i#vEXjw`v^-5S>zbBP^@Voq<{%n=N}{dXKsKP$
zdu1N^WpEKW&Ilss=5QAadJ!S>AW08&CX0Z3|Dr++_)@t8lF)1!vsX`d-dL_y@Z#C?
zH#k&8Z+Atq{rX+IS!am^#X505&a7zfL<6G(mWpmW&$LuJDhiz?!ZZ2E$}Pq>8sE&K
zkY+}YY?JS=fSn1Nu@Q8+LTt>QKIPHK!3^}ib2&=8Ju3l@3vrO-Uo+X$xR<A~HZso(
zo93AjkRr!Ui&w|Jure+qLe9WE#z5+h=X(v$SMNa&JimNJtxo^f)Uv9mDpk}Cbycl+
z%W4_AD{5VxA+O0BF}?7!XsE+bzGz{HPr`VBWx%Bg*z0KuGW)-8OaMUnipaO6qUyeb
fXK%6_=FkLkHdygOT}!r`F25~42NJ@PS}Oeo<E?&)

literal 0
HcmV?d00001

diff --git a/samples/asmodeus/run.py b/samples/asmodeus/run.py
new file mode 100755
index 0000000..b646d06
--- /dev/null
+++ b/samples/asmodeus/run.py
@@ -0,0 +1,8 @@
+#!/usr/bin/python -u
+
+from asmodeus import *
+
+asmodeus = Asmodeus()
+if asmodeus.Setup():
+	while asmodeus.MoveCycle():
+		pass
diff --git a/samples/basic_cpp/Makefile b/samples/basic_cpp/Makefile
new file mode 100644
index 0000000..0a249b3
--- /dev/null
+++ b/samples/basic_cpp/Makefile
@@ -0,0 +1,30 @@
+#Makefile for basic_cpp
+# Sample C++ Stratego AI
+# UCC Programming Competition 2012 
+
+CPP = g++ -Wall -pedantic -lSDL -lGL  -g
+OBJ = basic_cpp.o
+
+BIN = basic_cpp
+
+
+
+$(BIN) : $(OBJ) 
+	$(CPP) -o $(BIN) $(OBJ)
+
+
+
+
+%.o : %.cpp %.h
+	$(CPP) -c $<
+
+clean :
+	$(RM) $(BIN) $(OBJ) $(LINKOBJ)
+
+#Cleans up all backup files
+clean_full: 
+	$(RM) $(BIN) $(OBJ) $(LINKOBJ)
+	$(RM) *.*~
+	$(RM) *~
+
+
diff --git a/samples/basic_cpp/basic_cpp b/samples/basic_cpp/basic_cpp
new file mode 100755
index 0000000000000000000000000000000000000000..a56a036c15bb82f3f55378f1cc2d0ff16a782943
GIT binary patch
literal 144981
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

literal 0
HcmV?d00001

diff --git a/samples/basic_cpp/basic_cpp.cpp b/samples/basic_cpp/basic_cpp.cpp
new file mode 100644
index 0000000..ab00826
--- /dev/null
+++ b/samples/basic_cpp/basic_cpp.cpp
@@ -0,0 +1,560 @@
+/**
+ * "basic_cpp", a sample Stratego AI for the UCC Programming Competition 2012
+ * Implementations of main function, and Helper functions
+ *
+ * @author Sam Moore (matches) [SZM]
+ * @website http://matches.ucc.asn.au/stratego
+ * @email progcomp@ucc.asn.au or matches@ucc.asn.au
+ * @git git.ucc.asn.au/progcomp2012.git
+ */
+
+#include "basic_cpp.h" //Needs class Base_Cpp and the includes in this file
+
+using namespace std;
+
+/**
+ * The characters used to represent various pieces
+ * NOTHING, BOULDER, FLAG, SPY, SCOUT, MINER, SERGEANT, LIETENANT, CAPTAIN, MAJOR, COLONEL, GENERAL, MARSHAL, BOMB, UNKNOWN
+ */
+char  Piece::tokens[] = {'.','*','F','s','9','8','7','6','5','4','3','2','1','B','?'};
+
+/**
+ * Gets a rank from the character used to represent it
+ * Basic lookup of Piece::tokens
+ */
+Rank Piece::GetRank(char token)
+{
+	for (int ii=0; ii <= 14; ++ii)
+	{
+		if (tokens[ii] == token)
+			return (Rank)(ii);
+	}
+	return UNKNOWN;
+}
+
+/**
+ * IMPLEMENTATION of Helper FOLLOWS
+ */
+
+/**
+ * Convert string to direction
+ */
+Direction Helper::StrToDir(const string & dir)
+{
+	if (dir == "UP")
+		return UP;
+	else if (dir == "DOWN")
+		return DOWN;
+	else if (dir == "LEFT")
+		return LEFT;
+	else if (dir == "RIGHT")
+		return RIGHT;
+	else
+		return DIRECTION_ERROR;
+}
+
+/**
+ * Direction to String
+ */
+void Helper::DirToStr(const Direction & dir, std::string & buffer)
+{
+	switch (dir)
+	{
+		case UP:
+			buffer = "UP";
+			break;
+		case DOWN:
+			buffer = "DOWN";
+			break;
+		case LEFT:
+			buffer = "LEFT";
+			break;
+		case RIGHT:
+			buffer = "RIGHT";
+			break;
+		default:
+			buffer = "DIRECTION_ERROR";
+			break;
+	}
+}
+
+/**
+ * Move a point in a direction
+ */
+void Helper::MoveInDirection(int & x, int & y, const Direction & dir, int multiplier)
+{
+	switch (dir)
+	{
+		case UP:
+			y -= multiplier;
+			break;
+		case DOWN:
+			y += multiplier;
+			break;
+		case LEFT:
+			x -= multiplier;
+			break;
+		case RIGHT:
+			x += multiplier;
+			break;
+		default:
+			break;
+	}
+
+}
+
+/**
+ * Tokenise a string
+ */
+int Helper::Tokenise(std::vector<string> & buffer, std::string & str, char split)
+{
+	string token = "";
+	for (unsigned int x = 0; x < str.size(); ++x)
+	{
+		if (str[x] == split && token.size() > 0)
+		{
+			buffer.push_back(token);
+			token = "";
+		}
+		if (str[x] != split)
+			token += str[x];
+	}
+	if (token.size() > 0)
+		buffer.push_back(token);
+	return buffer.size();
+}
+
+/**
+ * Convert string to integer
+ */
+int Helper::Integer(std::string & fromStr)
+{
+	stringstream s(fromStr);
+	int result = 0;
+	s >> result;
+	return result;
+}
+
+/**
+ * Read in a line from stdin
+ */
+void Helper::ReadLine(std::string & buffer)
+{
+	buffer = "";
+	for (char c = cin.get(); c != '\n' && cin.good(); c = cin.get())
+	{		
+		buffer += c;
+	}
+}
+
+/**
+ * IMPLEMENTATION of Board FOLLOWS
+ */
+
+/**
+ * Constructer for Board
+ */
+Board::Board(int w, int h) : width(w), height(h), board(NULL)
+{
+	//Construct 2D array of P*'s
+	board = new Piece**[width];
+	for (int x=0; x < width; ++x)
+	{
+		board[x] = new Piece*[height];
+		for (int y=0; y < height; ++y)
+			board[x][y] = NULL;
+	}
+}
+
+/**
+ * Destructor for board
+ */
+Board::~Board()
+{
+	//Destroy the 2D array of P*'s
+	for (int x=0; x < width; ++x)
+	{
+		for (int y=0; y < height; ++y)
+			delete board[x][y];
+		delete [] board[x];
+	}
+}
+
+/**
+ * Retrieves a piece on the Board
+ * @param x x coordinate
+ * @param y y coordinate
+ * @returns A Piece* for the piece, or NULL if there is no piece at the point given
+ */
+Piece * Board::Get(int x, int y) const
+{
+	if (ValidPosition(x, y))
+		return board[x][y];
+	return NULL;
+}
+/**
+ * Sets a piece on the Board
+ * @param x x coordinate
+ * @param y y coordinate
+ * @param newPiece
+ * @param returns newPiece if successful, NULL if not
+ */
+Piece * Board::Set(int x, int y, Piece * newPiece)
+{
+	if (!ValidPosition(x, y))
+		return NULL;
+	board[x][y] = newPiece;
+	assert(Get(x,y) == newPiece);
+	return newPiece;
+}
+
+/**
+ * IMPLEMENTATION of Base_Cpp FOLLOWS
+ */
+
+/**
+ * Constructor for AI
+ */
+BasicAI::BasicAI() : turn(0), board(NULL), units(), enemyUnits(), colour(NONE), colourStr("")
+{
+	srand(time(NULL));
+	cin.rdbuf()->pubsetbuf(NULL, 0);
+	cout.rdbuf()->pubsetbuf(NULL, 0);
+}
+
+/**
+ * Destructor for AI
+ */
+BasicAI::~BasicAI()
+{
+	if (board != NULL)
+		delete board;
+}
+
+
+/**
+ * Setup the AI
+ * @returns true if successful, false on error
+ */
+bool BasicAI::Setup()
+{
+	
+	cin >> colourStr; 
+
+
+	std::string opponentName(""); //opponentName is unused, just read it
+	cin >> opponentName; 
+	
+	int width = 0; int height = 0;
+	cin >> width; cin >> height;
+
+	while(cin.get() != '\n' && cin.good()); //trim newline
+	
+	board = new Board(width, height);
+
+	if (colourStr == "RED")
+	{
+		colour = RED;
+		cout << "FB8sB479B8\nBB31555583\n6724898974\n967B669999\n";
+	}
+	else if (colourStr == "BLUE")
+	{
+		colour = BLUE;
+		cout << "967B669999\n6724898974\nBB31555583\nFB8sB479B8\n";
+	}
+	else 
+		return false;
+
+	return (board != NULL);
+}
+
+/**
+ * Performs a move, including the saving states bits
+ * @returns true if the game is to continue, false if it is to end
+ */
+bool BasicAI::MoveCycle()
+{
+	//cerr << "BasicAI at MoveCycle()\n";
+	if (!InterpretResult())	
+		return false;
+	if (!ReadBoard())
+		return false;
+	if (!MakeMove())
+		return false;
+
+	turn++;
+	return InterpretResult();
+}
+
+/**
+ * Interprets the result of a move. Ignores the first move
+ * @returns true if successful, false if there was an error
+ */
+bool BasicAI::InterpretResult()
+{
+	//cerr << "BasicAI at InterpretResult()\n";
+	if (turn == 0)
+	{
+		while (cin.get() != '\n' && cin.good());
+		return true;
+	}
+
+
+	string resultLine; Helper::ReadLine(resultLine);
+	vector<string> tokens; Helper::Tokenise(tokens, resultLine, ' ');
+	
+	if (tokens.size() <= 0)
+	{
+		//cerr << "No tokens!\n";
+		return false;
+	}
+	
+	if (tokens[0] == "QUIT")
+	{
+		return false;
+	}
+
+	if (tokens[0] == "NO_MOVE")
+	{
+		return true;
+
+	}
+
+	if (tokens.size() < 4)
+	{
+		//cerr << "Only got " << tokens.size() << " tokens\n";
+		return false;
+	}
+	
+
+	int x = Helper::Integer(tokens[0]);
+	int y = Helper::Integer(tokens[1]);
+	
+	
+
+	Direction dir = Helper::StrToDir(tokens[2]);
+	string & outcome = tokens[3];
+
+	int x2 = x; int y2 = y; Helper::MoveInDirection(x2,y2,dir);
+
+	Piece * attacker = board->Get(x,y);
+	if (attacker == NULL)
+	{
+		//cerr << "No attacker!\n";
+		return false;
+	}
+	Piece * defender = board->Get(x2,y2);
+	if (outcome == "OK")
+	{
+		board->Set(x2,y2, attacker);
+		board->Set(x,y,NULL);
+		attacker->x = x2; attacker->y = y2;
+	}
+	else if (outcome == "KILLS")
+	{
+		if (defender == NULL)
+		{
+			//cerr << "No defender!\n";
+			return false;
+		}
+
+		board->Set(x2,y2, attacker);
+		board->Set(x,y,NULL);
+		attacker->x = x2; attacker->y = y2;
+		
+		attacker->rank = Piece::GetRank(tokens[4][0]);
+		ForgetUnit(defender);
+	}
+	else if (outcome == "DIES")
+	{
+		if (defender == NULL)
+		{
+			//cerr << "No defender!\n";
+			return false;
+		}
+		
+
+		board->Set(x,y,NULL);
+		defender->rank = Piece::GetRank(tokens[5][0]);
+		ForgetUnit(attacker);
+
+		
+	}
+	else if (outcome == "BOTHDIE")
+	{
+		board->Set(x,y,NULL);
+		board->Set(x2,y2, NULL);
+
+		ForgetUnit(attacker);
+		ForgetUnit(defender);
+	}
+	else if (outcome == "FLAG")
+	{
+		//cerr << "BasicAI - Flag was captured, exit!\n";
+		return false;
+	}
+	else if (outcome == "ILLEGAL")
+	{
+		//cerr << "BasicAI - Illegal move, exit!\n";
+		return false;
+	}
+
+	//cerr << "BasicAI finished InterpretResult()\n";
+	return true;
+}
+
+/**
+ * Performs a random move
+ * TODO: Overwrite with custom move
+ * @returns true if a move could be made (including NO_MOVE), false on error
+ */
+bool BasicAI::MakeMove()
+{
+	//cerr << "BasicAI at MakeMove()\n";
+	if (units.size() <= 0)
+	{
+		//cerr << " No units!\n";
+		return false;
+
+	}
+	
+	int index = rand() % units.size();
+	int startIndex = index;
+	while (true)
+	{
+		
+
+		Piece * piece = units[index];
+		if (piece != NULL && piece->Mobile())
+		{
+			int dirIndex = rand() % 4;
+			int startDirIndex = dirIndex;
+			while (true)
+			{
+				int x = piece->x; int y = piece->y;
+				assert(board->Get(x,y) == piece);
+				Helper::MoveInDirection(x,y,(Direction)(dirIndex));
+				if (board->ValidPosition(x,y))
+				{
+					Piece * target = board->Get(x,y);	
+					if (target == NULL || (target->colour != piece->colour && target->colour != NONE))
+					{
+						string dirStr;
+						Helper::DirToStr((Direction)(dirIndex), dirStr);
+						cout << piece->x << " " << piece->y << " " << dirStr << "\n";
+						return true;
+					}
+				}
+
+				dirIndex = (dirIndex + 1) % 4;
+				if (dirIndex == startDirIndex)
+					break;
+			}
+		}
+
+		index = (index+1) % (units.size());
+		if (index == startIndex)
+		{
+			cout << "NO_MOVE\n";
+			return true;
+		}
+	}
+	return true;
+}
+
+/**
+ * Reads in the board
+ * On first turn, sets up Board
+ * On subsquent turns, takes no action
+ * @returns true on success, false on error
+ */
+bool BasicAI::ReadBoard()
+{
+	//cerr << "BasicAI at ReadBoard()\n";
+	for (int y = 0; y < board->Height(); ++y)
+	{
+		string row;
+		Helper::ReadLine(row);
+		for (unsigned int x = 0; x < row.size(); ++x)
+		{
+			if (turn == 0)
+			{
+				switch (row[x])
+				{
+					case '.':
+						break;
+					case '#':
+						board->Set(x,y, new Piece(x,y,Piece::Opposite(colour), UNKNOWN));
+						enemyUnits.push_back(board->Get(x,y));
+						break;
+					case '+':
+						board->Set(x,y, new Piece(x,y,NONE, BOULDER));
+						break;
+					default:
+						board->Set(x,y,new Piece(x,y,colour, Piece::GetRank(row[x])));
+						units.push_back(board->Get(x,y));
+						break;
+				}
+			}
+		}
+	}
+	return true;
+}
+
+/**
+ * Removes a piece from memory
+ * @param piece The piece to delete
+ * @returns true if the piece was actually found
+ */
+bool BasicAI::ForgetUnit(Piece * piece)
+{	
+	//cerr << "BasicAI at ForgetUnit()\n";
+	bool result = false;
+	vector<Piece*>::iterator i = units.begin(); 
+	while (i != units.end())
+	{
+		if ((*i) == piece)
+		{
+			i = units.erase(i); result = true;
+			continue;
+		}
+		++i;
+	}
+
+	i = enemyUnits.begin();
+	while (i != enemyUnits.end())
+	{
+		if ((*i) == piece)
+		{
+			i = enemyUnits.erase(i); result = true;
+			continue;
+		}
+		++i;
+	}
+
+
+	delete piece;
+	return result;
+}
+
+
+/**
+ * The main function
+ * @param argc
+ * @param argv
+ * @returns zero on success, non-zero on failure
+ */
+int main(int argc, char ** argv)
+{
+
+	srand(time(NULL));
+
+	BasicAI * basicAI = new BasicAI();
+	if (basicAI->Setup())
+	{
+		while (basicAI->MoveCycle());		
+	}
+	delete basicAI;
+	exit(EXIT_SUCCESS);
+	return 0;
+}
diff --git a/samples/basic_cpp/basic_cpp.h b/samples/basic_cpp/basic_cpp.h
new file mode 100644
index 0000000..733d9a7
--- /dev/null
+++ b/samples/basic_cpp/basic_cpp.h
@@ -0,0 +1,145 @@
+/**
+ * "basic_cpp", a sample Stratego AI for the UCC Programming Competition 2012
+ * Declarations for classes Piece, Board and Basic_Cpp
+ * @author Sam Moore (matches) [SZM]
+ * @website http://matches.ucc.asn.au/stratego
+ * @email progcomp@ucc.asn.au or matches@ucc.asn.au
+ * @git git.ucc.asn.au/progcomp2012.git
+ */
+
+#ifndef BASIC_CPP_H
+#define BASIC_CPP_H
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <cassert>
+
+
+
+
+
+/**
+ * enum for possible ranks of pieces
+ */
+typedef enum {UNKNOWN=14,BOMB=13,MARSHAL=12, GENERAL=11, COLONEL=10, MAJOR=9, CAPTAIN=8, LIEUTENANT=7, SERGEANT=6, MINER=5, SCOUT=4, SPY=3, FLAG=2,BOULDER=1, NOTHING=0} Rank;
+
+/**
+ * enum for possible colours of pieces and the AI
+ */		
+typedef enum {RED=0, BLUE=1, NONE, BOTH} Colour;
+
+
+/**
+ * Class to represent a piece on the board
+ * TODO: Add features required for Pieces as used by your AI
+ * 	For example, can replace the single member "rank" with two, "maxRank" and "minRank" 
+ *	Or add an array of probability values for EVERY rank!
+ */
+class Piece
+{
+	public:
+		static  char tokens[]; //The tokens used to identify various pieces
+
+		Piece(int newX, int newY,const Colour & newColour, const Rank & newRank = UNKNOWN)
+			: x(newX), y(newY), colour(newColour), rank(newRank) {}
+		virtual ~Piece() {}
+
+		bool Mobile() const {return rank != BOMB && rank != FLAG;}
+		
+		static Colour Opposite(const Colour & colour) {return colour == RED ? BLUE : RED;}
+
+		int x; int y;
+		const Colour colour; //The colour of the piece
+		Rank rank; //The rank of the piece
+
+		static Rank GetRank(char token); //Helper to get rank from character
+
+};
+
+/**
+ * enum for Directions that a piece can move in
+ */
+typedef enum {UP=0, DOWN=1, LEFT=2, RIGHT=3, DIRECTION_ERROR=4} Direction;
+
+/**
+ * Class to represent a board
+ */
+class Board
+{
+	public:
+		Board(int width, int height); //Construct a board with width and height
+		virtual ~Board(); //Destroy the board
+
+		Piece * Get(int x, int y) const; //Retrieve single piece
+		Piece *  Set(int x, int y, Piece * newPiece); //Add piece to board
+
+		int Width() const {return width;} //getter for width
+		int Height() const {return height;} //getter for height
+
+		bool ValidPosition(int x, int y) const {return (x >= 0 && x < width && y >= 0 && y < height);} //Helper - is position within board?
+	private:
+
+		int width; //The width of the board
+		int height; //The height of the board
+		Piece ** * board; //The pieces on the board
+};
+
+/**
+ * Basic AI class
+ * TODO: Make sure that if Piece is changed, BasicAI is updated to be consistent
+ * TODO: More complex AI's should inherit off this class.
+ *	It is recommended that only MakeMove is altered - hence the other functions are not virtual.
+ */
+class BasicAI
+{
+	public:
+		BasicAI(); //Constructor
+		virtual ~BasicAI(); //Destructor
+
+		bool Setup(); //Implements setup protocol
+		bool MoveCycle(); //Implements the MoveCycle protocol
+		bool ReadBoard(); //Reads the board as part of the MoveCycle protocol
+		bool InterpretResult(); //Interprets the result of a move
+		virtual bool MakeMove(); //Makes a move - defaults to randomised moves
+		bool DebugPrintBoard(); //DEBUG - Prints the board to stderr
+	protected:
+		int turn;
+		Board * board; //The board
+		std::vector<Piece*> units; //Allied units
+		std::vector<Piece*> enemyUnits; //Enemy units
+
+		bool ForgetUnit(Piece * forget); //Delete and forget about a unit
+
+		Colour colour;
+		std::string colourStr;
+};
+
+/**
+ * Purely static class of Helper functions
+ */
+class Helper
+{
+	public:
+		static Direction StrToDir(const std::string & str); //Helper - Convert string to a Direction enum
+		static void DirToStr(const Direction & dir, std::string & buffer); //Helper - Convert Direction enum to a string
+		static void MoveInDirection(int & x, int & y, const Direction & dir, int multiplier = 1); //Helper - Move a point in a direction
+		static int Tokenise(std::vector<std::string> & buffer, std::string & str, char split = ' '); //Helper - Split a string into tokens
+		static int Integer(std::string & fromStr); //Helper - convert a string to an integer
+		static void ReadLine(std::string & buffer); //Helper - read a line from stdin
+	private:
+		//By making these private we ensure that no one can create an instance of Helper
+		//Yes we could use namespaces instead, but I prefer this method because you can use private static member variables
+		//Not that I am. But you can.
+		Helper() {}
+		~Helper() {}
+};
+
+
+
+#endif //BASIC_CPP_H
+
+//EOF
+
diff --git a/samples/basic_cpp/info b/samples/basic_cpp/info
new file mode 100644
index 0000000..ee1b502
--- /dev/null
+++ b/samples/basic_cpp/info
@@ -0,0 +1 @@
+basic_cpp
diff --git a/samples/basic_python/basic_python.py b/samples/basic_python/basic_python.py
new file mode 100644
index 0000000..be88d56
--- /dev/null
+++ b/samples/basic_python/basic_python.py
@@ -0,0 +1,292 @@
+#!/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.
+
+"""
+ basic_python.py - A sample Stratego AI for the UCC Programming Competition 2012
+
+ Written in python, the slithery language 
+ Simply makes random moves, as long as possible
+
+ author Sam Moore (matches) [SZM]
+ website http://matches.ucc.asn.au/stratego
+ email progcomp@ucc.asn.au or matches@ucc.asn.au
+ git git.ucc.asn.au/progcomp2012.git
+"""
+
+import sys
+import random
+
+ranks = ['B','1','2','3','4','5','6','7','8','9','s','F', '?', '+']
+
+def move(x, y, direction):
+	""" Moves point (x,y) in direction, returns a pair """
+	if direction == "UP":
+		return (x,y-1)
+	elif direction == "DOWN":
+		return (x,y+1)
+	elif direction == "LEFT":
+		return (x-1, y)
+	elif direction == "RIGHT":
+		return (x+1, 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
+
+	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
+	
+
+
+
+class BasicAI:
+	"""
+		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 = []
+
+		
+
+	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(' ')
+		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 "FB8sB479B8\nBB31555583\n6724898974\n967B669999"
+		elif self.colour == "BLUE":
+			print "967B669999\n6724898974\nBB31555583\nFB8sB479B8"
+		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("BasicAI MakeMove here...\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")
+		while True:
+			piece = self.units[index]
+			if piece != None and piece.mobile():
+				dirIndex = random.randint(0, len(directions)-1)
+				startDirIndex = dirIndex
+				
+				while True:
+					#sys.stderr.write("Trying index " + str(dirIndex) + "\n")
+					p = move(piece.x, piece.y, directions[dirIndex])
+					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"):	
+							print str(piece.x) + " " + str(piece.y) + " "+directions[dirIndex]
+							return True
+					dirIndex = (dirIndex + 1) % len(directions)
+					if startDirIndex == dirIndex:
+						break
+
+			index = (index + 1) % len(self.units)
+			if startIndex == index:
+				print "NO_MOVE"
+				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
+		"""
+		#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())
+
+
+		#sys.stderr.write("	Board position " + str(x) + " " + str(y) + " is OK!\n")		
+
+		direction = result[2].strip()
+		outcome = result[3].strip()
+		
+		p = move(x,y,direction)
+
+		
+
+		if outcome == "OK":
+			self.board[p[0]][p[1]] = self.board[x][y]
+			self.board[x][y].x = p[0]
+			self.board[x][y].y = p[1]
+
+			self.board[x][y] = None
+		elif outcome == "KILLS":
+			if self.board[p[0]][p[1]] == None:
+				return False
+
+			if self.board[p[0]][p[1]].colour == self.colour:
+				self.units.remove(self.board[p[0]][p[1]])
+			elif self.board[p[0]][p[1]].colour == oppositeColour(self.colour):
+				self.enemyUnits.remove(self.board[p[0]][p[1]])
+
+			self.board[x][y].x = p[0]
+			self.board[x][y].y = p[1]
+
+
+			self.board[p[0]][p[1]] = self.board[x][y]
+			self.board[x][y].rank = result[4].strip()
+
+			self.board[x][y] = None
+			
+		elif outcome == "DIES":
+			if self.board[p[0]][p[1]] == None:
+				return False
+
+			if self.board[x][y].colour == self.colour:
+				self.units.remove(self.board[x][y])
+			elif self.board[x][y].colour == oppositeColour(self.colour):
+				self.enemyUnits.remove(self.board[x][y])
+
+			self.board[p[0]][p[1]].rank = result[5].strip()
+			self.board[x][y] = None
+		elif outcome == "BOTHDIE":
+			if self.board[p[0]][p[1]] == None:
+				return False
+
+
+			if self.board[x][y].colour == self.colour:
+				self.units.remove(self.board[x][y])
+			elif self.board[x][y].colour == oppositeColour(self.colour):
+				self.enemyUnits.remove(self.board[x][y])
+			if self.board[p[0]][p[1]].colour == self.colour:
+				self.units.remove(self.board[p[0]][p[1]])
+			elif self.board[p[0]][p[1]].colour == oppositeColour(self.colour):
+				self.enemyUnits.remove(self.board[p[0]][p[1]])
+
+
+			self.board[p[0]][p[1]] = None
+			self.board[x][y] = None
+		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")
+
+#basicAI = BasicAI()
+#if basicAI.Setup():
+#	while basicAI.MoveCycle():
+#		pass
+
diff --git a/samples/basic_python/basic_python.pyc b/samples/basic_python/basic_python.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4c201efce0acbd9d849a70cb74cd7174dbeeb55f
GIT binary patch
literal 9170
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
QJNq-|GKB+$!qCXS0l`d3Z~y=R

literal 0
HcmV?d00001

diff --git a/samples/basic_python/info b/samples/basic_python/info
new file mode 100644
index 0000000..9260726
--- /dev/null
+++ b/samples/basic_python/info
@@ -0,0 +1 @@
+basic_python.py
diff --git a/samples/basic_python/run.py b/samples/basic_python/run.py
new file mode 100755
index 0000000..80b4cfe
--- /dev/null
+++ b/samples/basic_python/run.py
@@ -0,0 +1,8 @@
+#!/usr/bin/python -u
+
+from basic_python import *
+
+basicAI = BasicAI()
+if basicAI.Setup():
+	while basicAI.MoveCycle():
+		pass
diff --git a/simulator/Makefile b/simulator/Makefile
new file mode 100644
index 0000000..1d71ef5
--- /dev/null
+++ b/simulator/Makefile
@@ -0,0 +1,15 @@
+#Makefile for simulations
+# Not used for building simulate.py
+# Used for building/removing results
+
+BASEDIR = /home/sam/Documents/progcomp2012/
+RESULTSDIR = /home/sam/Documents/progcomp2012/results
+LOGDIR = /home/sam/Documents/progcomp2012/log
+AGENTSDIR = /home/sam/Documents/progcomp2012/samples
+MANAGER = /home/sam/Documents/progcomp2012/manager/stratego
+
+
+
+clean:
+	rm -r -f $(RESULTSDIR)
+	rm -r -f $(LOGDIR)
diff --git a/simulator/simulate.py b/simulator/simulate.py
index 5531143..60320d9 100755
--- a/simulator/simulate.py
+++ b/simulator/simulate.py
@@ -26,9 +26,9 @@ nGames = 10 #Number of games played by each agent against each opponent. Half wi
 managerPath = baseDirectory+"manager/stratego" #Path to the manager program
 
 
-scores = {"WIN":3, "DRAW":2, "LOSS":1, "NONE":0} #Score dictionary
-#NONE occurs if both programs crash. If only one program crashes the result is reported as a win-loss
+scores = {"VICTORY":(3,1), "DEFEAT":(1,3), "SURRENDER":(0,3), "DRAW":(2,2), "DRAW_DEFAULT":(1,1), "ILLEGAL":(-1,2), "DEFAULT":(2,-1), "BOTH_ILLEGAL":(-1,-1), "INTERNAL_ERROR":(0,0)} #Score dictionary
 
+verbose = True
 
 
 #Make necessary directories
@@ -55,15 +55,19 @@ agentNames = os.listdir(agentsDirectory)
 agents = []
 for name in agentNames:
 	#sys.stdout.write("\nLooking at Agent: \""+ str(name)+"\"... ")
-	sys.stdout.write("Scan \""+name+"\"... ")
+	if verbose:
+		sys.stdout.write("Scan \""+name+"\"... ")
 	if os.path.isdir(agentsDirectory+name) == False: #Remove non-directories
-		sys.stdout.write(" Invalid! (Not a directory)\n")
+		if verbose:
+			sys.stdout.write(" Invalid! (Not a directory)\n")
 		continue
 
 	if os.path.exists(agentsDirectory+name+"/info") == False: #Try and find the special "info" file in each directory; ignore if it doesn't exist
-		sys.stdout.write(" Invalid! (No \"info\" file found)\n")
+		if verbose:
+			sys.stdout.write(" Invalid! (No \"info\" file found)\n")
 		continue
-	sys.stdout.write(" Valid!")
+	if verbose:
+		sys.stdout.write(" Valid!")
 	#sys.stdout.write("OK")
 	#Convert the array of names to an array of triples
 	#agents[0] - The name of the agent (its directory)
@@ -71,19 +75,17 @@ for name in agentNames:
 	#agents[2] - The score the agent achieved in _this_ round. Begins at zero
 	agentExecutable = agentsDirectory+name+"/"+(open(agentsDirectory+name+"/info").readline().strip())
 	agents.append([name, agentExecutable, 0])
-	sys.stdout.write(" (Run program \""+agentExecutable+"\")\n")
+	if verbose:
+		sys.stdout.write(" (Run program \""+agentExecutable+"\")\n")
 
 if len(agents) == 0:
 	print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents."
 	sys.exit(0)
+if verbose:
+	print "Total: " + str(len(agents)) + " valid agents found (From "+str(len(agentNames))+" possibilities)"
+	print ""
+	print "Commencing ROUND " + str(roundNumber) + " combat! ("+str(nGames)+" games per pairing)"
 
-print "Total: " + str(len(agents)) + " valid agents found (From "+str(len(agentNames))+" possibilities)"
-
-print ""
-
-print "Commencing ROUND " + str(roundNumber) + " combat! ("+str(nGames)+" games per pairing)"
-print "Points values are: "+str(scores)
-print ""
 
 normalGames = 0
 draws = 0
@@ -96,45 +98,47 @@ for red in agents:  #for each agent playing as red,
 			continue #Exclude battles against self
 		for i in range(1, nGames/2 + 1):
 			#Play a game and read the result. Note the game is logged to a file based on the agent's names
-			sys.stdout.write("Agents: \""+red[0]+"\" and \""+blue[0]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ")
+			if verbose:
+				sys.stdout.write("Agents: \""+red[0]+"\" and \""+blue[0]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ")
 			logFile = logDirectory + "round"+str(roundNumber) + "/"+red[0]+"_vs_"+blue[0]+"_"+str(i)
 			outline = os.popen(managerPath + " -o " + logFile + " " + red[1] + " " + blue[1], "r").read()
 			results = outline.split(' ')
-			#Look at who won, and adjust scores based on that
-			if results[0] == "NONE":
-				red[2] += scores["NONE"]
-				blue[2] += scores["NONE"]
-				sys.stdout.write(" No contest. (Check AI for errors).\n")
-				aiErrors += 1
-			elif results[0] == "DRAW":
-				red[2] += scores["DRAW"]
-				blue[2] += scores["DRAW"]
-				sys.stdout.write(" Draw.\n")
-				draws += 1
-			elif results[0] == red[1]:
-				red[2] += scores["WIN"]
-				blue[2] += scores["LOSS"]
-				sys.stdout.write(" \""+red[0]+"\"\n")
-				normalGames += 1
-			elif results[0] == blue[1]:
-				red[2] += scores["LOSS"]
-				blue[2] += scores["WIN"]
-				sys.stdout.write(" \""+blue[0]+"\"\n")
-				normalGames += 1
+			
+			if len(results) != 6:
+				if verbose:
+					sys.stdout.write("Garbage output!	" + outline)
 			else:
-				sys.stdout.write(" Garbage output! \""+outline+"\" (log file \""+logFile+"\")\n")
-				managerErrors += 1
-		
+				if results[1] == "RED":
+					red[2] += scores[results[2]][0]
+					blue[2] += scores[results[2]][1]
+				elif results[1] == "BLUE":
+					red[2] += scores[results[2]][1]
+					blue[2] += scores[results[2]][0]
+				elif results[1] == "BOTH":
+					red[2] += scores[results[2]][0]
+					blue[2] += scores[results[2]][1]
+					red[2] += scores[results[2]][1]
+					blue[2] += scores[results[2]][0]
+
+			if verbose:
+				sys.stdout.write("	" + outline)
+				
+				
+				
+				
 
-print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. "
+		
+if verbose:
+	print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. "
 if managerErrors != 0:
-	print "	WARNING: Recieved "+str(managerErrors)+" garbage outputs. Check the manager program."
+	print "WARNING: Recieved "+str(managerErrors)+" garbage outputs. Check the manager program."
 
-print "" 
+if verbose:
+	print "" 
 #We should now have complete score values.
 		
-
-sys.stdout.write("Creating results files for ROUND " + str(roundNumber) + "... ")
+if verbose:
+	sys.stdout.write("Creating results files for ROUND " + str(roundNumber) + "... ")
 
 agents.sort(key = lambda e : e[2], reverse=True) #Sort the agents based on score
 
@@ -142,13 +146,14 @@ resultsFile = open(resultsDirectory+"round"+str(roundNumber)+".results", "w") #C
 for agent in agents:
 	resultsFile.write(agent[0] + " " + str(agent[2]) +"\n") #Write the agent names and scores into the file, in descending order
 
-sys.stdout.write(" Complete!\n")
-
-sys.stdout.write("Updating total scores... ");
+if verbose:
+	sys.stdout.write(" Complete!\n")
+	sys.stdout.write("Updating total scores... ");
 
 #Now update the total scores
 if os.path.exists(resultsDirectory+"total.scores"):
-	sys.stdout.write(" Reading from \""+resultsDirectory+"total.scores\" to update scores... ")
+	if verbose:
+		sys.stdout.write(" Reading from \""+resultsDirectory+"total.scores\" to update scores... ")
 	totalFile = open(resultsDirectory+"total.scores", "r") #Try to open the total.scores file
 	for line in totalFile: #For all entries, 
 		data = line.split(' ')
@@ -163,11 +168,13 @@ if os.path.exists(resultsDirectory+"total.scores"):
 	agents.sort(key = lambda e : e[2], reverse=True)
 
 else:
-	sys.stdout.write(" First round - creating \""+resultsDirectory+"total.scores\"... ")
-sys.stdout.write(" Complete!\n")
+	if verbose:
+		sys.stdout.write(" First round - creating \""+resultsDirectory+"total.scores\"... ")
+if verbose:
+	sys.stdout.write(" Complete!\n")
+	print "Finished writing results for ROUND " + str(roundNumber)
+	print ""
 
-print "Finished writing results for ROUND " + str(roundNumber)
-print ""
 
 print "RESULTS FOR ROUND " + str(roundNumber)
 print "Agent: [name, path, total_score, recent_score]"
-- 
GitLab