2 * "basic_cpp", a sample Stratego AI for the UCC Programming Competition 2012
3 * Implementations of main function, and Helper functions
5 * @author Sam Moore (matches) [SZM]
6 * @website http://matches.ucc.asn.au/stratego
7 * @email progcomp@ucc.asn.au or matches@ucc.asn.au
8 * @git git.ucc.asn.au/progcomp2012.git
11 #include "basic_cpp.h" //Needs class Base_Cpp and the includes in this file
16 * The characters used to represent various pieces
17 * NOTHING, BOULDER, FLAG, SPY, SCOUT, MINER, SERGEANT, LIETENANT, CAPTAIN, MAJOR, COLONEL, GENERAL, MARSHAL, BOMB, UNKNOWN
19 char Piece::tokens[] = {'.','*','F','s','9','8','7','6','5','4','3','2','1','B','?'};
22 * Gets a rank from the character used to represent it
23 * Basic lookup of Piece::tokens
25 Rank Piece::GetRank(char token)
27 for (int ii=0; ii <= 14; ++ii)
29 if (tokens[ii] == token)
36 * IMPLEMENTATION of Helper FOLLOWS
40 * Convert string to direction
42 Direction Helper::StrToDir(const string & dir)
46 else if (dir == "DOWN")
48 else if (dir == "LEFT")
50 else if (dir == "RIGHT")
53 return DIRECTION_ERROR;
59 void Helper::DirToStr(const Direction & dir, std::string & buffer)
76 buffer = "DIRECTION_ERROR";
82 * Move a point in a direction
84 void Helper::MoveInDirection(int & x, int & y, const Direction & dir, int multiplier)
109 int Helper::Tokenise(std::vector<string> & buffer, std::string & str, char split)
112 for (unsigned int x = 0; x < str.size(); ++x)
114 if (str[x] == split && token.size() > 0)
116 buffer.push_back(token);
122 if (token.size() > 0)
123 buffer.push_back(token);
124 return buffer.size();
128 * Convert string to integer
130 int Helper::Integer(std::string & fromStr)
132 stringstream s(fromStr);
139 * Read in a line from stdin
141 void Helper::ReadLine(std::string & buffer)
144 for (char c = cin.get(); c != '\n' && cin.good(); c = cin.get())
151 * IMPLEMENTATION of Board FOLLOWS
155 * Constructer for Board
157 Board::Board(int w, int h) : width(w), height(h), board(NULL)
159 //Construct 2D array of P*'s
160 board = new Piece**[width];
161 for (int x=0; x < width; ++x)
163 board[x] = new Piece*[height];
164 for (int y=0; y < height; ++y)
170 * Destructor for board
174 //Destroy the 2D array of P*'s
175 for (int x=0; x < width; ++x)
177 for (int y=0; y < height; ++y)
184 * Retrieves a piece on the Board
185 * @param x x coordinate
186 * @param y y coordinate
187 * @returns A Piece* for the piece, or NULL if there is no piece at the point given
189 Piece * Board::Get(int x, int y) const
191 if (ValidPosition(x, y))
196 * Sets a piece on the Board
197 * @param x x coordinate
198 * @param y y coordinate
200 * @param returns newPiece if successful, NULL if not
202 Piece * Board::Set(int x, int y, Piece * newPiece)
204 if (!ValidPosition(x, y))
206 board[x][y] = newPiece;
207 assert(Get(x,y) == newPiece);
212 * IMPLEMENTATION of Base_Cpp FOLLOWS
218 BasicAI::BasicAI() : turn(0), board(NULL), units(), enemyUnits(), colour(NONE), colourStr("")
221 cin.rdbuf()->pubsetbuf(NULL, 0);
222 cout.rdbuf()->pubsetbuf(NULL, 0);
237 * @returns true if successful, false on error
239 bool BasicAI::Setup()
245 std::string opponentName(""); //opponentName is unused, just read it
248 int width = 0; int height = 0;
249 cin >> width; cin >> height;
251 while(cin.get() != '\n' && cin.good()); //trim newline
253 board = new Board(width, height);
255 if (colourStr == "RED")
258 cout << "FB8sB479B8\nBB31555583\n6724898974\n967B669999\n";
260 else if (colourStr == "BLUE")
263 cout << "967B669999\n6724898974\nBB31555583\nFB8sB479B8\n";
268 return (board != NULL);
272 * Performs a move, including the saving states bits
273 * @returns true if the game is to continue, false if it is to end
275 bool BasicAI::MoveCycle()
277 //cerr << "BasicAI at MoveCycle()\n";
278 if (!InterpretResult())
286 return InterpretResult();
290 * Interprets the result of a move. Ignores the first move
291 * @returns true if successful, false if there was an error
293 bool BasicAI::InterpretResult()
295 //cerr << "BasicAI at InterpretResult()\n";
298 while (cin.get() != '\n' && cin.good());
303 string resultLine; Helper::ReadLine(resultLine);
304 vector<string> tokens; Helper::Tokenise(tokens, resultLine, ' ');
306 if (tokens.size() <= 0)
308 //cerr << "No tokens!\n";
312 if (tokens[0] == "QUIT")
317 if (tokens[0] == "NO_MOVE")
323 if (tokens.size() < 4)
325 //cerr << "Only got " << tokens.size() << " tokens\n";
330 int x = Helper::Integer(tokens[0]);
331 int y = Helper::Integer(tokens[1]);
335 Direction dir = Helper::StrToDir(tokens[2]);
336 string & outcome = tokens[3];
338 int x2 = x; int y2 = y; Helper::MoveInDirection(x2,y2,dir);
340 Piece * attacker = board->Get(x,y);
341 if (attacker == NULL)
343 //cerr << "No attacker!\n";
346 Piece * defender = board->Get(x2,y2);
349 board->Set(x2,y2, attacker);
350 board->Set(x,y,NULL);
351 attacker->x = x2; attacker->y = y2;
353 else if (outcome == "KILLS")
355 if (defender == NULL)
357 //cerr << "No defender!\n";
361 board->Set(x2,y2, attacker);
362 board->Set(x,y,NULL);
363 attacker->x = x2; attacker->y = y2;
365 attacker->rank = Piece::GetRank(tokens[4][0]);
366 ForgetUnit(defender);
368 else if (outcome == "DIES")
370 if (defender == NULL)
372 //cerr << "No defender!\n";
377 board->Set(x,y,NULL);
378 defender->rank = Piece::GetRank(tokens[5][0]);
379 ForgetUnit(attacker);
383 else if (outcome == "BOTHDIE")
385 board->Set(x,y,NULL);
386 board->Set(x2,y2, NULL);
388 ForgetUnit(attacker);
389 ForgetUnit(defender);
391 else if (outcome == "FLAG")
393 //cerr << "BasicAI - Flag was captured, exit!\n";
396 else if (outcome == "ILLEGAL")
398 //cerr << "BasicAI - Illegal move, exit!\n";
402 //cerr << "BasicAI finished InterpretResult()\n";
407 * Performs a random move
408 * TODO: Overwrite with custom move
409 * @returns true if a move could be made (including NO_MOVE), false on error
411 bool BasicAI::MakeMove()
413 //cerr << "BasicAI at MakeMove()\n";
414 if (units.size() <= 0)
416 //cerr << " No units!\n";
421 int index = rand() % units.size();
422 int startIndex = index;
427 Piece * piece = units[index];
428 if (piece != NULL && piece->Mobile())
430 int dirIndex = rand() % 4;
431 int startDirIndex = dirIndex;
434 int x = piece->x; int y = piece->y;
435 assert(board->Get(x,y) == piece);
436 Helper::MoveInDirection(x,y,(Direction)(dirIndex));
437 if (board->ValidPosition(x,y))
439 Piece * target = board->Get(x,y);
440 if (target == NULL || (target->colour != piece->colour && target->colour != NONE))
443 Helper::DirToStr((Direction)(dirIndex), dirStr);
444 cout << piece->x << " " << piece->y << " " << dirStr << "\n";
449 dirIndex = (dirIndex + 1) % 4;
450 if (dirIndex == startDirIndex)
455 index = (index+1) % (units.size());
456 if (index == startIndex)
467 * On first turn, sets up Board
468 * On subsquent turns, takes no action
469 * @returns true on success, false on error
471 bool BasicAI::ReadBoard()
473 //cerr << "BasicAI at ReadBoard()\n";
474 for (int y = 0; y < board->Height(); ++y)
477 Helper::ReadLine(row);
478 for (unsigned int x = 0; x < row.size(); ++x)
487 board->Set(x,y, new Piece(x,y,Piece::Opposite(colour), UNKNOWN));
488 enemyUnits.push_back(board->Get(x,y));
491 board->Set(x,y, new Piece(x,y,NONE, BOULDER));
494 board->Set(x,y,new Piece(x,y,colour, Piece::GetRank(row[x])));
495 units.push_back(board->Get(x,y));
505 * Removes a piece from memory
506 * @param piece The piece to delete
507 * @returns true if the piece was actually found
509 bool BasicAI::ForgetUnit(Piece * piece)
511 //cerr << "BasicAI at ForgetUnit()\n";
513 vector<Piece*>::iterator i = units.begin();
514 while (i != units.end())
518 i = units.erase(i); result = true;
524 i = enemyUnits.begin();
525 while (i != enemyUnits.end())
529 i = enemyUnits.erase(i); result = true;
545 * @returns zero on success, non-zero on failure
547 int main(int argc, char ** argv)
552 BasicAI * basicAI = new BasicAI();
553 if (basicAI->Setup())
555 while (basicAI->MoveCycle());