X-Git-Url: https://git.ucc.asn.au/?p=progcomp2012.git;a=blobdiff_plain;f=progcomp%2Fjudge%2Fmanager%2Fstratego.cpp;fp=progcomp%2Fjudge%2Fmanager%2Fstratego.cpp;h=f2df0ffc29719cda5a4e91b4e129580e4b2b5237;hp=0000000000000000000000000000000000000000;hb=88fc5a96c424e9a451b98f3b680bc1980345320d;hpb=e3b15cd5dea739f7523920d83bda592db95a7b93 diff --git a/progcomp/judge/manager/stratego.cpp b/progcomp/judge/manager/stratego.cpp new file mode 100644 index 0000000..f2df0ff --- /dev/null +++ b/progcomp/judge/manager/stratego.cpp @@ -0,0 +1,512 @@ + + +#include "stratego.h" + +using namespace std; + +/** + * Static variables + */ + +//nothing, boulder, flag, spy, scout, miner, sergeant, lietenant, captain, major, colonel, general, marshal, bomb, error +char Piece::tokens[] = {'.','*','F','s','9','8','7','6','5','4','3','2','1','B','?'}; +int Piece::maxUnits[] = {0,0,1,1,8,5,4,4,4,3,2,1,1,6,0}; + + + + +Piece::TextureManager Piece::textures; + + + + +Piece::TextureManager::~TextureManager() +{ + Array::Iterator i(*this); + while (i.Good()) + { + delete (*i); + ++i; + } +} + +Texture & Piece::TextureManager::operator[](const LUint & at) +{ + while (Array::Size() <= at) + { + char buffer[BUFSIZ]; + sprintf(buffer, "images/piece%lu.bmp", Array::Size()); + Array::Add(new Texture(buffer, false)); + + } + return *(Array::operator[](at)); +} + + +/** + * Gets the type of a piece, based off a character token + * @param fromToken - character identifying the piece + * @returns The type of the piece + */ +Piece::Type Piece::GetType(char fromToken) +{ + for (int ii=0; ii <= (int)(Piece::BOMB); ++ii) + { + if (tokens[ii] == fromToken) + { + return Type(Piece::NOTHING + ii); + } + } + return Piece::BOULDER; +} + +/** + * Construct a new, empty board + * @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), pieces() +{ + 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; + } +} + +/** + * Cleanup a board + */ +Board::~Board() +{ + for (int x=0; x < width; ++x) + { + for (int y=0; y < height; ++y) + delete board[x][y]; + delete [] board[x]; + } +} + +/** + * Print textual representation of the board to a stream + * @param stream - the stream to print information to + * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' + */ +void Board::Print(FILE * stream, const Piece::Colour & reveal) +{ + for (int y=0; y < height; ++y) + { + for (int x=0; x < width; ++x) + { + Piece * piece = board[x][y]; + if (piece == NULL) + { + fprintf(stream, "."); + } + else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH)) + { + + fprintf(stream, "%c", Piece::tokens[piece->type]); + + + } + else + { + switch (piece->colour) + { + case Piece::RED: + case Piece::BLUE: + fprintf(stream, "#"); + break; + case Piece::NONE: + fprintf(stream, "+"); + break; + case Piece::BOTH: + fprintf(stream, "$"); + break; + } + } + } + fprintf(stream, "\n"); + } + +} + +/** + * Print textual representation of the board to a stream + * @param stream - the stream to print information to + * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' + */ +void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal) +{ + for (int y=0; y < height; ++y) + { + for (int x=0; x < width; ++x) + { + Piece * piece = board[x][y]; + if (piece == NULL) + { + fprintf(stream, "."); + } + else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH)) + { + switch (piece->colour) + { + case Piece::RED: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40); + break; + case Piece::BLUE: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40); + break; + default: + break; + } + fprintf(stream, "%c", Piece::tokens[piece->type]); + + } + else + { + switch (piece->colour) + { + case Piece::RED: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41); + + break; + case Piece::BLUE: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44); + break; + case Piece::NONE: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47); + break; + case Piece::BOTH: + //Should never see this + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43); + break; + + } + fprintf(stream, "#"); + + } + fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0); + } + fprintf(stream, "\n"); + } + +} + + + +/** + * Draw the board state to graphics + * @param reveal - Pieces matching this colour will be revealed. All others will be shown as blank coloured squares. + */ +void Board::Draw(const Piece::Colour & reveal, bool showRevealed) +{ + if (!Graphics::Initialised()) + { + fprintf(stderr, "ERROR - Board::Draw called whilst graphics disabled!!!\n"); + exit(EXIT_FAILURE); + + } + + Graphics::ClearScreen(); + + for (int y=0; y < height; ++y) + { + for (int x=0; x < width; ++x) + { + Piece * piece = board[x][y]; + if (piece == NULL) + { + //Don't display anything + + } + else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH)) + || (piece->beenRevealed && showRevealed)) + { + //Display the piece + Piece::textures[(int)(piece->type)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour)); + + } + else + { + switch (piece->colour) + { + case Piece::RED: + Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour)); + break; + case Piece::BLUE: + Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour)); + break; + case Piece::NONE: + Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour)); + break; + case Piece::BOTH: + Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour)); + break; + } + } + } + + } + Graphics::UpdateScreen(); + +} + +/** + * Adds a piece to the board + * @param x - x-coord to place the piece at, starting at zero, must be less than board width + * @param y - y-coord to place the piece at, starting at zero, must be less than board height + * @param newType - the Type of the piece + * @param newColour - the Colour of the piece + * @returns true if and only if the piece could be successfully added. + */ +bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour) +{ + if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL) + return false; + + Piece * piece = new Piece(newType, newColour); + board[x][y] = piece; + + pieces.push_back(piece); + return true; +} + +/** + * Gets a pointer to a piece at a board location + * UNUSED + * @param x - x-coord of the piece + * @param y - y-coord of the piece + * @returns pointer to the piece, or NULL if the board location was empty + * @throws error if board is null or coords are invalid + */ +Piece * Board::GetPiece(int x, int y) +{ + assert(board != NULL); + assert(x >= 0 && x < width && y >= 0 && y < height); + return board[x][y]; +} + +/** + * Moves a piece at a specified position in the specified direction, handles combat if necessary + * @param x - x-coord of the piece + * @param y - y-coord of the piece + * @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT) + * @param colour - Colour which the piece must match for the move to be valid + * @returns A MovementResult which indicates the result of the move - OK is good, VICTORY means that a flag was captured, anything else is an error + */ +MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour) +{ + if (board == NULL) + { + return MovementResult(MovementResult::NO_BOARD); + } + if (!(x >= 0 && x < width && y >= 0 && y < height)) + { + return MovementResult(MovementResult::INVALID_POSITION); + } + Piece * target = board[x][y]; + if (target == NULL) + { + return MovementResult(MovementResult::NO_SELECTION); + } + if (!(colour == Piece::NONE || target->colour == colour)) + { + return MovementResult(MovementResult::NOT_YOUR_UNIT); + } + if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER) + { + return MovementResult(MovementResult::IMMOBILE_UNIT); + } + if (multiplier > 1 && target->type != Piece::SCOUT) + { + return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times. + } + int x2 = x; int y2 = y; + + for (int ii=0; ii < multiplier; ++ii) + { + switch (direction) + { + case UP: + --y2; + break; + case DOWN: + ++y2; + break; + case LEFT: + --x2; + break; + case RIGHT: + ++x2; + break; + } + if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height)) + { + return MovementResult(MovementResult::INVALID_DIRECTION); + } + if (ii < multiplier-1 && board[x2][y2] != NULL) + { + return MovementResult(MovementResult::POSITION_FULL); + } + } + Piece * defender = board[x2][y2]; + if (defender == NULL) + { + board[x][y] = NULL; + board[x2][y2] = target; + } + else if (defender->colour != target->colour) + { + defender->beenRevealed = true; + target->beenRevealed = true; + + Piece::Type defenderType = defender->type; + Piece::Type attackerType = target->type; + + if (defender->colour == Piece::NONE) + { + return MovementResult(MovementResult::POSITION_FULL); + } + if (defender->type == Piece::FLAG) + { + winner = target->colour; + return MovementResult(MovementResult::VICTORY); + } + else if (defender->type == Piece::BOMB) + { + if (target->type == Piece::MINER) + { + RemovePiece(defender); + delete defender; + board[x][y] = NULL; + board[x2][y2] = target; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); + } + else + { + RemovePiece(defender); + RemovePiece(target); + delete defender; + delete target; + board[x][y] = NULL; + board[x2][y2] = NULL; + return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType); + } + } + else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY) + { + RemovePiece(defender); + delete defender; + board[x][y] = NULL; + board[x2][y2] = target; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); + } + else if (target->operator > (*defender)) + { + RemovePiece(defender); + delete defender; + board[x][y] = NULL; + board[x2][y2] = target; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); + } + else if (target->operator==(*defender) && rand() % 2 == 0) + { + RemovePiece(defender); + delete defender; + board[x][y] = NULL; + board[x2][y2] = target; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); + } + else + { + RemovePiece(target); + delete target; + board[x][y] = NULL; + return MovementResult(MovementResult::DIES, attackerType, defenderType); + } + } + else + { + return MovementResult(MovementResult::POSITION_FULL); + } + 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::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::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::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; +} + +