11 //nothing, boulder, flag, spy, scout, miner, sergeant, lietenant, captain, major, colonel, general, marshal, bomb, error
12 char Piece::tokens[] = {'.','*','F','s','9','8','7','6','5','4','3','2','1','B','?'};
13 int Piece::maxUnits[] = {0,0,1,1,8,5,4,4,4,3,2,1,1,6,0};
18 Piece::TextureManager Piece::textures;
23 Piece::TextureManager::~TextureManager()
25 Array<Texture*>::Iterator i(*this);
33 Texture & Piece::TextureManager::operator[](const LUint & at)
35 while (Array<Texture*>::Size() <= at)
38 sprintf(buffer, "images/piece%lu.bmp", Array<Texture*>::Size());
39 Array<Texture*>::Add(new Texture(buffer, false));
42 return *(Array<Texture*>::operator[](at));
47 * Gets the type of a piece, based off a character token
48 * @param fromToken - character identifying the piece
49 * @returns The type of the piece
51 Piece::Type Piece::GetType(char fromToken)
53 for (int ii=0; ii <= (int)(Piece::BOMB); ++ii)
55 if (tokens[ii] == fromToken)
57 return Type(Piece::NOTHING + ii);
60 return Piece::BOULDER;
64 * Construct a new, empty board
65 * @param newWidth - the width of the board
66 * @param newHeight - the height of the board
68 Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL), pieces()
70 board = new Piece**[width];
71 for (int x=0; x < width; ++x)
73 board[x] = new Piece*[height];
74 for (int y=0; y < height; ++y)
84 for (int x=0; x < width; ++x)
86 for (int y=0; y < height; ++y)
93 * Print textual representation of the board to a stream
94 * @param stream - the stream to print information to
95 * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
97 void Board::Print(FILE * stream, const Piece::Colour & reveal)
99 for (int y=0; y < height; ++y)
101 for (int x=0; x < width; ++x)
103 Piece * piece = board[x][y];
106 fprintf(stream, ".");
108 else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
111 fprintf(stream, "%c", Piece::tokens[piece->type]);
117 switch (piece->colour)
121 fprintf(stream, "#");
124 fprintf(stream, "+");
127 fprintf(stream, "$");
132 fprintf(stream, "\n");
138 * Print textual representation of the board to a stream
139 * @param stream - the stream to print information to
140 * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
142 void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal)
144 for (int y=0; y < height; ++y)
146 for (int x=0; x < width; ++x)
148 Piece * piece = board[x][y];
151 fprintf(stream, ".");
153 else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
155 switch (piece->colour)
158 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40);
161 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40);
166 fprintf(stream, "%c", Piece::tokens[piece->type]);
171 switch (piece->colour)
174 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41);
178 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44);
181 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47);
184 //Should never see this
185 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43);
189 fprintf(stream, "#");
192 fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0);
194 fprintf(stream, "\n");
202 * Draw the board state to graphics
203 * @param reveal - Pieces matching this colour will be revealed. All others will be shown as blank coloured squares.
205 void Board::Draw(const Piece::Colour & reveal, bool showRevealed)
207 if (!Graphics::Initialised())
209 fprintf(stderr, "ERROR - Board::Draw called whilst graphics disabled!!!\n");
214 Graphics::ClearScreen();
216 for (int y=0; y < height; ++y)
218 for (int x=0; x < width; ++x)
220 Piece * piece = board[x][y];
223 //Don't display anything
226 else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
227 || (piece->beenRevealed && showRevealed))
230 Piece::textures[(int)(piece->type)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
235 switch (piece->colour)
238 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
241 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
244 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
247 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
254 Graphics::UpdateScreen();
259 * Adds a piece to the board
260 * @param x - x-coord to place the piece at, starting at zero, must be less than board width
261 * @param y - y-coord to place the piece at, starting at zero, must be less than board height
262 * @param newType - the Type of the piece
263 * @param newColour - the Colour of the piece
264 * @returns true if and only if the piece could be successfully added.
266 bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour)
268 if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL)
271 Piece * piece = new Piece(newType, newColour);
274 pieces.push_back(piece);
279 * Gets a pointer to a piece at a board location
281 * @param x - x-coord of the piece
282 * @param y - y-coord of the piece
283 * @returns pointer to the piece, or NULL if the board location was empty
284 * @throws error if board is null or coords are invalid
286 Piece * Board::GetPiece(int x, int y)
288 assert(board != NULL);
289 assert(x >= 0 && x < width && y >= 0 && y < height);
294 * Moves a piece at a specified position in the specified direction, handles combat if necessary
295 * @param x - x-coord of the piece
296 * @param y - y-coord of the piece
297 * @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT)
298 * @param colour - Colour which the piece must match for the move to be valid
299 * @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
301 MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
305 return MovementResult(MovementResult::NO_BOARD);
307 if (!(x >= 0 && x < width && y >= 0 && y < height))
309 return MovementResult(MovementResult::INVALID_POSITION);
311 Piece * target = board[x][y];
314 return MovementResult(MovementResult::NO_SELECTION);
316 if (!(colour == Piece::NONE || target->colour == colour))
318 return MovementResult(MovementResult::NOT_YOUR_UNIT);
320 if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER)
322 return MovementResult(MovementResult::IMMOBILE_UNIT);
324 if (multiplier > 1 && target->type != Piece::SCOUT)
326 return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times.
328 int x2 = x; int y2 = y;
330 for (int ii=0; ii < multiplier; ++ii)
347 if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height))
349 return MovementResult(MovementResult::INVALID_DIRECTION);
351 if (ii < multiplier-1 && board[x2][y2] != NULL)
353 return MovementResult(MovementResult::POSITION_FULL);
356 Piece * defender = board[x2][y2];
357 if (defender == NULL)
360 board[x2][y2] = target;
362 else if (defender->colour != target->colour)
364 defender->beenRevealed = true;
365 target->beenRevealed = true;
367 Piece::Type defenderType = defender->type;
368 Piece::Type attackerType = target->type;
370 if (defender->colour == Piece::NONE)
372 return MovementResult(MovementResult::POSITION_FULL);
374 if (defender->type == Piece::FLAG)
376 winner = target->colour;
377 return MovementResult(MovementResult::VICTORY);
379 else if (defender->type == Piece::BOMB)
381 if (target->type == Piece::MINER)
383 RemovePiece(defender);
386 board[x2][y2] = target;
387 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
391 RemovePiece(defender);
396 board[x2][y2] = NULL;
397 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
400 else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
402 RemovePiece(defender);
405 board[x2][y2] = target;
406 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
408 else if (target->operator > (*defender))
410 RemovePiece(defender);
413 board[x2][y2] = target;
414 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
416 else if (target->operator==(*defender) && rand() % 2 == 0)
418 RemovePiece(defender);
421 board[x2][y2] = target;
422 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
429 return MovementResult(MovementResult::DIES, attackerType, defenderType);
434 return MovementResult(MovementResult::POSITION_FULL);
436 return MovementResult(MovementResult::OK);
440 * Removes a piece from the board
441 * @param piece The piece to remove
442 * @returns true iff the piece actually existed
444 bool Board::RemovePiece(Piece * piece)
447 for (int x = 0; x < width; ++x)
449 for (int y = 0; y < height; ++y)
451 if (board[x][y] == piece)
459 vector<Piece*>::iterator i = pieces.begin();
460 while (i != pieces.end())
474 * Returns the total value of pieces belonging to colour
475 * @param colour the colour
476 * @returns the total value of pieces belonging to colour.
477 * (Redundant repetition <3)
479 int Board::TotalPieceValue(const Piece::Colour & colour) const
482 for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
484 if ((*i)->colour == colour || colour == Piece::BOTH)
486 result += (*i)->PieceValue();
493 * Returns the total number of mobile pieces belonging to colour
494 * @param colour the colour
495 * @returns the total value of mobile pieces belonging to colour.
496 * (Redundant repetition <3)
498 int Board::MobilePieces(const Piece::Colour & colour) const
501 for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
503 if ((*i)->colour == colour || colour == Piece::BOTH)
505 if ((*i)->type <= Piece::MARSHAL && (*i)->type >= Piece::SPY)