Committing results from Preliminary Round 1 (Rounds 1, 2, 3)
[progcomp2012.git] / judge / manager / stratego.cpp
1
2
3 #include "stratego.h"
4
5 using namespace std;
6
7 /**
8  * Static variables
9  */
10
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};
14
15
16
17 #ifdef BUILD_GRAPHICS
18 Piece::TextureManager Piece::textures;
19
20 Piece::TextureManager::~TextureManager()
21 {
22         Array<Texture*>::Iterator i(*this);
23         while (i.Good())
24         {
25                 delete (*i);
26                 ++i;
27         }
28 }
29
30 Texture & Piece::TextureManager::operator[](const LUint & at)
31 {
32         while (Array<Texture*>::Size() <= at)
33         {
34                 char buffer[BUFSIZ];
35                 sprintf(buffer, "images/piece%lu.bmp", Array<Texture*>::Size());
36                 Array<Texture*>::Add(new Texture(buffer, false));
37                 
38         }
39         return *(Array<Texture*>::operator[](at));
40 }
41 #endif //BUILD_GRAPHICS
42
43 /**
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
47  */
48 Piece::Type Piece::GetType(char fromToken)
49 {
50         for (int ii=0; ii <= (int)(Piece::BOMB); ++ii)
51         {
52                 if (tokens[ii] == fromToken)
53                 {
54                         return Type(Piece::NOTHING + ii);
55                 }
56         }
57         return Piece::BOULDER;
58 }
59
60 /**
61  * Gets the opposite to the indicated colour
62  */
63 Piece::Colour Piece::OppositeColour(const Colour & colour)
64 {
65         switch (colour)
66         {
67                 case Piece::RED:
68                         return Piece::BLUE;
69                         break;
70                 case Piece::BLUE:
71                         return Piece::RED;
72                         break;
73                 case Piece::BOTH:
74                         return Piece::BOTH;
75                         break;
76                 case Piece::NONE:
77                         return Piece::NONE;
78         }
79 }
80
81 /**
82  * Construct a new, empty board
83  * @param newWidth - the width of the board
84  * @param newHeight - the height of the board
85  */
86 Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL), pieces()
87 {
88         board = new Piece**[width];
89         for (int x=0; x < width; ++x)
90         {
91                 board[x] = new Piece*[height];
92                 for (int y=0; y < height; ++y)
93                         board[x][y] = NULL;
94         }
95 }
96
97 /**
98  * Cleanup a board
99  */
100 Board::~Board()
101 {
102         for (int x=0; x < width; ++x)
103         {
104                 for (int y=0; y < height; ++y)
105                         delete board[x][y];
106                 delete [] board[x];
107         }
108 }
109
110 /**
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 '#'
114  */
115 void Board::Print(FILE * stream, const Piece::Colour & reveal)
116 {
117         for (int y=0; y < height; ++y)
118         {
119                 for (int x=0; x < width; ++x)
120                 {
121                         Piece * piece = board[x][y];
122                         if (piece == NULL)
123                         {
124                                 fprintf(stream, ".");
125                         }
126                         else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
127                         {
128
129                                 fprintf(stream, "%c", Piece::tokens[piece->type]);
130
131
132                         }
133                         else
134                         {
135                                 switch (piece->colour)
136                                 {
137                                         case Piece::RED:
138                                         case Piece::BLUE:
139                                                 fprintf(stream, "#");
140                                                 break;
141                                         case Piece::NONE:
142                                                 fprintf(stream, "+");
143                                                 break;
144                                         case Piece::BOTH:
145                                                 fprintf(stream, "$");
146                                                 break;
147                                 }
148                         }
149                 }
150                 fprintf(stream, "\n");
151         }
152         
153 }
154
155 /**
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 '#'
159  */
160 void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal, bool showRevealed)
161 {
162         for (int y=0; y < height; ++y)
163         {
164                 for (int x=0; x < width; ++x)
165                 {
166                         Piece * piece = board[x][y];
167                         if (piece == NULL)
168                         {
169                                 fprintf(stream, ".");
170                         }
171                         else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
172                                         || (piece->beenRevealed && showRevealed))
173                         {
174                                 switch (piece->colour)  
175                                 {
176                                         case Piece::RED:
177                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40);
178                                                 break;
179                                         case Piece::BLUE:
180                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40);
181                                                 break;
182                                         default:
183                                                 break;
184                                 }
185                                 fprintf(stream, "%c", Piece::tokens[piece->type]);
186
187                         }
188                         else
189                         {
190                                 switch (piece->colour)
191                                 {
192                                         case Piece::RED:
193                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41);
194
195                                                 break;
196                                         case Piece::BLUE:
197                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44);
198                                                 break;
199                                         case Piece::NONE:
200                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47);
201                                                 break;
202                                         case Piece::BOTH:
203                                                 //Should never see this
204                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43);
205                                                 break;
206
207                                 }       
208                                 fprintf(stream, "#");
209                                 
210                         }
211                         fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0);
212                 }
213                 fprintf(stream, "\n");
214         }
215         
216 }
217
218
219 #ifdef BUILD_GRAPHICS
220 /**
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
225  */
226 void Board::Draw(const Piece::Colour & reveal, bool showRevealed)
227 {
228
229         if (!Graphics::Initialised())
230         {
231                 fprintf(stderr, "ERROR - Board::Draw called whilst graphics disabled!!!\n");
232                 exit(EXIT_FAILURE);
233                 
234         }
235
236         Graphics::ClearScreen();
237         float scale = (float)(Piece::textures[(int)(Piece::NOTHING)].width()) / (float)(GRID_SIZE);
238         for (int y=0; y < height; ++y)
239         {
240                 for (int x=0; x < width; ++x)
241                 {
242                         Piece * piece = board[x][y];
243                         if (piece == NULL)
244                         {
245                                 //Don't display anything
246
247                         }
248                         else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
249                                         || (piece->beenRevealed && showRevealed))
250                         {
251                                 //Display the piece
252                                 
253                                 Piece::textures[(int)(piece->type)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
254                                 
255                         }
256                         else
257                         {
258                                 switch (piece->colour)
259                                 {
260                                         case Piece::RED:
261                                                 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
262                                                 break;
263                                         case Piece::BLUE:
264                                                 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
265                                                 break;
266                                         case Piece::NONE:
267                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
268                                                 break;
269                                         case Piece::BOTH:
270                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*GRID_SIZE*scale,y*GRID_SIZE*scale,0,scale, Piece::GetGraphicsColour(piece->colour));
271                                                 break;
272                                 }
273                         }
274                 }
275                 
276         }
277         Graphics::UpdateScreen();
278         
279 }
280 #endif //BUILD_GRAPHICS
281
282 /**
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.
289  */
290 bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour)
291 {
292         if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL)
293                 return false;
294
295         Piece * piece = new Piece(newType, newColour);
296         board[x][y] = piece;
297
298         pieces.push_back(piece);
299         return true;
300 }
301
302 /**
303  * Gets a pointer to a piece at a board location
304  * UNUSED
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
309  */
310 Piece * Board::GetPiece(int x, int y)
311 {
312         assert(board != NULL);
313         assert(x >= 0 && x < width && y >= 0 && y < height);
314         return board[x][y];
315 }
316
317 /**
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
324  */
325 MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
326 {
327         if (board == NULL) 
328         {
329                 return MovementResult(MovementResult::NO_BOARD);
330         }
331         if (!(x >= 0 && x < width && y >= 0 && y < height)) 
332         {
333                 return MovementResult(MovementResult::INVALID_POSITION);
334         }
335         Piece * target = board[x][y];
336         if (target == NULL) 
337         {
338                 return MovementResult(MovementResult::NO_SELECTION);
339         }
340         if (!(colour == Piece::NONE || target->colour == colour)) 
341         {
342                 return MovementResult(MovementResult::NOT_YOUR_UNIT);
343         }
344         if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER) 
345         {
346                 return MovementResult(MovementResult::IMMOBILE_UNIT);
347         }
348         if (multiplier < 1)
349                 return MovementResult(MovementResult::INVALID_DIRECTION); //Don't allow moves that don't actually move forward
350         if (multiplier > 1 && target->type != Piece::SCOUT)
351         {
352                 return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times.
353         }
354         int x2 = x; int y2 = y;
355
356         for (int ii=0; ii < multiplier; ++ii)
357         {
358                 switch (direction)
359                 {
360                         case UP:
361                                 --y2;
362                                 break;
363                         case DOWN:
364                                 ++y2;
365                                 break;
366                         case LEFT:
367                                 --x2;
368                                 break;
369                         case RIGHT:
370                                 ++x2;
371                                 break;
372                 }
373                 if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height)) 
374                 {
375                         return MovementResult(MovementResult::INVALID_DIRECTION);
376                 }
377                 if (ii < multiplier-1 && board[x2][y2] != NULL)
378                 {
379                         return MovementResult(MovementResult::POSITION_FULL);
380                 }
381         }
382         Piece * defender = board[x2][y2];
383         if (defender == NULL)
384         {
385                 board[x][y] = NULL;
386                 board[x2][y2] = target;
387         }
388         else if (defender->colour != target->colour)
389         {
390                 defender->beenRevealed = true;
391                 target->beenRevealed = true;
392
393                 Piece::Type defenderType = defender->type;
394                 Piece::Type attackerType = target->type;
395
396                 if (defender->colour == Piece::NONE) 
397                 {
398                         return MovementResult(MovementResult::POSITION_FULL);
399                 }
400                 if (defender->type == Piece::FLAG)
401                 {
402                         winner = target->colour;
403                         return MovementResult(MovementResult::VICTORY_FLAG);
404                 }
405                 else if (defender->type == Piece::BOMB)
406                 {
407                         if (target->type == Piece::MINER)
408                         {
409                                 RemovePiece(defender);
410                                 delete defender;
411                                 board[x][y] = NULL;
412                                 board[x2][y2] = target;
413                                 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
414                         }
415                         else
416                         {
417                                 //Use this to destroy only the attacking piece, and not the bomb
418                                 RemovePiece(target);
419                                 delete target;
420                                 board[x][y] = NULL;
421                                 return MovementResult(MovementResult::DIES, attackerType, defenderType);
422
423                                 /*
424                                 //Use this to destroy both the bomb and the attacking piece
425                                 RemovePiece(defender);
426                                 RemovePiece(target);
427                                 delete defender;
428                                 delete target;
429                                 board[x][y] = NULL;
430                                 board[x2][y2] = NULL;
431                                 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
432                                 */
433                         }
434                 }
435                 else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
436                 {
437                         RemovePiece(defender);
438                         delete defender;
439                         board[x][y] = NULL;
440                         board[x2][y2] = target;
441                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
442                 }
443                 else if (target->operator > (*defender))
444                 {
445                         RemovePiece(defender);
446                         delete defender;
447                         board[x][y] = NULL;
448                         board[x2][y2] = target;
449                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
450                 }
451                 else if (target->operator==(*defender))// && rand() % 2 == 0)
452                 {
453                         RemovePiece(defender);
454                         RemovePiece(target);
455                         delete defender;
456                         delete target;
457                         board[x][y] = NULL;
458                         board[x2][y2] = NULL;   
459                         return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
460                 }
461                 else
462                 {
463                         RemovePiece(target);
464                         delete target;
465                         board[x][y] = NULL;
466                         return MovementResult(MovementResult::DIES, attackerType, defenderType);
467                 }
468         }
469         else
470         {
471                 return MovementResult(MovementResult::POSITION_FULL);
472         }
473         return MovementResult(MovementResult::OK);
474 }       
475
476 /**
477  * Removes a piece from the board
478  * @param piece The piece to remove
479  * @returns true iff the piece actually existed
480  */
481 bool Board::RemovePiece(Piece * piece)
482 {
483         bool result = false;
484         for (int x = 0; x < width; ++x)
485         {
486                 for (int y = 0; y < height; ++y)        
487                 {
488                         if (board[x][y] == piece)
489                         {
490                                 result = true;
491                                 board[x][y] = NULL;
492                         }
493                 }
494         }
495
496         vector<Piece*>::iterator i = pieces.begin();
497         while (i != pieces.end())
498         {
499                 if ((*i) == piece)
500                 {
501                         i = pieces.erase(i);
502                         result = true;
503                         continue;
504                 }
505                 ++i;
506         }
507         return result;
508 }
509
510 /**
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)
515  */
516 int Board::TotalPieceValue(const Piece::Colour & colour) const
517 {
518         int result = 0;
519         for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
520         {
521                 if ((*i)->colour == colour || colour == Piece::BOTH)
522                 {
523                         result += (*i)->PieceValue();
524                 }
525         }
526         return result;
527 }
528
529 /**
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)
534  */
535 int Board::MobilePieces(const Piece::Colour & colour) const
536 {
537         int result = 0;
538         for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
539         {
540                 if ((*i)->colour == colour || colour == Piece::BOTH)
541                 {
542                         if ((*i)->type <= Piece::MARSHAL && (*i)->type >= Piece::SPY)
543                                 result++;
544                 }
545         }
546         return result;
547 }
548
549

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