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;
20 Piece::TextureManager::~TextureManager()
22 Array<Texture*>::Iterator i(*this);
30 Texture & Piece::TextureManager::operator[](const LUint & at)
32 while (Array<Texture*>::Size() <= at)
35 sprintf(buffer, "images/piece%lu.bmp", Array<Texture*>::Size());
36 Array<Texture*>::Add(new Texture(buffer, false));
39 return *(Array<Texture*>::operator[](at));
41 #endif //BUILD_GRAPHICS
44 * Gets the type of a piece, based off a character token
45 * @param fromToken - character identifying the piece
46 * @returns The type of the piece
48 Piece::Type Piece::GetType(char fromToken)
50 for (int ii=0; ii <= (int)(Piece::BOMB); ++ii)
52 if (tokens[ii] == fromToken)
54 return Type(Piece::NOTHING + ii);
57 return Piece::BOULDER;
61 * Gets the opposite to the indicated colour
63 Piece::Colour Piece::OppositeColour(const Colour & colour)
82 * Construct a new, empty board
83 * @param newWidth - the width of the board
84 * @param newHeight - the height of the board
86 Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL), pieces()
88 board = new Piece**[width];
89 for (int x=0; x < width; ++x)
91 board[x] = new Piece*[height];
92 for (int y=0; y < height; ++y)
102 for (int x=0; x < width; ++x)
104 for (int y=0; y < height; ++y)
111 * Print textual representation of the board to a stream
112 * @param stream - the stream to print information to
113 * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
115 void Board::Print(FILE * stream, const Piece::Colour & reveal)
117 for (int y=0; y < height; ++y)
119 for (int x=0; x < width; ++x)
121 Piece * piece = board[x][y];
124 fprintf(stream, ".");
126 else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
129 fprintf(stream, "%c", Piece::tokens[piece->type]);
135 switch (piece->colour)
139 fprintf(stream, "#");
142 fprintf(stream, "+");
145 fprintf(stream, "$");
150 fprintf(stream, "\n");
156 * Print textual representation of the board to a stream
157 * @param stream - the stream to print information to
158 * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
160 void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal, bool showRevealed)
162 for (int y=0; y < height; ++y)
164 for (int x=0; x < width; ++x)
166 Piece * piece = board[x][y];
169 fprintf(stream, ".");
171 else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
172 || (piece->beenRevealed && showRevealed))
174 switch (piece->colour)
177 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40);
180 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40);
185 fprintf(stream, "%c", Piece::tokens[piece->type]);
190 switch (piece->colour)
193 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41);
197 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44);
200 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47);
203 //Should never see this
204 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43);
208 fprintf(stream, "#");
211 fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0);
213 fprintf(stream, "\n");
219 #ifdef BUILD_GRAPHICS
221 * Draw the board state to graphics
222 * @param reveal - Pieces matching this colour will be revealed. If Piece::BOTH, all pieces will be revealed
223 * @param showRevealed - If true, then all pieces that have taken part in combat will be revealed, regardless of colour.
224 * If false, only pieces matching the colour reveal will be revealed
226 void Board::Draw(const Piece::Colour & reveal, bool showRevealed)
229 if (!Graphics::Initialised())
231 fprintf(stderr, "ERROR - Board::Draw called whilst graphics disabled!!!\n");
236 Graphics::ClearScreen();
237 float scale = (float)(Piece::textures[(int)(Piece::NOTHING)].width()) / (float)(GRID_SIZE);
238 for (int y=0; y < height; ++y)
240 for (int x=0; x < width; ++x)
242 Piece * piece = board[x][y];
245 //Don't display anything
248 else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
249 || (piece->beenRevealed && showRevealed))
253 Piece::textures[(int)(piece->type)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
258 switch (piece->colour)
261 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
264 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
267 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
270 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
277 Graphics::UpdateScreen();
280 #endif //BUILD_GRAPHICS
283 * Adds a piece to the board
284 * @param x - x-coord to place the piece at, starting at zero, must be less than board width
285 * @param y - y-coord to place the piece at, starting at zero, must be less than board height
286 * @param newType - the Type of the piece
287 * @param newColour - the Colour of the piece
288 * @returns true if and only if the piece could be successfully added.
290 bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour)
292 if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL)
295 Piece * piece = new Piece(newType, newColour);
298 pieces.push_back(piece);
303 * Gets a pointer to a piece at a board location
305 * @param x - x-coord of the piece
306 * @param y - y-coord of the piece
307 * @returns pointer to the piece, or NULL if the board location was empty
308 * @throws error if board is null or coords are invalid
310 Piece * Board::GetPiece(int x, int y)
312 assert(board != NULL);
313 assert(x >= 0 && x < width && y >= 0 && y < height);
318 * Moves a piece at a specified position in the specified direction, handles combat if necessary, updates state of the board
319 * @param x - x-coord of the piece
320 * @param y - y-coord of the piece
321 * @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT)
322 * @param colour - Colour which the piece must match for the move to be valid
323 * @returns A MovementResult which indicates the result of the move
325 MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
329 return MovementResult(MovementResult::NO_BOARD);
331 if (!(x >= 0 && x < width && y >= 0 && y < height))
333 return MovementResult(MovementResult::INVALID_POSITION);
335 Piece * target = board[x][y];
338 return MovementResult(MovementResult::NO_SELECTION);
340 if (!(colour == Piece::NONE || target->colour == colour))
342 return MovementResult(MovementResult::NOT_YOUR_UNIT);
344 if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER)
346 return MovementResult(MovementResult::IMMOBILE_UNIT);
349 return MovementResult(MovementResult::INVALID_DIRECTION); //Don't allow moves that don't actually move forward
350 if (multiplier > 1 && target->type != Piece::SCOUT)
352 return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times.
354 int x2 = x; int y2 = y;
356 for (int ii=0; ii < multiplier; ++ii)
373 if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height))
375 return MovementResult(MovementResult::INVALID_DIRECTION);
377 if (ii < multiplier-1 && board[x2][y2] != NULL)
379 return MovementResult(MovementResult::POSITION_FULL);
382 Piece * defender = board[x2][y2];
383 if (defender == NULL)
386 board[x2][y2] = target;
388 else if (defender->colour != target->colour)
390 defender->beenRevealed = true;
391 target->beenRevealed = true;
393 Piece::Type defenderType = defender->type;
394 Piece::Type attackerType = target->type;
396 if (defender->colour == Piece::NONE)
398 return MovementResult(MovementResult::POSITION_FULL);
400 if (defender->type == Piece::FLAG)
402 winner = target->colour;
403 return MovementResult(MovementResult::VICTORY_FLAG);
405 else if (defender->type == Piece::BOMB)
407 if (target->type == Piece::MINER)
409 RemovePiece(defender);
412 board[x2][y2] = target;
413 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
417 //Use this to destroy only the attacking piece, and not the bomb
421 return MovementResult(MovementResult::DIES, attackerType, defenderType);
424 //Use this to destroy both the bomb and the attacking piece
425 RemovePiece(defender);
430 board[x2][y2] = NULL;
431 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
435 else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
437 RemovePiece(defender);
440 board[x2][y2] = target;
441 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
443 else if (target->operator > (*defender))
445 RemovePiece(defender);
448 board[x2][y2] = target;
449 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
451 else if (target->operator==(*defender))// && rand() % 2 == 0)
453 RemovePiece(defender);
458 board[x2][y2] = NULL;
459 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
466 return MovementResult(MovementResult::DIES, attackerType, defenderType);
471 return MovementResult(MovementResult::POSITION_FULL);
473 return MovementResult(MovementResult::OK);
477 * Removes a piece from the board
478 * @param piece The piece to remove
479 * @returns true iff the piece actually existed
481 bool Board::RemovePiece(Piece * piece)
484 for (int x = 0; x < width; ++x)
486 for (int y = 0; y < height; ++y)
488 if (board[x][y] == piece)
496 vector<Piece*>::iterator i = pieces.begin();
497 while (i != pieces.end())
511 * Returns the total value of pieces belonging to colour
512 * @param colour the colour
513 * @returns the total value of pieces belonging to colour.
514 * (Redundant repetition <3)
516 int Board::TotalPieceValue(const Piece::Colour & colour) const
519 for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
521 if ((*i)->colour == colour || colour == Piece::BOTH)
523 result += (*i)->PieceValue();
530 * Returns the total number of mobile pieces belonging to colour
531 * @param colour the colour
532 * @returns the total value of mobile pieces belonging to colour.
533 * (Redundant repetition <3)
535 int Board::MobilePieces(const Piece::Colour & colour) const
538 for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
540 if ((*i)->colour == colour || colour == Piece::BOTH)
542 if ((*i)->type <= Piece::MARSHAL && (*i)->type >= Piece::SPY)