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

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