5acfaa38250b07152732069bda41c636894eb230
[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  * Construct a new, empty board
62  * @param newWidth - the width of the board
63  * @param newHeight - the height of the board
64  */
65 Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL), pieces()
66 {
67         board = new Piece**[width];
68         for (int x=0; x < width; ++x)
69         {
70                 board[x] = new Piece*[height];
71                 for (int y=0; y < height; ++y)
72                         board[x][y] = NULL;
73         }
74 }
75
76 /**
77  * Cleanup a board
78  */
79 Board::~Board()
80 {
81         for (int x=0; x < width; ++x)
82         {
83                 for (int y=0; y < height; ++y)
84                         delete board[x][y];
85                 delete [] board[x];
86         }
87 }
88
89 /**
90  * Print textual representation of the board to a stream
91  * @param stream - the stream to print information to
92  * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
93  */
94 void Board::Print(FILE * stream, const Piece::Colour & reveal)
95 {
96         for (int y=0; y < height; ++y)
97         {
98                 for (int x=0; x < width; ++x)
99                 {
100                         Piece * piece = board[x][y];
101                         if (piece == NULL)
102                         {
103                                 fprintf(stream, ".");
104                         }
105                         else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
106                         {
107
108                                 fprintf(stream, "%c", Piece::tokens[piece->type]);
109
110
111                         }
112                         else
113                         {
114                                 switch (piece->colour)
115                                 {
116                                         case Piece::RED:
117                                         case Piece::BLUE:
118                                                 fprintf(stream, "#");
119                                                 break;
120                                         case Piece::NONE:
121                                                 fprintf(stream, "+");
122                                                 break;
123                                         case Piece::BOTH:
124                                                 fprintf(stream, "$");
125                                                 break;
126                                 }
127                         }
128                 }
129                 fprintf(stream, "\n");
130         }
131         
132 }
133
134 /**
135  * Print textual representation of the board to a stream
136  * @param stream - the stream to print information to
137  * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#'
138  */
139 void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal)
140 {
141         for (int y=0; y < height; ++y)
142         {
143                 for (int x=0; x < width; ++x)
144                 {
145                         Piece * piece = board[x][y];
146                         if (piece == NULL)
147                         {
148                                 fprintf(stream, ".");
149                         }
150                         else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
151                         {
152                                 switch (piece->colour)  
153                                 {
154                                         case Piece::RED:
155                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40);
156                                                 break;
157                                         case Piece::BLUE:
158                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40);
159                                                 break;
160                                         default:
161                                                 break;
162                                 }
163                                 fprintf(stream, "%c", Piece::tokens[piece->type]);
164
165                         }
166                         else
167                         {
168                                 switch (piece->colour)
169                                 {
170                                         case Piece::RED:
171                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41);
172
173                                                 break;
174                                         case Piece::BLUE:
175                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44);
176                                                 break;
177                                         case Piece::NONE:
178                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47);
179                                                 break;
180                                         case Piece::BOTH:
181                                                 //Should never see this
182                                                 fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43);
183                                                 break;
184
185                                 }       
186                                 fprintf(stream, "#");
187                                 
188                         }
189                         fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0);
190                 }
191                 fprintf(stream, "\n");
192         }
193         
194 }
195
196
197 #ifdef BUILD_GRAPHICS
198 /**
199  * Draw the board state to graphics
200  * @param reveal - Pieces matching this colour will be revealed. If Piece::BOTH, all pieces will be revealed
201  * @param showRevealed - If true, then all pieces that have taken part in combat will be revealed, regardless of colour.
202  *                       If false, only pieces matching the colour reveal will be revealed
203  */
204 void Board::Draw(const Piece::Colour & reveal, bool showRevealed)
205 {
206
207         if (!Graphics::Initialised())
208         {
209                 fprintf(stderr, "ERROR - Board::Draw called whilst graphics disabled!!!\n");
210                 exit(EXIT_FAILURE);
211                 
212         }
213
214         Graphics::ClearScreen();
215         
216         for (int y=0; y < height; ++y)
217         {
218                 for (int x=0; x < width; ++x)
219                 {
220                         Piece * piece = board[x][y];
221                         if (piece == NULL)
222                         {
223                                 //Don't display anything
224
225                         }
226                         else if ((piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
227                                         || (piece->beenRevealed && showRevealed))
228                         {
229                                 //Display the piece
230                                 Piece::textures[(int)(piece->type)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
231                                 
232                         }
233                         else
234                         {
235                                 switch (piece->colour)
236                                 {
237                                         case Piece::RED:
238                                                 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
239                                                 break;
240                                         case Piece::BLUE:
241                                                 Piece::textures[(int)(Piece::NOTHING)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
242                                                 break;
243                                         case Piece::NONE:
244                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
245                                                 break;
246                                         case Piece::BOTH:
247                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
248                                                 break;
249                                 }
250                         }
251                 }
252                 
253         }
254         Graphics::UpdateScreen();
255         
256 }
257 #endif //BUILD_GRAPHICS
258
259 /**
260  * Adds a piece to the board
261  * @param x - x-coord to place the piece at, starting at zero, must be less than board width
262  * @param y - y-coord to place the piece at, starting at zero, must be less than board height
263  * @param newType - the Type of the piece
264  * @param newColour - the Colour of the piece
265  * @returns true if and only if the piece could be successfully added.
266  */
267 bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour)
268 {
269         if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL)
270                 return false;
271
272         Piece * piece = new Piece(newType, newColour);
273         board[x][y] = piece;
274
275         pieces.push_back(piece);
276         return true;
277 }
278
279 /**
280  * Gets a pointer to a piece at a board location
281  * UNUSED
282  * @param x - x-coord of the piece
283  * @param y - y-coord of the piece
284  * @returns pointer to the piece, or NULL if the board location was empty
285  * @throws error if board is null or coords are invalid
286  */
287 Piece * Board::GetPiece(int x, int y)
288 {
289         assert(board != NULL);
290         assert(x >= 0 && x < width && y >= 0 && y < height);
291         return board[x][y];
292 }
293
294 /**
295  * Moves a piece at a specified position in the specified direction, handles combat if necessary, updates state of the board
296  * @param x - x-coord of the piece
297  * @param y - y-coord of the piece
298  * @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT)
299  * @param colour - Colour which the piece must match for the move to be valid
300  * @returns A MovementResult which indicates the result of the move
301  */
302 MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
303 {
304         if (board == NULL) 
305         {
306                 return MovementResult(MovementResult::NO_BOARD);
307         }
308         if (!(x >= 0 && x < width && y >= 0 && y < height)) 
309         {
310                 return MovementResult(MovementResult::INVALID_POSITION);
311         }
312         Piece * target = board[x][y];
313         if (target == NULL) 
314         {
315                 return MovementResult(MovementResult::NO_SELECTION);
316         }
317         if (!(colour == Piece::NONE || target->colour == colour)) 
318         {
319                 return MovementResult(MovementResult::NOT_YOUR_UNIT);
320         }
321         if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER) 
322         {
323                 return MovementResult(MovementResult::IMMOBILE_UNIT);
324         }
325         if (multiplier > 1 && target->type != Piece::SCOUT)
326         {
327                 return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times.
328         }
329         int x2 = x; int y2 = y;
330
331         for (int ii=0; ii < multiplier; ++ii)
332         {
333                 switch (direction)
334                 {
335                         case UP:
336                                 --y2;
337                                 break;
338                         case DOWN:
339                                 ++y2;
340                                 break;
341                         case LEFT:
342                                 --x2;
343                                 break;
344                         case RIGHT:
345                                 ++x2;
346                                 break;
347                 }
348                 if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height)) 
349                 {
350                         return MovementResult(MovementResult::INVALID_DIRECTION);
351                 }
352                 if (ii < multiplier-1 && board[x2][y2] != NULL)
353                 {
354                         return MovementResult(MovementResult::POSITION_FULL);
355                 }
356         }
357         Piece * defender = board[x2][y2];
358         if (defender == NULL)
359         {
360                 board[x][y] = NULL;
361                 board[x2][y2] = target;
362         }
363         else if (defender->colour != target->colour)
364         {
365                 defender->beenRevealed = true;
366                 target->beenRevealed = true;
367
368                 Piece::Type defenderType = defender->type;
369                 Piece::Type attackerType = target->type;
370
371                 if (defender->colour == Piece::NONE) 
372                 {
373                         return MovementResult(MovementResult::POSITION_FULL);
374                 }
375                 if (defender->type == Piece::FLAG)
376                 {
377                         winner = target->colour;
378                         return MovementResult(MovementResult::VICTORY_FLAG);
379                 }
380                 else if (defender->type == Piece::BOMB)
381                 {
382                         if (target->type == Piece::MINER)
383                         {
384                                 RemovePiece(defender);
385                                 delete defender;
386                                 board[x][y] = NULL;
387                                 board[x2][y2] = target;
388                                 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
389                         }
390                         else
391                         {
392                                 //Use this to destroy only the attacking piece, and not the bomb
393                                 RemovePiece(target);
394                                 delete target;
395                                 board[x][y] = NULL;
396                                 return MovementResult(MovementResult::DIES, attackerType, defenderType);
397
398                                 /*
399                                 //Use this to destroy both the bomb and the attacking piece
400                                 RemovePiece(defender);
401                                 RemovePiece(target);
402                                 delete defender;
403                                 delete target;
404                                 board[x][y] = NULL;
405                                 board[x2][y2] = NULL;
406                                 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
407                                 */
408                         }
409                 }
410                 else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
411                 {
412                         RemovePiece(defender);
413                         delete defender;
414                         board[x][y] = NULL;
415                         board[x2][y2] = target;
416                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
417                 }
418                 else if (target->operator > (*defender))
419                 {
420                         RemovePiece(defender);
421                         delete defender;
422                         board[x][y] = NULL;
423                         board[x2][y2] = target;
424                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
425                 }
426                 else if (target->operator==(*defender))// && rand() % 2 == 0)
427                 {
428                         RemovePiece(defender);
429                         RemovePiece(target);
430                         delete defender;
431                         delete target;
432                         board[x][y] = NULL;
433                         board[x2][y2] = NULL;   
434                         return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
435                 }
436                 else
437                 {
438                         RemovePiece(target);
439                         delete target;
440                         board[x][y] = NULL;
441                         return MovementResult(MovementResult::DIES, attackerType, defenderType);
442                 }
443         }
444         else
445         {
446                 return MovementResult(MovementResult::POSITION_FULL);
447         }
448         return MovementResult(MovementResult::OK);
449 }       
450
451 /**
452  * Removes a piece from the board
453  * @param piece The piece to remove
454  * @returns true iff the piece actually existed
455  */
456 bool Board::RemovePiece(Piece * piece)
457 {
458         bool result = false;
459         for (int x = 0; x < width; ++x)
460         {
461                 for (int y = 0; y < height; ++y)        
462                 {
463                         if (board[x][y] == piece)
464                         {
465                                 result = true;
466                                 board[x][y] = NULL;
467                         }
468                 }
469         }
470
471         vector<Piece*>::iterator i = pieces.begin();
472         while (i != pieces.end())
473         {
474                 if ((*i) == piece)
475                 {
476                         i = pieces.erase(i);
477                         result = true;
478                         continue;
479                 }
480                 ++i;
481         }
482         return result;
483 }
484
485 /**
486  * Returns the total value of pieces belonging to colour
487  * @param colour the colour
488  * @returns the total value of pieces belonging to colour.
489  *      (Redundant repetition <3)
490  */
491 int Board::TotalPieceValue(const Piece::Colour & colour) const
492 {
493         int result = 0;
494         for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
495         {
496                 if ((*i)->colour == colour || colour == Piece::BOTH)
497                 {
498                         result += (*i)->PieceValue();
499                 }
500         }
501         return result;
502 }
503
504 /**
505  * Returns the total number of mobile pieces belonging to colour
506  * @param colour the colour
507  * @returns the total value of mobile pieces belonging to colour.
508  *      (Redundant repetition <3)
509  */
510 int Board::MobilePieces(const Piece::Colour & colour) const
511 {
512         int result = 0;
513         for (vector<Piece*>::const_iterator i = pieces.begin(); i != pieces.end(); ++i)
514         {
515                 if ((*i)->colour == colour || colour == Piece::BOTH)
516                 {
517                         if ((*i)->type <= Piece::MARSHAL && (*i)->type >= Piece::SPY)
518                                 result++;
519                 }
520         }
521         return result;
522 }
523
524

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