Final Commit
[progcomp2013.git] / agents / c++ / qchess.cpp
1 /**
2  * agent++ : A Sample agent for UCC::Progcomp2013
3  * @file qchess.h
4  * @purpose Definitions for game related classes; Piece, Square, Board
5  */
6
7 #include "qchess.h"
8 #include <cassert>
9
10 using namespace std;
11
12
13 /**
14  * @constructor
15  * @param new_x, new_y - Position of piece
16  * @param new_colour - Colour of piece
17  * @param type1, type2 - Types of piece
18  * @param new_type_index - Index for initial type of piece
19  * @param new_piece_index - Index for piece in a vector
20  */
21 Piece::Piece(int new_x, int new_y, const Piece::Colour & new_colour, const Piece::Type & type1, const Piece::Type & type2, 
22              int new_type_index)
23         : x(new_x), y(new_y), colour(new_colour), type_index(new_type_index), types(), current_type()
24 {
25         types[0] = type1; types[1] = type2;
26         if (type_index < 0 || type_index >= 2)
27         {
28                 current_type = Piece::UNKNOWN;
29         }
30         else
31         {
32                 current_type = types[type_index];
33         }
34 }
35
36 /**
37  * @constructor
38  * @param cpy - Piece to copy construct from
39  */
40 Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_index(cpy.type_index)
41 {
42         types[0] = cpy.types[0];
43         types[1] = cpy.types[1];
44 }
45
46 /**
47  * @constructor
48  * @param choose_types - Indicates whether Board should setup the 2nd types of pieces; default false
49  */
50 Board::Board(bool choose_types) 
51         : white(), black(), white_unknown(), black_unknown(), white_nUnknown(0), black_nUnknown(0),
52         white_king(NULL), black_king(NULL)
53 {
54
55         // initialise all the Squares
56         for (int x = 0; x < BOARD_WIDTH; ++x)
57         {
58                 for (int y = 0; y < BOARD_HEIGHT; ++y)
59                 {
60                         grid[x][y].x = x;
61                         grid[x][y].y = y;
62                 }
63         }
64
65         // const arrays simplify below code
66         Piece::Colour colours[] = {Piece::BLACK, Piece::WHITE};
67         Piece::Type types[] = {Piece::PAWN, Piece::BISHOP, Piece::KNIGHT, Piece::ROOK, Piece::QUEEN};
68
69         // frequency of each type of piece
70         map<Piece::Type, int> freq;
71         freq[Piece::ROOK] = 2;
72         freq[Piece::BISHOP] = 2;
73         freq[Piece::KNIGHT] = 2;
74         freq[Piece::QUEEN] = 1;
75         freq[Piece::PAWN] = 8;
76         
77         if (!choose_types)
78         {
79                 white_unknown = freq;
80                 black_unknown = freq;
81                 white_nUnknown = 15;
82                 black_nUnknown = 15;
83         }
84         
85         // for white and black...
86         for (int i = 0; i < 2; ++i)
87         {
88                 vector<Piece*> & v = pieces(colours[i]); // get vector of pieces
89                 
90                 
91
92                 // add pawns
93                 int y = (i == 0) ? 1 : BOARD_HEIGHT-2;
94                 for (int x = 0; x < BOARD_WIDTH; ++x)
95                 {       
96                         Piece::AddPiece(v, x, y, colours[i], Piece::PAWN, Piece::UNKNOWN);
97                 }               
98
99                 // add other pieces
100                 y = (i == 0) ? 0 : BOARD_HEIGHT-1;
101                 Piece::AddPiece(v, 0, y, colours[i], Piece::ROOK, Piece::UNKNOWN);
102                 Piece::AddPiece(v, BOARD_WIDTH-1, y, colours[i], Piece::ROOK, Piece::UNKNOWN);
103                 Piece::AddPiece(v, 1, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN);
104                 Piece::AddPiece(v, BOARD_WIDTH-2, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN);
105                 Piece::AddPiece(v, 2, y, colours[i], Piece::BISHOP, Piece::UNKNOWN);
106                 Piece::AddPiece(v, BOARD_WIDTH-3, y, colours[i], Piece::BISHOP, Piece::UNKNOWN);
107                 Piece::AddPiece(v, 3, y, colours[i], Piece::QUEEN, Piece::UNKNOWN);
108
109                 Piece * k = Piece::AddPiece(v, 4, y, colours[i], Piece::KING, Piece::KING, 1);
110                 if (i == 0)
111                         white_king = k;
112                 else
113                         black_king = k;
114                 
115                 
116                 // add to board and choose second types if required
117                 map<Piece::Type, int> f(freq); 
118                 int type2;
119                 for (unsigned j = 0; j < v.size(); ++j)
120                 {
121                         Piece * p = v[j];
122                         grid[p->x][p->y].piece = p;
123                         if (choose_types)
124                         {
125                                 if (p->types[1] != Piece::UNKNOWN)
126                                         continue;
127         
128                                 do
129                                 {
130                                         type2 = rand() % 5;
131                                 } while (f[types[type2]] <= 0);
132                                 f[types[type2]] -= 1;
133         
134                                 p->types[1] = types[type2];                     
135                         }
136
137                         
138                 }
139
140                 
141
142         }
143
144 }
145
146 /**
147  * @constructor
148  * @param cpy - Board to clone
149  */
150 Board::Board(Board & cpy) 
151 : white(cpy.white), black(cpy.black), white_unknown(cpy.white_unknown), black_unknown(cpy.black_unknown), 
152   white_nUnknown(cpy.white_nUnknown), black_nUnknown(cpy.black_nUnknown), 
153   white_king(cpy.white_king), black_king(cpy.black_king)
154 {
155         for (int x = 0; x < BOARD_WIDTH; ++x)
156         {
157                 for (int y = 0; y < BOARD_HEIGHT; ++y)
158                 {
159                         grid[x][y].x = x;
160                         grid[x][y].y = y;
161                         if (cpy.grid[x][y].piece != NULL)
162                         {
163                                 vector<Piece*> & v = pieces(cpy.grid[x][y].piece->colour);
164                                 Piece::AddPiece(v, *(cpy.grid[x][y].piece));
165                         }
166                 }
167         }
168 }
169
170 /**
171  * @destructor
172  */
173 Board::~Board()
174 {
175         white.clear();
176         black.clear();
177         for (int x = 0; x < BOARD_WIDTH; ++x)
178         {
179                 for (int y = 0; y < BOARD_HEIGHT; ++y)
180                 {
181                         delete grid[x][y].piece;
182                 }
183         }
184
185 }
186
187 /**
188  * @funct Update_select
189  * @purpose Update Piece that has been selected
190  * @param x, y - Position of Piece to update
191  * @param index - 0 or 1 - State the Piece "collapsed" into
192  * @param type - Type of the Piece as a string
193  */
194 void Board::Update_select(int x, int y, int index, const string & type)
195 {
196         Board::Update_select(x, y, index, Piece::str2type(type));
197 }
198
199 /**
200  * @funct Update_select
201  * @purpose Update Piece that has been selected
202  * @param x, y - Position of Piece to update
203  * @param index - 0 or 1 - State the Piece "collapsed" into
204  * @param t - Type of the Piece
205  */
206 void Board::Update_select(int x, int y, int index, const Piece::Type & t)
207 {
208         cerr << "Updating " << x << "," << y << " " << grid[x][y].piece << " " << index << " " << t << "\n";
209         Square & s = grid[x][y];
210         
211         
212         
213         assert(s.piece != NULL);
214         assert(index >= 0 && index < 2);
215         s.piece->type_index = index;
216         
217         if (s.piece->types[index] == Piece::UNKNOWN)
218         {
219                 map<Piece::Type, int> & m = unknown_types(s.piece->colour);
220                 int n = (m[t]--);
221                 if (n < 0)
222                         throw Exception("Board::Update_select", "Too many pieces of type %s found", Piece::type2str(t));
223                 
224                 nUnknown(s.piece->colour)--;
225                 
226         }
227         s.piece->types[index] = t;
228         s.piece->current_type = t;
229 }
230
231 /**
232  * @funct Update_move
233  * @purpose Move a Piece from one square to another
234  * @param x1, y1 - Coords of Square containing moving Piece
235  * @param x2, y2 - Coords of Square to move into
236  *      NOTE: Any Piece in the destination Square will be destroyed ("taken")
237  *              and the Board's other members updated accordingly
238  */
239 void Board::Update_move(int x1, int y1, int x2, int y2)
240 {
241         Square & s1 = grid[x1][y1];
242         Square & s2 = grid[x2][y2];
243         
244         
245
246         
247
248         if (s2.piece != NULL)
249         {
250                 vector<Piece*> & p = pieces(s2.piece->colour);
251                 vector<Piece*>::iterator i = p.begin();
252                 while (i != p.end())
253                 {
254                         if (*i == s2.piece)
255                         {
256                                 p.erase(i);
257                                 break;
258                         }
259                         ++i;
260                 }
261
262                 Piece * k = king(s2.piece->colour);
263                 if (k == s2.piece)
264                 {
265                         if (k->colour == Piece::WHITE)
266                                 white_king = NULL;
267                         else
268                                 black_king = NULL;
269                 }
270                 delete s2.piece;
271
272         }       
273
274         s1.piece->x = s2.x;
275         s1.piece->y = s2.y;
276
277         s2.piece = s1.piece;
278         s1.piece = NULL;        
279 }
280
281 /**
282  * @funct Get_moves
283  * @purpose Get all moves for a Piece and store them
284  * @param p - Piece
285  * @param v - vector to store Squares in. Will *not* be cleared.
286  */
287 void Board::Get_moves(Piece * p, vector<Square*> & v)
288 {
289         assert(p->current_type != Piece::UNKNOWN);
290         
291         int x = p->x; int y = p->y;
292         if (p->current_type == Piece::KING)
293         {
294                 Move(p, x+1, y, v);
295                 Move(p, x-1, y, v);
296                 Move(p, x, y+1, v);
297                 Move(p, x, y-1, v);
298                 Move(p, x+1, y+1, v);
299                 Move(p, x+1, y-1, v);
300                 Move(p, x-1, y+1, v);
301                 Move(p, x-1, y-1, v);
302         }
303         else if (p->current_type == Piece::KNIGHT)
304         {
305                 Move(p, x+2, y+1, v);
306                 Move(p, x+2, y-1, v);
307                 Move(p, x-2, y+1, v);
308                 Move(p, x-2, y-1, v);
309                 Move(p, x+1, y+2, v);
310                 Move(p, x-1, y+2, v);
311                 Move(p, x+1, y-2, v);
312                 Move(p, x-1, y-2, v); 
313         }
314         else if (p->current_type == Piece::PAWN)
315         {
316                 int y1 = (p->colour == Piece::WHITE) ? BOARD_HEIGHT-2 : 1;
317                 int y2 = (p->colour == Piece::WHITE) ? y1 - 2 : y1 + 2;
318                 if (p->types[0] == Piece::PAWN && p->y == y1)
319                 {
320                         
321                         Move(p, x, y2, v);
322                 }
323                 y2 = (p->colour == Piece::WHITE) ? y - 1 : y + 1;
324                 Move(p, x, y2, v);
325
326                 if (Valid_position(x-1, y2) && grid[x-1][y2].piece != NULL)
327                         Move(p, x-1, y2, v);
328                 if (Valid_position(x+1, y2) && grid[x+1][y2].piece != NULL)
329                         Move(p, x+1, y2, v);
330         }
331         else if (p->current_type == Piece::BISHOP)
332         {
333                 Scan(p, 1, 1, v);
334                 Scan(p, 1, -1, v);
335                 Scan(p, -1, 1, v);
336                 Scan(p, -1, -1, v);
337         }
338         else if (p->current_type == Piece::ROOK)
339         {
340                 Scan(p, 1, 0, v);
341                 Scan(p, -1, 0, v);
342                 Scan(p, 0, 1, v);
343                 Scan(p, 0, -1, v);
344         }
345         else if (p->current_type == Piece::QUEEN)
346         {
347                 Scan(p, 1, 1, v);
348                 Scan(p, 1, -1, v);
349                 Scan(p, -1, 1, v);
350                 Scan(p, -1, -1, v);
351                 Scan(p, 1, 0, v);
352                 Scan(p, -1, 0, v);
353                 Scan(p, 0, 1, v);
354                 Scan(p, 0, -1, v);
355         }
356
357
358
359 /**
360  * @funct Move
361  * @purpose Add a move to the vector, if it is valid
362  * @param p - Piece that would move
363  * @param x, y - Destination Square coords
364  * @param v - vector to put the destination Square in, if the move is valid
365  */
366 void Board::Move(Piece * p, int x, int y, vector<Square*> & v)
367 {
368         if (Valid_position(x, y) && (grid[x][y].piece == NULL || grid[x][y].piece->colour != p->colour))
369         {
370                 v.push_back(&(grid[x][y]));
371         }
372         //else
373         //      cerr << "Square " << x << "," << y << " invalid; " << grid[x][y].piece << "\n";
374 }
375
376 /**
377  * @funct Scan
378  * @purpose Add moves in a specified direction to the vector, until we get to an invalid move
379  * @param p - Piece to start scanning from
380  * @param vx, vy - "velocity" - change in coords each move
381  * @param v - vector to store valid Squares in
382  */
383 void Board::Scan(Piece * p, int vx, int vy, vector<Square*> & v)
384 {
385         int x = p->x + vx;
386         int y = p->y + vy;
387         while (Valid_position(x, y) && (grid[x][y].piece == NULL || grid[x][y].piece->colour != p->colour))
388         {
389                 v.push_back(&(grid[x][y]));
390                 if (grid[x][y].piece != NULL)
391                         break;
392                 x += vx;
393                 y += vy;
394         }
395 }
396
397 /**
398  * @funct str2type
399  * @purpose Convert string to Piece::Type
400  * @param str - The string
401  * @returns A Piece::Type
402  */
403 Piece::Type Piece::str2type(const string & str)
404 {
405         if (str == "king")
406                 return Piece::KING;
407         else if (str == "queen")
408                 return Piece::QUEEN;
409         else if (str == "rook")
410                 return Piece::ROOK;
411         else if (str == "bishop")
412                 return Piece::BISHOP;
413         else if (str == "knight")
414                 return Piece::KNIGHT;
415         else if (str == "pawn")
416                 return Piece::PAWN;
417         else if (str == "unknown")
418                 return Piece::UNKNOWN;
419
420         throw Exception("Piece::str2type", "String \"%s\" doesn't represent a type", str.c_str());
421         return Piece::UNKNOWN;
422 }
423
424 /**
425  * @funct type2str
426  * @purpose Convert Piece::Type to string
427  * @param t - The Types
428  * @returns a const char*
429  */
430 const char * Piece::type2str(const Piece::Type & t)
431 {
432         switch (t)
433         {
434                 case PAWN:
435                         return "pawn";
436                 case BISHOP:
437                         return "bishop";
438                 case KNIGHT:
439                         return "knight";
440                 case ROOK:
441                         return "rook";
442                 case QUEEN:
443                         return "queen";
444                 case UNKNOWN:
445                         return "unknown";
446                 case KING:
447                         return "king";
448                 default:
449                         throw Exception("Piece::type2str", "Unknown type %d", (int)t);
450                         return "";
451         }
452 }
453
454 /**
455  * @funct str2colour
456  * @purpose Convert string to Piece::Colour
457  * @param str - The string
458  * @returns A Piece::Colour
459  */
460 Piece::Colour Piece::str2colour(const string & str)
461 {
462         if (str == "white")
463                 return Piece::WHITE;
464         else if (str == "black")
465                 return Piece::BLACK;
466
467         throw Exception("Piece::str2colour", "string \"%s\" is not white|black", str.c_str());
468         return Piece::BLACK; // should never get here
469 }
470
471 /**
472  * @funct AddPiece
473  * @purpose Creates a new Piece and adds it to a vector
474  * @param v - The vector
475  * @params - All remaining parameters passed to Piece::Piece
476  * @returns Pointer to the new Piece
477  */
478 Piece * Piece::AddPiece(vector<Piece*> & v, int x, int y, const Piece::Colour & colour, const Piece::Type & t1, const Piece::Type & t2,
479                         int type_index)
480 {
481         Piece * p = new Piece(x,y,colour,t1, t2,type_index);
482         v.push_back(p);
483         return p;
484 }
485
486 /**
487  * @funct AddPiece
488  * @purpose Copy a Piece and add it to a vector
489  * @param v - The vector
490  * @param cpy - Piece to copy
491  * @returns Pointer to the new Piece
492  */
493 Piece * Piece::AddPiece(vector<Piece*> & v, const Piece & cpy)
494 {
495         Piece * p = new Piece(cpy);
496         v.push_back(p);
497         return p;
498 }

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