Actually commit stuff from ages ago
[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  * @constructor
14  * @param new_x, new_y - Position of piece
15  * @param new_colour - Colour of piece
16  * @param type1, type2 - Types of piece
17  * @param index - Index for initial type of piece
18  */
19 Piece::Piece(int new_x, int new_y, const Piece::Colour & new_colour, const Piece::Type & type1, const Piece::Type & type2, int index)
20         : x(new_x), y(new_y), colour(new_colour), type_index(index), types(), current_type()
21 {
22         types[0] = type1; types[1] = type2;
23         if (index < 0 || index >= 2)
24         {
25                 current_type = Piece::UNKNOWN;
26         }
27         else
28         {
29                 current_type = types[index];
30         }
31 }
32
33 /**
34  * @constructor
35  * @param cpy - Piece to copy construct from
36  */
37 Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_index(cpy.type_index)
38 {
39         types[0] = cpy.types[0];
40         types[1] = cpy.types[1];
41 }
42
43 /**
44  * @constructor
45  * @param choose_types - Indicates whether Board should setup the 2nd types of pieces; default false
46  */
47 Board::Board(bool choose_types)
48 {
49
50         // initialise all the Squares
51         for (int x = 0; x < BOARD_WIDTH; ++x)
52         {
53                 for (int y = 0; y < BOARD_HEIGHT; ++y)
54                 {
55                         grid[x][y].x = x;
56                         grid[x][y].y = y;
57                 }
58         }
59
60         // const arrays simplify below code
61         Piece::Colour colours[] = {Piece::BLACK, Piece::WHITE};
62         Piece::Type types[] = {Piece::PAWN, Piece::BISHOP, Piece::KNIGHT, Piece::ROOK, Piece::QUEEN};
63
64         // frequency of each type of piece
65         map<Piece::Type, int> freq;
66         freq[Piece::ROOK] = 2;
67         freq[Piece::BISHOP] = 2;
68         freq[Piece::KNIGHT] = 2;
69         freq[Piece::QUEEN] = 1;
70         freq[Piece::PAWN] = 8;
71         
72         // for white and black...
73         for (int i = 0; i < 2; ++i)
74         {
75                 vector<Piece*> & v = pieces(colours[i]); // get vector of pieces
76                 
77                 
78
79                 // add pawns
80                 int y = (i == 0) ? 1 : BOARD_HEIGHT-2;
81                 for (int x = 0; x < BOARD_WIDTH; ++x)
82                 {       
83                         Piece * p = new Piece(x, y, colours[i], Piece::PAWN, Piece::UNKNOWN);
84                         v.push_back(p);
85                 }               
86
87                 // add other pieces
88                 y = (i == 0) ? 0 : BOARD_HEIGHT-1;
89                 v.push_back(new Piece(0, y, colours[i], Piece::ROOK, Piece::UNKNOWN));
90                 v.push_back(new Piece(BOARD_WIDTH-1, y, colours[i], Piece::ROOK, Piece::UNKNOWN));
91                 v.push_back(new Piece(1, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN));
92                 v.push_back(new Piece(BOARD_WIDTH-2, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN));
93                 v.push_back(new Piece(2, y, colours[i], Piece::BISHOP, Piece::UNKNOWN));
94                 v.push_back(new Piece(BOARD_WIDTH-3, y, colours[i], Piece::BISHOP, Piece::UNKNOWN));
95                 v.push_back(new Piece(3, y, colours[i], Piece::QUEEN, Piece::UNKNOWN));
96
97                 Piece * k = new Piece(4, y, colours[i], Piece::KING, Piece::KING, 1);
98                 if (i == 0)
99                         white_king = k;
100                 else
101                         black_king = k;
102                 v.push_back(k);
103                 
104                 // add to board and choose second types if required
105                 map<Piece::Type, int> f(freq); 
106                 int type2;
107                 for (unsigned j = 0; j < v.size(); ++j)
108                 {
109                         Piece * p = v[j];
110                         grid[p->x][p->y].piece = p;
111                         if (choose_types)
112                         {
113                                 if (p->types[1] != Piece::UNKNOWN)
114                                         continue;
115         
116                                 do
117                                 {
118                                         type2 = rand() % 5;
119                                 } while (f[types[type2]] <= 0);
120                                 f[types[type2]] -= 1;
121         
122                                 p->types[1] = types[type2];                     
123                         }
124
125                         
126                 }
127
128                 
129
130         }
131
132 }
133
134 /**
135  * @constructor
136  * @param cpy - Board to copy construct from; each Piece in the copy will be *copied*
137  *              The Piece's in the copied Board may be altered without affecting the original
138  */
139 Board::Board(const Board & cpy)
140 {
141         for (int x = 0; x < BOARD_WIDTH; ++x)
142         {
143                 for (int y = 0; y < BOARD_HEIGHT; ++y)
144                 {
145                         grid[x][y].x = x;
146                         grid[x][y].y = y;
147
148                         if (cpy.grid[x][y].piece != NULL)
149                         {
150                                 grid[x][y].piece = new Piece(*(cpy.grid[x][y].piece));
151                                 pieces(grid[x][y].piece->colour).push_back(grid[x][y].piece);
152                         }
153                 }
154         }
155 }
156
157 /**
158  * @destructor
159  */
160 Board::~Board()
161 {
162         white.clear();
163         black.clear();
164         for (int x = 0; x < BOARD_WIDTH; ++x)
165         {
166                 for (int y = 0; y < BOARD_HEIGHT; ++y)
167                 {
168                         delete grid[x][y].piece;
169                 }
170         }
171
172 }
173
174 /**
175  * @funct Update_select
176  * @purpose Update Piece that has been selected
177  * @param x, y - Position of Piece to update
178  * @param index - 0 or 1 - State the Piece "collapsed" into
179  * @param type - Type of the Piece
180  */
181 void Board::Update_select(int x, int y, int index, const string & type)
182 {
183         cerr << "Updating " << x << "," << y << " " << grid[x][y].piece << " " << index << " " << type << "\n";
184         Square & s = grid[x][y];
185         assert(s.piece != NULL);
186         assert(index >= 0 && index < 2);
187         s.piece->type_index = index;
188         s.piece->types[index] = Piece::str2type(type);
189         s.piece->current_type = s.piece->types[index];
190 }
191
192 /**
193  * @funct Update_move
194  * @purpose Move a Piece from one square to another
195  * @param x1, y1 - Coords of Square containing moving Piece
196  * @param x2, y2 - Coords of Square to move into
197  *      NOTE: Any Piece in the destination Square will be destroyed ("taken")
198  *              and the Board's other members updated accordingly
199  */
200 void Board::Update_move(int x1, int y1, int x2, int y2)
201 {
202         Square & s1 = grid[x1][y1];
203         Square & s2 = grid[x2][y2];
204         if (s2.piece != NULL)
205         {
206                 vector<Piece*> & p = pieces(s2.piece->colour);
207                 vector<Piece*>::iterator i = p.begin();
208                 while (i != p.end())
209                 {
210                         if (*i == s2.piece)
211                         {
212                                 p.erase(i);
213                                 break;
214                         }
215                         ++i;
216                 }
217                 Piece * k = king(s2.piece->colour);
218                 if (k == s2.piece)
219                 {
220                         if (k->colour == Piece::WHITE)
221                                 white_king = NULL;
222                         else
223                                 black_king = NULL;
224                 }
225
226                 delete s2.piece;
227         }       
228
229         s1.piece->x = s2.x;
230         s1.piece->y = s2.y;
231
232         s2.piece = s1.piece;
233         s1.piece = NULL;        
234 }
235
236 /**
237  * @funct Get_moves
238  * @purpose Get all moves for a Piece and store them
239  * @param p - Piece
240  * @param v - vector to store Squares in. Will *not* be cleared.
241  */
242 void Board::Get_moves(Piece * p, vector<Square*> & v)
243 {
244         assert(p->current_type != Piece::UNKNOWN);
245         int x = p->x; int y = p->y;
246         if (p->current_type == Piece::KING)
247         {
248                 Move(p, x+1, y, v);
249                 Move(p, x-1, y, v);
250                 Move(p, x, y+1, v);
251                 Move(p, x, y-1, v);
252                 Move(p, x+1, y+1, v);
253                 Move(p, x+1, y-1, v);
254                 Move(p, x-1, y+1, v);
255                 Move(p, x-1, y-1, v);
256         }
257         else if (p->current_type == Piece::KNIGHT)
258         {
259                 Move(p, x+2, y+1, v);
260                 Move(p, x+2, y-1, v);
261                 Move(p, x-2, y+1, v);
262                 Move(p, x-2, y-1, v);
263                 Move(p, x+1, y+2, v);
264                 Move(p, x-1, y+2, v);
265                 Move(p, x+1, y-2, v);
266                 Move(p, x-1, y-2, v); 
267         }
268         else if (p->current_type == Piece::PAWN)
269         {
270                 int y1 = (p->colour == Piece::WHITE) ? BOARD_HEIGHT-2 : 1;
271                 int y2 = (p->colour == Piece::WHITE) ? y1 - 2 : y1 + 2;
272                 if (p->types[0] == Piece::PAWN && p->y == y1)
273                 {
274                         
275                         Move(p, x, y2, v);
276                 }
277                 y2 = (p->colour == Piece::WHITE) ? y - 1 : y + 1;
278                 Move(p, x, y2, v);
279
280                 if (Valid_position(x-1, y2) && grid[x-1][y2].piece != NULL)
281                         Move(p, x-1, y2, v);
282                 if (Valid_position(x+1, y2) && grid[x+1][y2].piece != NULL)
283                         Move(p, x+1, y2, v);
284         }
285         else if (p->current_type == Piece::BISHOP)
286         {
287                 Scan(p, 1, 1, v);
288                 Scan(p, 1, -1, v);
289                 Scan(p, -1, 1, v);
290                 Scan(p, -1, -1, v);
291         }
292         else if (p->current_type == Piece::ROOK)
293         {
294                 Scan(p, 1, 0, v);
295                 Scan(p, -1, 0, v);
296                 Scan(p, 0, 1, v);
297                 Scan(p, 0, -1, v);
298         }
299         else if (p->current_type == Piece::QUEEN)
300         {
301                 Scan(p, 1, 1, v);
302                 Scan(p, 1, -1, v);
303                 Scan(p, -1, 1, v);
304                 Scan(p, -1, -1, v);
305                 Scan(p, 1, 0, v);
306                 Scan(p, -1, 0, v);
307                 Scan(p, 0, 1, v);
308                 Scan(p, 0, -1, v);
309         }
310
311
312
313 /**
314  * @funct Move
315  * @purpose Add a move to the vector, if it is valid
316  * @param p - Piece that would move
317  * @param x, y - Destination Square coords
318  * @param v - vector to put the destination Square in, if the move is valid
319  */
320 void Board::Move(Piece * p, int x, int y, vector<Square*> & v)
321 {
322         if (Valid_position(x, y) && (grid[x][y].piece == NULL || grid[x][y].piece->colour != p->colour))
323         {
324                 v.push_back(&(grid[x][y]));
325         }
326         //else
327         //      cerr << "Square " << x << "," << y << " invalid; " << grid[x][y].piece << "\n";
328 }
329
330 /**
331  * @funct Scan
332  * @purpose Add moves in a specified direction to the vector, until we get to an invalid move
333  * @param p - Piece to start scanning from
334  * @param vx, vy - "velocity" - change in coords each move
335  * @param v - vector to store valid Squares in
336  */
337 void Board::Scan(Piece * p, int vx, int vy, vector<Square*> & v)
338 {
339         int x = p->x + vx;
340         int y = p->y + vy;
341         while (Valid_position(x, y) && (grid[x][y].piece == NULL || grid[x][y].piece->colour != p->colour))
342         {
343                 v.push_back(&(grid[x][y]));
344                 if (grid[x][y].piece != NULL)
345                         break;
346                 x += vx;
347                 y += vy;
348         }
349 }
350
351 /**
352  * @funct str2type
353  * @purpose Convert string to Piece::Type
354  * @param str - The string
355  * @returns A Piece::Type
356  */
357 Piece::Type Piece::str2type(const string & str)
358 {
359         if (str == "king")
360                 return Piece::KING;
361         else if (str == "queen")
362                 return Piece::QUEEN;
363         else if (str == "rook")
364                 return Piece::ROOK;
365         else if (str == "bishop")
366                 return Piece::BISHOP;
367         else if (str == "knight")
368                 return Piece::KNIGHT;
369         else if (str == "pawn")
370                 return Piece::PAWN;
371         else if (str == "unknown")
372                 return Piece::UNKNOWN;
373
374         throw Exception("Piece::str2type", "String \"%s\" doesn't represent a type", str.c_str());
375         return Piece::UNKNOWN;
376 }
377
378 /**
379  * @funct str2colour
380  * @purpose Convert string to Piece::Colour
381  * @param str - The string
382  * @returns A Piece::Colour
383  */
384 Piece::Colour Piece::str2colour(const string & str)
385 {
386         if (str == "white")
387                 return Piece::WHITE;
388         else if (str == "black")
389                 return Piece::BLACK;
390
391         throw Exception("Piece::str2colour", "string \"%s\" is not white|black", str.c_str());
392         return Piece::BLACK; // should never get here
393 }
394
395

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