Changed the directory structure.
[progcomp2012.git] / home / progcomp / agents / basic_cpp / basic_cpp.cpp
diff --git a/home/progcomp/agents/basic_cpp/basic_cpp.cpp b/home/progcomp/agents/basic_cpp/basic_cpp.cpp
new file mode 100644 (file)
index 0000000..ab00826
--- /dev/null
@@ -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
+ * @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;
+}

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