Modified Turn Response Protocol, added handling for SIGPIPE, changed placeholder...
[progcomp2012.git] / manager / stratego.cpp
1 #include "common.h"
2
3 #include "stratego.h"
4
5 using namespace std;
6
7 /**
8  * Static variables
9  */
10 Board Board::theBoard(14,14);
11 //nothing, boulder, flag, spy, scout, miner, sergeant, lietenant, captain, major, colonel, general, marshal, bomb, error
12 char  Piece::tokens[] = {'.','+','F','y','s','n','S','L','c','m','C','G','M','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 GRAPHICS
18         Piece::TextureManager Piece::textures;
19 #endif //GRAPHICS
20
21
22 #ifdef GRAPHICS
23
24 Piece::TextureManager::~TextureManager()
25 {
26         Array<Texture*>::Iterator i(*this);
27         while (i.Good())
28         {
29                 delete (*i);
30                 ++i;
31         }
32 }
33
34 Texture & Piece::TextureManager::operator[](const LUint & at)
35 {
36         while (Array<Texture*>::Size() <= at)
37         {
38                 char buffer[BUFSIZ];
39                 sprintf(buffer, "images/piece%lu.bmp", Array<Texture*>::Size());
40                 Array<Texture*>::Add(new Texture(buffer, false));
41                 
42         }
43         return *(Array<Texture*>::operator[](at));
44 }
45 #endif //GRAPHICS
46
47 /**
48  * Gets the type of a piece, based off a character token
49  * @param fromToken - character identifying the piece
50  * @returns The type of the piece
51  */
52 Piece::Type Piece::GetType(char fromToken)
53 {
54         for (int ii=0; ii <= (int)(Piece::BOMB); ++ii)
55         {
56                 if (tokens[ii] == fromToken)
57                 {
58                         return Type(Piece::NOTHING + ii);
59                 }
60         }
61         return Piece::BOULDER;
62 }
63
64 /**
65  * Construct a new, empty board
66  * @param newWidth - the width of the board
67  * @param newHeight - the height of the board
68  */
69 Board::Board(int newWidth, int newHeight) : winner(Piece::NONE), width(newWidth), height(newHeight), board(NULL)
70 {
71         board = new Piece**[width];
72         for (int x=0; x < width; ++x)
73         {
74                 board[x] = new Piece*[height];
75                 for (int y=0; y < height; ++y)
76                         board[x][y] = NULL;
77         }
78 }
79
80 /**
81  * Cleanup a board
82  */
83 Board::~Board()
84 {
85         for (int x=0; x < width; ++x)
86         {
87                 for (int y=0; y < height; ++y)
88                         delete board[x][y];
89                 delete [] board[x];
90         }
91 }
92
93 /**
94  * Print textual representation of the board to a stream
95  * @param stream - the stream to print information to
96  * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' or '*' for RED or BLUE respectively.
97  */
98 void Board::Print(FILE * stream, const Piece::Colour & reveal)
99 {
100         for (int y=0; y < height; ++y)
101         {
102                 for (int x=0; x < width; ++x)
103                 {
104                         Piece * piece = board[x][y];
105                         if (piece == NULL)
106                         {
107                                 fprintf(stream, ".");
108                         }
109                         else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
110                         {
111                                 fprintf(stream, "%c", Piece::tokens[piece->type]);
112                         }
113                         else
114                         {
115                                 switch (piece->colour)
116                                 {
117                                         case Piece::RED:
118                                                 fprintf(stream, "#");
119                                                 break;
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, "$"); //Should never see these!
128                                                 break;
129                                 }
130                         }
131                 }
132                 fprintf(stream, "\n");
133         }
134         
135 }
136
137
138 #ifdef GRAPHICS
139 /**
140  * Draw the board state to graphics
141  * @param reveal - Pieces matching this colour will be revealed. All others will be shown as blank coloured squares.
142  */
143 void Board::Draw(const Piece::Colour & reveal)
144 {
145         if (!Graphics::Initialised())
146         {
147                 Graphics::Initialise("Stratego", width*32, height*32);
148         }
149
150         Graphics::ClearScreen();
151         
152         for (int y=0; y < height; ++y)
153         {
154                 for (int x=0; x < width; ++x)
155                 {
156                         Piece * piece = board[x][y];
157                         if (piece == NULL)
158                         {
159                                 //Don't display anything
160
161                         }
162                         else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH))
163                         {
164                                 //Display the piece
165                                 Piece::textures[(int)(piece->type)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
166                                 
167                         }
168                         else
169                         {
170                                 switch (piece->colour)
171                                 {
172                                         case Piece::RED:
173                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
174                                                 break;
175                                         case Piece::BLUE:
176                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
177                                                 break;
178                                         case Piece::NONE:
179                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
180                                                 break;
181                                         case Piece::BOTH:
182                                                 Piece::textures[(int)(Piece::BOULDER)].DrawColour(x*32,y*32,0,1, Piece::GetGraphicsColour(piece->colour));
183                                                 break;
184                                 }
185                         }
186                 }
187                 
188         }
189         Graphics::UpdateScreen();
190         
191 }
192 #endif //GRAPHICS
193
194 /**
195  * Adds a piece to the board
196  * @param x - x-coord to place the piece at, starting at zero, must be less than board width
197  * @param y - y-coord to place the piece at, starting at zero, must be less than board height
198  * @param newType - the Type of the piece
199  * @param newColour - the Colour of the piece
200  * @returns true if and only if the piece could be successfully added.
201  */
202 bool Board::AddPiece(int x, int y, const Piece::Type & newType, const Piece::Colour & newColour)
203 {
204         if (board == NULL || x < 0 || y < 0 || x >= width || y >= width || board[x][y] != NULL)
205                 return false;
206
207         Piece * piece = new Piece(newType, newColour);
208         board[x][y] = piece;
209         return true;
210 }
211
212 /**
213  * Gets a pointer to a piece at a board location
214  * UNUSED
215  * @param x - x-coord of the piece
216  * @param y - y-coord of the piece
217  * @returns pointer to the piece, or NULL if the board location was empty
218  * @throws error if board is null or coords are invalid
219  */
220 Piece * Board::GetPiece(int x, int y)
221 {
222         assert(board != NULL);
223         assert(x >= 0 && x < width && y >= 0 && y < height);
224         return board[x][y];
225 }
226
227 /**
228  * Moves a piece at a specified position in the specified direction, handles combat if necessary
229  * @param x - x-coord of the piece
230  * @param y - y-coord of the piece
231  * @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT)
232  * @param colour - Colour which the piece must match for the move to be valid
233  * @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
234  */
235 MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
236 {
237         if (board == NULL) 
238         {
239                 return MovementResult(MovementResult::NO_BOARD);
240         }
241         if (!(x >= 0 && x < width && y >= 0 && y < height)) 
242         {
243                 return MovementResult(MovementResult::INVALID_POSITION);
244         }
245         Piece * target = board[x][y];
246         if (target == NULL) 
247         {
248                 return MovementResult(MovementResult::NO_SELECTION);
249         }
250         if (!(colour == Piece::NONE || target->colour == colour)) 
251         {
252                 return MovementResult(MovementResult::NOT_YOUR_UNIT);
253         }
254         if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER) 
255         {
256                 return MovementResult(MovementResult::IMMOBILE_UNIT);
257         }
258         if (multiplier > 1 && target->type != Piece::SCOUT)
259         {
260                 return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times.
261         }
262         int x2 = x; int y2 = y;
263
264         for (int ii=0; ii < multiplier; ++ii)
265         {
266                 switch (direction)
267                 {
268                         case UP:
269                                 --y2;
270                                 break;
271                         case DOWN:
272                                 ++y2;
273                                 break;
274                         case LEFT:
275                                 --x2;
276                                 break;
277                         case RIGHT:
278                                 ++x2;
279                                 break;
280                 }
281                 if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height)) 
282                 {
283                         return MovementResult(MovementResult::INVALID_DIRECTION);
284                 }
285                 if (ii < multiplier-1 && board[x2][y2] != NULL)
286                 {
287                         return MovementResult(MovementResult::POSITION_FULL);
288                 }
289         }
290         Piece * defender = board[x2][y2];
291         if (defender == NULL)
292         {
293                 board[x][y] = NULL;
294                 board[x2][y2] = target;
295         }
296         else if (defender->colour != target->colour)
297         {
298                 Piece::Type defenderType = defender->type;
299                 Piece::Type attackerType = target->type;
300
301                 if (defender->colour == Piece::NONE) 
302                 {
303                         return MovementResult(MovementResult::POSITION_FULL);
304                 }
305                 if (defender->type == Piece::FLAG)
306                 {
307                         winner = target->colour;
308                         return MovementResult(MovementResult::VICTORY);
309                 }
310                 else if (defender->type == Piece::BOMB)
311                 {
312                         if (target->type == Piece::MINER)
313                         {
314
315                                 delete defender;
316                                 board[x][y] = NULL;
317                                 board[x2][y2] = target;
318                                 return MovementResult(MovementResult::KILLS, attackerType, defenderType);
319                         }
320                         else
321                         {
322                                 delete defender;
323                                 delete target;
324                                 board[x][y] = NULL;
325                                 board[x2][y2] = NULL;
326                                 return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
327                         }
328                 }
329                 else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY)
330                 {
331                         delete defender;
332                         board[x][y] = NULL;
333                         board[x2][y2] = target;
334                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
335                 }
336                 else if (target->operator > (*defender))
337                 {
338                         delete defender;
339                         board[x][y] = NULL;
340                         board[x2][y2] = target;
341                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
342                 }
343                 else if (target->operator==(*defender) && rand() % 2 == 0)
344                 {
345                         delete defender;
346                         board[x][y] = NULL;
347                         board[x2][y2] = target; 
348                         return MovementResult(MovementResult::KILLS, attackerType, defenderType);
349                 }
350                 else
351                 {
352                         delete target;
353                         board[x][y] = NULL;
354                         return MovementResult(MovementResult::DIES, attackerType, defenderType);
355                 }
356         }
357         else
358         {
359                 return MovementResult(MovementResult::POSITION_FULL);
360         }
361         return MovementResult(MovementResult::OK);
362 }       
363
364
365

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