diff --git a/agents/basic_java/Makefile b/agents/basic_java/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b058cdfedc39cf058bfe1d8e4788ad8c88d77278
--- /dev/null
+++ b/agents/basic_java/Makefile
@@ -0,0 +1,13 @@
+#Makefile for basic_java
+# Sample C++ Stratego AI
+# UCC Programming Competition 2012 
+
+BasicAI.class : basic.java Reader.java piece.java
+	javac Reader.java
+	javac piece.java
+	javac basic.java
+
+clean : 
+	rm *.class
+
+
diff --git a/agents/basic_java/Reader.java b/agents/basic_java/Reader.java
new file mode 100644
index 0000000000000000000000000000000000000000..da51459e4ee8ed617346d6008100e151b3fa9c3e
--- /dev/null
+++ b/agents/basic_java/Reader.java
@@ -0,0 +1,48 @@
+/**
+ * Needed to do reading from stdin in Java
+ * SERIOUSLY
+ * Stupid Java
+ * @author Some website somewhere
+ */
+import java.io.*;
+import java.lang.Exception;
+import java.util.Vector;
+
+class Reader
+{
+	public static String readLine()
+	{
+		String s = "";
+		try 
+		{
+			InputStreamReader converter = new InputStreamReader(System.in);
+			BufferedReader in = new BufferedReader(converter);
+			s = in.readLine();
+		} 
+		catch (Exception e) 
+		{
+			System.out.println("EXCEPTION: Reader.readLine - "+e); 
+		}
+		return s;
+	}
+
+	public static Vector<String> readTokens()
+	{
+		String r = readLine();
+		String token = "";
+		Vector<String> result = new Vector<String>();
+		for (int ii=0; ii < r.length(); ++ii)
+		{
+			if (r.charAt(ii) == ' ' || r.charAt(ii) == '\n')
+			{
+				result.add(new String(token));	
+				//System.out.println("Token " + token);
+				token = "";
+			}
+			else
+				token += r.charAt(ii);
+		}
+		result.add(new String(token));
+		return result;
+	}
+}
diff --git a/agents/basic_java/basic.java b/agents/basic_java/basic.java
new file mode 100644
index 0000000000000000000000000000000000000000..242e6cb4164025e54ddfd970e07ab35fa83bd14a
--- /dev/null
+++ b/agents/basic_java/basic.java
@@ -0,0 +1,390 @@
+/**
+ * Class to manage a Stratego playing AI in Java
+ * @author Sam Moore for the UCC::Progcomp 2012
+ * @website http://progcomp.ucc.asn.au
+ */
+
+import java.lang.Exception;
+import java.util.Vector;
+import java.util.Random;
+
+
+
+class BasicAI
+{
+
+
+	
+	/**
+ 	 * Moves a point in a direction, returns new point
+	 * @param x x coord
+	 * @param y y coord
+	 * @param direction Indicates direction. Must be "LEFT", "RIGHT", "UP", "DOWN"
+	 * @param multiplier Spaces to move
+	 * @returns An array of length 2, containing the new x and y coords
+	 * @throws Exception on unrecognised direction
+	 */
+	public static int[] Move(int x, int y, String direction, int multiplier) throws Exception
+	{
+		//NOTE: The board is indexed so that the top left corner is x = 0, y = 0
+		//	Does not check that coordiantes would be valid in the board.
+
+		if (direction.compareTo("DOWN") == 0)
+			y += multiplier; //Moving down increases y
+		else if (direction.compareTo("UP") == 0)
+			y -= multiplier; //Moving up decreases y
+		else if (direction.compareTo("LEFT") == 0)
+			x -= multiplier; //Moving left decreases x
+		else if (direction.compareTo("RIGHT") == 0)
+			x += multiplier;
+		else
+		{
+			throw new Exception("BasicAI.Move - Unrecognised direction " + direction);
+		}
+
+		int result[] = new int[2];
+		result[0] = x; result[1] = y;
+		return result;
+	}
+
+	/**
+	 * Returns the "opposite" colour to that given
+	 * @param colour Must be "RED" or "BLUE"
+	 * @returns The alternate String to colour
+	 * @throws Exception if colour is not "RED" or "BLUE"
+	 */
+	public static String OppositeColour(String colour) throws Exception
+	{
+		if (colour.compareTo("BLUE") == 0)
+			return "RED";
+		else if (colour.compareTo("RED") == 0)
+			return "BLUE";
+		else
+			throw new Exception("BasicAI.OppositeColour - Unrecognised colour " + colour);
+	}
+
+	/**
+	 * Tests if a value is an integer
+	 * I cry at using exceptions for this
+	 */
+	public static boolean IsInteger(String str)
+	{
+		try
+		{
+			Integer.parseInt(str);
+		}
+		catch (NumberFormatException e)
+		{
+			return false;
+		}
+		return true;
+	}
+
+	private int turn; //The turn number of the game
+	private Piece board[][]; //The board
+	private Vector<Piece> units; //All units
+	private Vector<Piece> enemyUnits; //All enemy units
+	private Piece lastMoved; //Last moved piece
+	private String colour; //Colour of the AI
+	private String opponentName; //Name of the AI's opponent
+	private int width; //Width of the board (NOTE: Should always be 10)
+	private int height; //Height of the board (NOTE: Should always be 10)
+
+	private static int totalAllies[] = {6,1,1,2,3,4,4,4,5,8,1,1}; //Numbers of allies, B -> F
+	private static int totalEnemies[] = {6,1,1,2,3,4,4,4,5,8,1,1}; //Numbers of enemies, B -> F
+	private static int hiddenEnemies[] = {6,1,1,2,3,4,4,4,5,8,1,1}; //Number of hidden enemies of each type
+	private static int hiddenAllies[] = {6,1,1,2,3,4,4,4,5,8,1,1}; //Number of hidden allies of each type
+
+	private static String directions[] = {"UP", "DOWN", "LEFT", "RIGHT"}; //All available directions
+	
+	private static Random rand = new Random(); //A random number generator
+	
+	/**
+	 * Constructor
+ 	 * Sets up a board, prepares to play
+	 */
+	public BasicAI()
+	{
+		turn = 0;
+		board = null;
+		units = new Vector<Piece>();
+		enemyUnits = new Vector<Piece>();
+
+		lastMoved = null;
+		colour = null;
+		opponentName = null;
+
+		//HACK to get rid of stupid Javac warnings
+		if (lastMoved == null && opponentName == null);
+	}
+
+	/**
+	 * Implements Setup phase of protocol described in manager program man page
+	 * Always uses the same setup. Override to create custom setups.
+	 */
+	public void Setup() throws Exception
+	{
+		Vector<String> setup = Reader.readTokens(); //Wierd java way of doing input from stdin, see Reader.java
+		if (setup.size() != 4)
+		{
+			throw new Exception("BasicAI.Setup - Expected 4 tokens, got " + setup.size());
+		}	
+		colour = setup.elementAt(0);
+		opponentName = setup.elementAt(1);
+		width = Integer.parseInt(setup.elementAt(2));
+		height = Integer.parseInt(setup.elementAt(3));
+
+		if (width != 10 || height != 10)
+			throw new Exception("BasicAI.Setup - Expected width and height of 10, got " + width + " and " + height);
+
+		board = new Piece[width][height];
+		for (int x=0; x < board.length; ++x)
+		{
+			for (int y = 0; y < board[x].length; ++y)
+				board[x][y] = null;
+		}
+
+		//TODO: Modify this setup
+		if (colour.compareTo("RED") == 0)
+			System.out.println("FB8sB479B8\nBB31555583\n6724898974\n967B669999");
+		else if (colour.compareTo("BLUE") == 0)
+			System.out.println("967B669999\n6724898974\nBB31555583\nFB8sB479B8");
+		else
+			throw new Exception("BasicAI.Setup - Unrecognised colour of " + colour);
+
+	}
+
+	/**
+	 * Cycles a move
+ 	 */
+	public void MoveCycle() throws Exception
+	{
+		InterpretResult();
+		ReadBoard();
+		MakeMove();
+		InterpretResult();
+	}
+
+	/**
+	 * Makes a move
+	 * TODO: Rewrite move algorithm (currently uses random)
+	 */
+	public void MakeMove() throws Exception
+	{
+		if (units.size() <= 0)
+			throw new Exception("BasicAI.MakeMove - No units left!");
+
+		int index = rand.nextInt(units.size() - 1); //Pick index of unit to move
+		int startIndex = index; //Remember it
+		
+		while (true) //Don't worry, there is a break
+		{
+			Piece piece = units.elementAt(index);
+			if (piece == null)
+				throw new Exception("BasicAI.MakeMove - null unit ???");
+	
+			if (piece.Mobile())
+			{
+				int dirIndex = rand.nextInt(directions.length); //Pick a random direction index
+				int startDirIndex = dirIndex; //Remember
+				while (true)
+				{
+					int p[] = Move(piece.x, piece.y, directions[dirIndex], 1);
+					if (p[0] >= 0 && p[0] < width && p[1] >= 0 && p[1] < height)
+					{
+						Piece target = board[p[0]][p[1]];
+						if (target == null || (target.colour != piece.colour && target.colour != "NONE" && target.colour != "BOTH"))
+						{
+							System.out.println(""+piece.x + " " + piece.y + " " + directions[dirIndex]);
+							return;
+						}
+						
+					}
+					dirIndex = (dirIndex + 1) % directions.length;
+					if (dirIndex == startDirIndex)
+						break;
+				}
+			}
+			index = (index + 1) % units.size();
+			if (index == startIndex)
+			{
+				System.out.println("NO_MOVE");
+				break;
+			}
+		}
+		
+	}
+	
+	/**
+	 * Reads the board
+	 */
+	public void ReadBoard() throws Exception
+	{
+		for (int y = 0; y < height; ++y)
+		{
+			String row = Reader.readLine();
+			if (row.length() != width)
+				throw new Exception("BasicAI.ReadBoard - Row " + y + " has width " + row.length() + " instead of " + width);
+			for (int x = 0; x < width; ++x)
+			{
+				if (turn == 0)
+				{
+					switch (row.charAt(x))
+					{
+						case '.':
+							break;
+						case '#':
+							board[x][y] = new Piece(OppositeColour(colour), '?', x, y);
+							enemyUnits.add(board[x][y]);
+							break;
+						case '+':
+							board[x][y] = new Piece("NONE", '+', x, y);
+							break;
+						default:
+							board[x][y] = new Piece(colour, row.charAt(x), x, y);
+							units.add(board[x][y]);
+							break;	
+					}
+						
+				}
+			}
+		}
+	}
+
+	/**
+	 * Removes a unit from the game
+	 */
+	private void KillUnit(Piece kill) throws Exception
+	{
+		if (kill.colour.compareTo(colour) == 0)
+		{
+			totalAllies[Piece.Index(kill.rank)] -= 1;
+			if (units.remove(kill) == false)
+				throw new Exception("BasicAI.KillUnit - Couldn't remove allied Piece from units Vector!");
+		}
+		else if (kill.colour.compareTo(OppositeColour(colour)) == 0)
+		{
+			totalEnemies[Piece.Index(kill.rank)] -= 1;
+			if (enemyUnits.remove(kill) == false)
+				throw new Exception("BasicAI.KillUnit - Couldn't remove enemy Piece from enemyUnits Vector!");
+		}
+	}
+
+	/**
+	 * Interprets the result of a move, updates all relevant variables
+	 */
+	public void InterpretResult() throws Exception
+	{
+		Vector<String> result = Reader.readTokens();
+		if (turn == 0)
+			return;
+		if (result.elementAt(0).compareTo("QUIT") == 0)
+			System.exit(0);
+		if (result.elementAt(0).compareTo("NO_MOVE") == 0)
+			return;
+
+		if (result.size() < 4)
+		{
+			throw new Exception("BasicAI.InterpretResult - Expect at least 4 tokens, got " + result.size());
+		}
+
+		int x = Integer.parseInt(result.elementAt(0));
+		int y = Integer.parseInt(result.elementAt(1));
+		String direction = result.elementAt(2);
+
+		int multiplier = 1;
+		String outcome = result.elementAt(3);
+		int outIndex = 3;
+		if (IsInteger(outcome))
+		{
+			multiplier = Integer.parseInt(outcome);
+			outcome = result.elementAt(4);
+			outIndex = 4;
+		}
+		int p[] = Move(x,y,direction, multiplier);
+
+		Piece attacker = board[x][y];
+		board[x][y] = null;
+		if (attacker == null)
+			throw new Exception("BasicAI.InterpretResult - Couldn't find a piece to move at (" + x +"," + y+")");
+
+		lastMoved = attacker;
+
+		Piece defender = board[p[0]][p[1]];
+		
+
+		attacker.x = p[0]; attacker.y = p[1];
+		attacker.positions.add(0, p);
+
+		if (result.size() >= outIndex + 3)
+		{
+			if (defender == null)
+				throw new Exception("BasicAI.InterpretResult - Result suggests a defender at ("+p[0]+","+p[1]+"), but none found");
+			attacker.rank = result.elementAt(outIndex+1).charAt(0); //ranks are 1 char long
+			if (attacker.beenRevealed == false)
+			{
+				if (attacker.colour.compareTo(colour) == 0)
+					hiddenAllies[Piece.Index(attacker.rank)] -= 1;
+				else if (attacker.colour.compareTo(OppositeColour(colour)) == 0)
+					hiddenEnemies[Piece.Index(attacker.rank)] -= 1;
+				else
+					throw new Exception("BasicAI.InterpretResult - Colour " + attacker.colour + " for moving piece makes no sense.");
+			}
+			attacker.beenRevealed = true;
+			defender.rank = result.elementAt(outIndex+2).charAt(0); //ranks are 1 char long
+			if (defender.beenRevealed == false)
+			{
+				if (defender.colour.compareTo(colour) == 0)
+					hiddenAllies[Piece.Index(defender.rank)] -= 1;
+				else if (attacker.colour.compareTo(OppositeColour(colour)) == 0)
+					hiddenEnemies[Piece.Index(defender.rank)] -= 1;
+				else
+					throw new Exception("BasicAI.InterpretResult - Colour " + attacker.colour + " for defending piece makes no sense.");
+			}
+			defender.beenRevealed = true;
+			
+		}
+		if (outcome.compareTo("OK") == 0)
+			board[p[0]][p[1]] = attacker;
+		else if (outcome.compareTo("KILLS") == 0)
+		{
+			board[p[0]][p[1]] = attacker;
+			KillUnit(defender);
+		}
+		else if (outcome.compareTo("DIES") == 0)
+		{
+			KillUnit(attacker);
+		}
+		else if (outcome.compareTo("BOTHDIE") == 0)
+		{
+			board[p[0]][p[1]] = null;
+			KillUnit(attacker);
+			KillUnit(defender);
+		}
+		else
+		{
+			System.exit(0); //Game over
+		}
+		
+
+	}
+
+	/**
+	 * The main function!
+	 */
+	public static void main(String [] args)
+	{
+		try
+		{
+			BasicAI theAI = new BasicAI();
+			theAI.Setup();
+			while (true)
+				theAI.MoveCycle();
+		}
+		catch (Exception e)
+		{
+			System.out.println("EXCEPTION: " + e.getMessage());
+		}
+	}
+
+}
diff --git a/agents/basic_java/basic_java.hack b/agents/basic_java/basic_java.hack
new file mode 100755
index 0000000000000000000000000000000000000000..f148fbce9a8642ce02154e9836f99daf60db64b9
--- /dev/null
+++ b/agents/basic_java/basic_java.hack
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec java BasicAI.class
diff --git a/agents/basic_java/piece.java b/agents/basic_java/piece.java
new file mode 100644
index 0000000000000000000000000000000000000000..90db2ac2d196f2a3571a03510b475064d6321d87
--- /dev/null
+++ b/agents/basic_java/piece.java
@@ -0,0 +1,81 @@
+/**
+ * Class to represent a Piece
+ * @author Sam Moore
+ * @website http://progcomp.ucc.asn.au
+ */
+
+import java.lang.Exception;
+import java.util.Vector;
+
+class Piece
+{
+	//Normally in the Java Way (TM) you would have to make these private, and add "Getters" and "Setters" and all sorts of crap.
+	// Disclaimer: The author is not responsible for the repercussions of not following the Java Way (TM)
+	public int x; //x coord
+	public int y; //y coord
+	public char rank; //Rank of the piece
+	public String colour; //The colour of the Piece
+	public Vector<int[]> positions; //All positions the piece has been at
+	public boolean beenRevealed; //True if the piece has been revealed in combat
+
+	public static char ranks[] = {'B','1','2','3','4','5','6','7','8','9','s','F', '?', '+'}; //List of all the possible ranks
+	//'?' is an unknown piece, '+' is an obstacle
+
+	/**
+	 * Constructor
+	 * @param c The new colour
+	 * @param r The new rank
+	 * @param xx The new x coord
+	 * @param yy The new y coord
+	 */
+	public Piece(String c, char r, int xx, int yy)
+	{
+		
+		this.colour = c;
+		this.rank = r;
+		this.x = xx;
+		this.y = yy;
+		this.positions = new Vector<int[]>();
+		this.beenRevealed = false;
+		
+		positions.add(new int[2]);
+		positions.elementAt(0)[0] = x;
+		positions.elementAt(0)[1] = y;
+	}
+
+	/**
+ 	 * @returns True if the piece can move, based on its rank
+	 */
+	public boolean Mobile()
+	{
+		return (rank != 'F' && rank != 'B' && rank != '+' && rank != '?');
+	}
+
+	/**
+	 * @returns The value of the piece's rank
+	 */
+	public int ValuedRank()
+	{
+		for (int ii=0; ii < ranks.length; ++ii)
+		{
+			if (ranks[ii] == rank)
+				return (ranks.length - 2 - ii);
+		}
+		return 0;
+	}
+
+	/**
+ 	 * @returns the index in ranks of a rank
+	 * @throws Exception if the rank doesn't exist
+	 */
+	public static int Index(char rank) throws Exception
+	{
+		for (int ii=0; ii < ranks.length; ++ii)
+		{
+			if (ranks[ii] == rank)
+				return ii;
+		}
+		throw new Exception("Piece.Index - No such rank as " + rank);
+		
+	}
+}