├── .gitignore
├── Makefile
├── README.txt
├── chart_functions.png
├── logoDusan.jpg
├── logoGrahamBanks.png
├── secondchess
├── secondchess.c
└── secondchessW32.exe
/.gitignore:
--------------------------------------------------------------------------------
1 | nbproject
2 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=-O3 -funroll-loops
3 |
4 | seondchessmake: secondchess.c
5 | $(CC) -o secondchess *.c $(CFLAGS)
6 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | -secondchess is a derivative of firstchess
2 |
3 | -Its main aim is to add the neccesary code to firstchess in order
4 | to make it play real chess, especially adding the rules for castle and en
5 | passant capture, focusing in an easy to read code.
6 |
7 | -To compile under linux just "gcc secondchess.c -o secondchess -Ofast"
8 |
9 | -To compile under windows try tcc, geany+gcc, lcc. More info on the topic on http://www.chess2u.com/t5750-secondchess
10 |
11 | -Acknowledgments:
12 | -Pham Hong Nguyen, author of firstchess
13 | -Pedro Castro, author of danasah
14 | -The authors of http://chessprogramming.wikispaces.com/
15 | -Tony Mokonen for his windows compilations
16 | -Tom Kerrigan for TSCP
17 | -Bruce Moreland for his site
18 | -The people who post on talkchess
19 | -Jonatan Pettersson, author of mediocre chess
20 | -Graham Banks and Dusan Stamenkovic for their logos
21 | -Many more...
22 |
23 |
--------------------------------------------------------------------------------
/chart_functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/chart_functions.png
--------------------------------------------------------------------------------
/logoDusan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/logoDusan.jpg
--------------------------------------------------------------------------------
/logoGrahamBanks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/logoGrahamBanks.png
--------------------------------------------------------------------------------
/secondchess:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/secondchess
--------------------------------------------------------------------------------
/secondchess.c:
--------------------------------------------------------------------------------
1 | /*
2 | secondchess - gpl, by Emilio D�az, based on firstchess by Pham Hong Nguyen
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see
16 |
17 | * BASIC PARTS: *
18 | * Some definitions *
19 | * Board representation and main varians *
20 | * Move generator *
21 | * Evaluation for current position *
22 | * Make and Take back a move *
23 | * IsInCheck *
24 | * IsAttacked *
25 | * Search function - a typical alphabeta *
26 | * Quiescent search
27 | * Utilities *
28 | * Main program *
29 | */
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 |
37 | //#define NDEBUG
38 | #include
39 |
40 | /*
41 | ****************************************************************************
42 | * Some definitions *
43 | ****************************************************************************
44 | */
45 | #define PAWN 0
46 | #define KNIGHT 1
47 | #define BISHOP 2
48 | #define ROOK 3
49 | #define QUEEN 4
50 | #define KING 5
51 | #define EPS_SQUARE 6
52 | #define EMPTY 7
53 | #define WHITE 0
54 | #define BLACK 1
55 | #define false 0
56 |
57 | /* The values of the pieces */
58 | #define VALUE_PAWN 100
59 | #define VALUE_KNIGHT 310
60 | #define VALUE_BISHOP 320
61 | #define VALUE_ROOK 500
62 | #define VALUE_QUEEN 900
63 | #define VALUE_KING 10000
64 |
65 | #define MATE 10000 /* equal value of King, losing King==mate */
66 |
67 | #define COL(pos) ((pos)&7)
68 | #define ROW(pos) (((unsigned)pos)>>3)
69 |
70 | /* For move generation */
71 | #define MOVE_TYPE_NONE 0
72 | #define MOVE_TYPE_NORMAL 1
73 | #define MOVE_TYPE_CASTLE 2
74 | #define MOVE_TYPE_PAWN_TWO 3
75 | #define MOVE_TYPE_EPS 4
76 | #define MOVE_TYPE_PROMOTION_TO_QUEEN 5
77 | #define MOVE_TYPE_PROMOTION_TO_ROOK 6
78 | #define MOVE_TYPE_PROMOTION_TO_BISHOP 7
79 | #define MOVE_TYPE_PROMOTION_TO_KNIGHT 8
80 |
81 | /* Some useful squares */
82 | #define A1 56
83 | #define B1 57
84 | #define C1 58
85 | #define D1 59
86 | #define E1 60
87 | #define F1 61
88 | #define G1 62
89 | #define H1 63
90 | #define A8 0
91 | #define B8 1
92 | #define C8 2
93 | #define D8 3
94 | #define E8 4
95 | #define F8 5
96 | #define G8 6
97 | #define H8 7
98 |
99 | /*
100 | ****************************************************************************
101 | * Board representation and main variants *
102 | ****************************************************************************
103 | */
104 | /* Board representation */
105 | int piece[64];
106 | int color[64];
107 |
108 | /* Piece in each square */
109 | int init_piece[64] = {
110 | ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
111 | PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
112 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
113 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
114 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
115 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
116 | PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
117 | ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
118 | };
119 |
120 | /* Color of each square */
121 | int init_color[64] = {
122 | BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
123 | BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
124 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
125 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
126 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
127 | EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
128 | WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
129 | WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
130 | };
131 |
132 | //int piece[64] = {
133 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
134 | // EMPTY, EMPTY, EMPTY, EMPTY, ROOK, PAWN, EMPTY, EMPTY,
135 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
136 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
137 | // EMPTY, EMPTY, EMPTY, EMPTY, PAWN, KING, EMPTY, EMPTY,
138 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
139 | // EMPTY, EMPTY, EMPTY, PAWN, EMPTY, EMPTY, PAWN, PAWN,
140 | // EMPTY, EMPTY, EMPTY, EMPTY, KING, EMPTY, EMPTY, ROOK };
141 | ///* Color of each square */
142 | //int color[64] = {
143 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
144 | // EMPTY, EMPTY, EMPTY, EMPTY, BLACK, WHITE, EMPTY, EMPTY,
145 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
146 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
147 | // EMPTY, EMPTY, EMPTY, EMPTY, BLACK, BLACK, EMPTY, EMPTY,
148 | // EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
149 | // EMPTY, EMPTY, EMPTY, WHITE, EMPTY, EMPTY, WHITE, WHITE,
150 | // EMPTY, EMPTY, EMPTY, EMPTY, WHITE, EMPTY, EMPTY, WHITE };
151 |
152 |
153 | int side; /* Side to move, value = BLACK or WHITE */
154 | int computer_side;
155 | int max_depth; /* max depth to search */
156 |
157 | /* A move is defined by its origin and final squares, the castle rights and the kind of
158 | * move it's: normal, enpasant... */
159 | typedef struct tag_MOVE
160 | {
161 | int from;
162 | int dest;
163 | // int castle;
164 | int type;
165 | } MOVE;
166 |
167 | /* For storing all moves of game */
168 | typedef struct tag_HIST
169 | {
170 | MOVE m;
171 | int castle;
172 | int cap;
173 | } HIST;
174 |
175 | HIST hist[6000]; /* Game length < 6000 */
176 |
177 | /* For castle rights we use a bitfield, like in TSCP
178 | *
179 | * 0001 -> White can short castle
180 | * 0010 -> White can long castle
181 | * 0100 -> Black can short castle
182 | * 1000 -> Black can long castle
183 | *
184 | * 15 = 1111 = 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
185 | *
186 | */
187 | int castle_rights = 15; /* At start position all castle types ar available */
188 |
189 |
190 | /* This mask is applied like this
191 | *
192 | * castle &= castle_mask[from] & castle_mask[dest]
193 | *
194 | * When from and dest are whatever pieces, then nothing happens, otherwise
195 | * the values are chosen in such a way that if vg the white king moves
196 | * to F1 then
197 | *
198 | * castle = castle & (12 & 15)
199 | * 1111 & (1100 & 1111) == 1111 & 1100 == 1100
200 | *
201 | * and white's lost all its castle rights
202 | *
203 | * */
204 | int castle_mask[64] = {
205 | 7, 15, 15, 15, 3, 15, 15, 11,
206 | 15, 15, 15, 15, 15, 15, 15, 15,
207 | 15, 15, 15, 15, 15, 15, 15, 15,
208 | 15, 15, 15, 15, 15, 15, 15, 15,
209 | 15, 15, 15, 15, 15, 15, 15, 15,
210 | 15, 15, 15, 15, 15, 15, 15, 15,
211 | 15, 15, 15, 15, 15, 15, 15, 15,
212 | 13, 15, 15, 15, 12, 15, 15, 14
213 | };
214 |
215 | int hdp; /* Current move order */
216 | //int allmoves = 0;
217 |
218 | /* For searching */
219 | int nodes; /* Count all visited nodes when searching */
220 | int ply; /* ply of search */
221 | int count_evaluations;
222 | int count_checks;
223 | int count_MakeMove;
224 | int count_quies_calls;
225 | int count_cap_calls;
226 |
227 | /* The values of the pieces in centipawns */
228 | int value_piece[6] =
229 | { VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN,
230 | VALUE_KING };
231 |
232 | /* * * * * * * * * * * * *
233 | * Piece Square Tables
234 | * * * * * * * * * * * * */
235 | /* When evaluating the position we'll add a bonus (or malus) to each piece
236 | * depending on the very square where it's placed. Vg, a knight in d4 will
237 | * be given an extra +15, whilst a knight in a1 will be penalized with -40.
238 | * This simple idea allows the engine to make more sensible moves */
239 | int pst_pawn[64] = {
240 | 0, 0, 0, 0, 0, 0, 0, 0,
241 | 0, 0, 0, 0, 0, 0, 0, 0,
242 | 0, 0, 0, 0, 0, 0, 0, 0,
243 | 0, 0, 0, 15, 15, 0, 0, 0,
244 | 0, 0, 0, 10, 10, 0, 0, 0,
245 | 0, 0, 0, 5, 5, 0, 0, 0,
246 | 0, 0, 0, -25, -25, 0, 0, 0,
247 | 0, 0, 0, 0, 0, 0, 0, 0
248 | };
249 |
250 | int pst_knight[64] = {
251 | -40, -25, -25, -25, -25, -25, -25, -40,
252 | -30, 0, 0, 0, 0, 0, 0, -30,
253 | -30, 0, 0, 0, 0, 0, 0, -30,
254 | -30, 0, 0, 15, 15, 0, 0, -30,
255 | -30, 0, 0, 15, 15, 0, 0, -30,
256 | -30, 0, 10, 0, 0, 10, 0, -30,
257 | -30, 0, 0, 5, 5, 0, 0, -30,
258 | -40, -30, -25, -25, -25, -25, -30, -40
259 | };
260 |
261 | int pst_bishop[64] = {
262 | -10, 0, 0, 0, 0, 0, 0, -10,
263 | -10, 5, 0, 0, 0, 0, 5, -10,
264 | -10, 0, 5, 0, 0, 5, 0, -10,
265 | -10, 0, 0, 10, 10, 0, 0, -10,
266 | -10, 0, 5, 10, 10, 5, 0, -10,
267 | -10, 0, 5, 0, 0, 5, 0, -10,
268 | -10, 5, 0, 0, 0, 0, 5, -10,
269 | -10, -20, -20, -20, -20, -20, -20, -10
270 | };
271 |
272 | int pst_rook[64] = {
273 | 0, 0, 0, 0, 0, 0, 0, 0,
274 | 10, 10, 10, 10, 10, 10, 10, 10,
275 | 0, 0, 0, 0, 0, 0, 0, 0,
276 | 0, 0, 0, 0, 0, 0, 0, 0,
277 | 0, 0, 0, 0, 0, 0, 0, 0,
278 | 0, 0, 0, 0, 0, 0, 0, 0,
279 | 0, 0, 0, 0, 0, 0, 0, 0,
280 | 0, 0, 0, 5, 5, 0, 0, 0
281 | };
282 |
283 | int pst_king[64] = {
284 | -25, -25, -25, -25, -25, -25, -25, -25,
285 | -25, -25, -25, -25, -25, -25, -25, -25,
286 | -25, -25, -25, -25, -25, -25, -25, -25,
287 | -25, -25, -25, -25, -25, -25, -25, -25,
288 | -25, -25, -25, -25, -25, -25, -25, -25,
289 | -25, -25, -25, -25, -25, -25, -25, -25,
290 | -25, -25, -25, -25, -25, -25, -25, -25,
291 | 10, 15, -15, -15, -15, -15, 15, 10
292 | };
293 |
294 | /* The flip array is used to calculate the piece/square
295 | values for BLACKS pieces, without needing to write the
296 | arrays for them (idea taken from TSCP).
297 | The piece/square value of a white pawn is pst_pawn[sq]
298 | and the value of a black pawn is pst_pawn[flip[sq]] */
299 | int flip[64] = {
300 | 56, 57, 58, 59, 60, 61, 62, 63,
301 | 48, 49, 50, 51, 52, 53, 54, 55,
302 | 40, 41, 42, 43, 44, 45, 46, 47,
303 | 32, 33, 34, 35, 36, 37, 38, 39,
304 | 24, 25, 26, 27, 28, 29, 30, 31,
305 | 16, 17, 18, 19, 20, 21, 22, 23,
306 | 8, 9, 10, 11, 12, 13, 14, 15,
307 | 0, 1, 2, 3, 4, 5, 6, 7
308 | };
309 |
310 | /*
311 | ****************************************************************************
312 | * Move generator *
313 | ****************************************************************************
314 | */
315 | void
316 | Gen_Push (int from, int dest, int type, MOVE * pBuf, int *pMCount)
317 | {
318 | MOVE move;
319 | move.from = from;
320 | move.dest = dest;
321 | move.type = type;
322 | // move.castle = castle;
323 | pBuf[*pMCount] = move;
324 | *pMCount = *pMCount + 1;
325 | }
326 |
327 | void
328 | Gen_PushNormal (int from, int dest, MOVE * pBuf, int *pMCount)
329 | {
330 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
331 | }
332 |
333 | /* Especial cases for Pawn */
334 |
335 | /* Pawn can promote */
336 | void
337 | Gen_PushPawn (int from, int dest, MOVE * pBuf, int *pMCount)
338 | {
339 | /* The 7 and 56 are to limit pawns to the 2nd through 7th ranks, which
340 | * means this isn't a promotion, i.e., a normal pawn move */
341 | if (piece[dest] == EPS_SQUARE)
342 | {
343 | Gen_Push (from, dest, MOVE_TYPE_EPS, pBuf, pMCount);
344 | }
345 | else if (dest > 7 && dest < 56) /* this is just a normal move */
346 | {
347 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
348 | }
349 | else /* otherwise it's a promotion */
350 | {
351 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
352 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
353 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
354 | Gen_Push (from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
355 | }
356 | }
357 |
358 | /* When a pawn moves two squares then appears the possibility of the en passanta capture*/
359 | void
360 | Gen_PushPawnTwo (int from, int dest, MOVE * pBuf, int *pMCount)
361 | {
362 | Gen_Push (from, dest, MOVE_TYPE_PAWN_TWO, pBuf, pMCount);
363 | }
364 |
365 | /* Especial cases for King */
366 | void
367 | Gen_PushKing (int from, int dest, MOVE * pBuf, int *pMCount)
368 | {
369 | /* Is it a castle? */
370 | if (from == E1 && (dest == G1 || dest == C1)) /* this is a white castle */
371 | {
372 | Gen_Push (from, dest, MOVE_TYPE_CASTLE, pBuf, pMCount);
373 | }
374 | else if (from == E8 && (dest == G8 || dest == C8)) /* this is a black castle */
375 | {
376 | Gen_Push (from, dest, MOVE_TYPE_CASTLE, pBuf, pMCount);
377 | }
378 | else /* otherwise it's a normal king's move */
379 | {
380 | Gen_Push (from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
381 | }
382 | }
383 |
384 | /* Gen all moves of current_side to move and push them to pBuf, and return number of moves */
385 | int
386 | GenMoves (int current_side, MOVE * pBuf)
387 | {
388 | int i; /* Counter for the board squares */
389 | int k; /* Counter for cols */
390 | int y;
391 | int row;
392 | int col;
393 | int movecount;
394 | movecount = 0;
395 |
396 | for (i = 0; i < 64; i++) /* Scan all board */
397 | if (color[i] == current_side)
398 | {
399 | switch (piece[i])
400 | {
401 |
402 | case PAWN:
403 | col = COL (i);
404 | row = ROW (i);
405 | if (current_side == BLACK)
406 | {
407 | if (color[i + 8] == EMPTY)
408 | /* Pawn advances one square.
409 | * We use Gen_PushPawn because it can be a promotion */
410 | Gen_PushPawn (i, i + 8, pBuf, &movecount);
411 | if (row == 1 && color[i + 8] == EMPTY
412 | && color[i + 16] == EMPTY)
413 | /* Pawn advances two squares */
414 | Gen_PushPawnTwo (i, i + 16, pBuf, &movecount);
415 | if (col && color[i + 7] == WHITE)
416 | /* Pawn captures and it can be a promotion */
417 | Gen_PushPawn (i, i + 7, pBuf, &movecount);
418 | if (col < 7 && color[i + 9] == WHITE)
419 | /* Pawn captures and can be a promotion */
420 | Gen_PushPawn (i, i + 9, pBuf, &movecount);
421 | /* For en passant capture */
422 | if (col && piece[i + 7] == EPS_SQUARE)
423 | /* Pawn captures and it can be a promotion */
424 | Gen_PushPawn (i, i + 7, pBuf, &movecount);
425 | if (col < 7 && piece[i + 9] == EPS_SQUARE)
426 | /* Pawn captures and can be a promotion */
427 | Gen_PushPawn (i, i + 9, pBuf, &movecount);
428 | }
429 | else
430 | {
431 | if (color[i - 8] == EMPTY)
432 | Gen_PushPawn (i, i - 8, pBuf, &movecount);
433 | /* Pawn moves 2 squares */
434 | if (row == 6 && color[i - 8] == EMPTY
435 | && color[i - 16] == EMPTY)
436 | Gen_PushPawnTwo (i, i - 16, pBuf, &movecount);
437 | /* For captures */
438 | if (col && color[i - 9] == BLACK)
439 | Gen_PushPawn (i, i - 9, pBuf, &movecount);
440 | if (col < 7 && color[i - 7] == BLACK)
441 | Gen_PushPawn (i, i - 7, pBuf, &movecount);
442 | /* For en passant capture */
443 | if (col && piece[i - 9] == EPS_SQUARE)
444 | Gen_PushPawn (i, i - 9, pBuf, &movecount);
445 | if (col < 7 && piece[i - 7] == EPS_SQUARE)
446 | Gen_PushPawn (i, i - 7, pBuf, &movecount);
447 | }
448 | break;
449 |
450 | case QUEEN: /* == BISHOP+ROOK */
451 |
452 | case BISHOP:
453 | for (y = i - 9; y >= 0 && COL (y) != 7; y -= 9)
454 | { /* go left up */
455 | if (color[y] != current_side)
456 | Gen_PushNormal (i, y, pBuf, &movecount);
457 | if (color[y] != EMPTY)
458 | break;
459 | }
460 | for (y = i - 7; y >= 0 && COL (y) != 0; y -= 7)
461 | { /* go right up */
462 | if (color[y] != current_side)
463 | Gen_PushNormal (i, y, pBuf, &movecount);
464 | if (color[y] != EMPTY)
465 | break;
466 | }
467 | for (y = i + 9; y < 64 && COL (y) != 0; y += 9)
468 | { /* go right down */
469 | if (color[y] != current_side)
470 | Gen_PushNormal (i, y, pBuf, &movecount);
471 | if (color[y] != EMPTY)
472 | break;
473 | }
474 | for (y = i + 7; y < 64 && COL (y) != 7; y += 7)
475 | { /* go left down */
476 | if (color[y] != current_side)
477 | Gen_PushNormal (i, y, pBuf, &movecount);
478 | if (color[y] != EMPTY)
479 | break;
480 | }
481 | if (piece[i] == BISHOP) /* In the case of the bishop we're done */
482 | break;
483 |
484 | /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
485 | case ROOK:
486 | col = COL (i);
487 | for (k = i - col, y = i - 1; y >= k; y--)
488 | { /* go left */
489 | if (color[y] != current_side)
490 | Gen_PushNormal (i, y, pBuf, &movecount);
491 | if (color[y] != EMPTY)
492 | break;
493 | }
494 | for (k = i - col + 7, y = i + 1; y <= k; y++)
495 | { /* go right */
496 | if (color[y] != current_side)
497 | Gen_PushNormal (i, y, pBuf, &movecount);
498 | if (color[y] != EMPTY)
499 | break;
500 | }
501 | for (y = i - 8; y >= 0; y -= 8)
502 | { /* go up */
503 | if (color[y] != current_side)
504 | Gen_PushNormal (i, y, pBuf, &movecount);
505 | if (color[y] != EMPTY)
506 | break;
507 | }
508 | for (y = i + 8; y < 64; y += 8)
509 | { /* go down */
510 | if (color[y] != current_side)
511 | Gen_PushNormal (i, y, pBuf, &movecount);
512 | if (color[y] != EMPTY)
513 | break;
514 | }
515 | break;
516 |
517 | case KNIGHT:
518 | col = COL (i);
519 | y = i - 6;
520 | if (y >= 0 && col < 6 && color[y] != current_side)
521 | Gen_PushNormal (i, y, pBuf, &movecount);
522 | y = i - 10;
523 | if (y >= 0 && col > 1 && color[y] != current_side)
524 | Gen_PushNormal (i, y, pBuf, &movecount);
525 | y = i - 15;
526 | if (y >= 0 && col < 7 && color[y] != current_side)
527 | Gen_PushNormal (i, y, pBuf, &movecount);
528 | y = i - 17;
529 | if (y >= 0 && col > 0 && color[y] != current_side)
530 | Gen_PushNormal (i, y, pBuf, &movecount);
531 | y = i + 6;
532 | if (y < 64 && col > 1 && color[y] != current_side)
533 | Gen_PushNormal (i, y, pBuf, &movecount);
534 | y = i + 10;
535 | if (y < 64 && col < 6 && color[y] != current_side)
536 | Gen_PushNormal (i, y, pBuf, &movecount);
537 | y = i + 15;
538 | if (y < 64 && col > 0 && color[y] != current_side)
539 | Gen_PushNormal (i, y, pBuf, &movecount);
540 | y = i + 17;
541 | if (y < 64 && col < 7 && color[y] != current_side)
542 | Gen_PushNormal (i, y, pBuf, &movecount);
543 | break;
544 |
545 | case KING:
546 | /* the column and rank checks are to make sure it is on the board */
547 | /* The 'normal' moves */
548 | col = COL (i);
549 | if (col && color[i - 1] != current_side)
550 | Gen_PushKing (i, i - 1, pBuf, &movecount); /* left */
551 | if (col < 7 && color[i + 1] != current_side)
552 | Gen_PushKing (i, i + 1, pBuf, &movecount); /* right */
553 | if (i > 7 && color[i - 8] != current_side)
554 | Gen_PushKing (i, i - 8, pBuf, &movecount); /* up */
555 | if (i < 56 && color[i + 8] != current_side)
556 | Gen_PushKing (i, i + 8, pBuf, &movecount); /* down */
557 | if (col && i > 7 && color[i - 9] != current_side)
558 | Gen_PushKing (i, i - 9, pBuf, &movecount); /* left up */
559 | if (col < 7 && i > 7 && color[i - 7] != current_side)
560 | Gen_PushKing (i, i - 7, pBuf, &movecount); /* right up */
561 | if (col && i < 56 && color[i + 7] != current_side)
562 | Gen_PushKing (i, i + 7, pBuf, &movecount); /* left down */
563 | if (col < 7 && i < 56 && color[i + 9] != current_side)
564 | Gen_PushKing (i, i + 9, pBuf, &movecount); /* right down */
565 |
566 | /* The castle moves */
567 | if (current_side == WHITE)
568 | {
569 | /* Can white short castle? */
570 | if (castle_rights & 1)
571 | {
572 | /* If white can castle the white king has to be in square 60 */
573 | if (col &&
574 | color[i + 1] == EMPTY &&
575 | color[i + 2] == EMPTY &&
576 | !IsInCheck (current_side) &&
577 | !IsAttacked (current_side, i + 1))
578 | {
579 | /* The king goes 2 sq to the left */
580 | Gen_PushKing (i, i + 2, pBuf, &movecount);
581 | }
582 | }
583 |
584 | /* Can white long castle? */
585 | if (castle_rights & 2)
586 | {
587 | if (col &&
588 | color[i - 1] == EMPTY &&
589 | color[i - 2] == EMPTY &&
590 | color[i - 3] == EMPTY &&
591 | !IsInCheck (current_side) &&
592 | !IsAttacked (current_side, i - 1))
593 | {
594 | /* The king goes 2 sq to the left */
595 | Gen_PushKing (i, i - 2, pBuf, &movecount);
596 | }
597 | }
598 | }
599 | else if (current_side == BLACK)
600 | {
601 | /* Can black short castle? */
602 | if (castle_rights & 4)
603 | {
604 | /* If white can castle the white king has to be in square 60 */
605 | if (col &&
606 | color[i + 1] == EMPTY &&
607 | color[i + 2] == EMPTY &&
608 | piece[i + 3] == ROOK &&
609 | !IsInCheck (current_side) &&
610 | !IsAttacked (current_side, i + 1))
611 | {
612 | /* The king goes 2 sq to the left */
613 | Gen_PushKing (i, i + 2, pBuf, &movecount);
614 | }
615 | }
616 | /* Can black long castle? */
617 | if (castle_rights & 8)
618 | {
619 | if (col &&
620 | color[i - 1] == EMPTY &&
621 | color[i - 2] == EMPTY &&
622 | color[i - 3] == EMPTY &&
623 | piece[i - 4] == ROOK &&
624 | !IsInCheck (current_side) &&
625 | !IsAttacked (current_side, i - 1))
626 | {
627 | /* The king goes 2 sq to the left */
628 | Gen_PushKing (i, i - 2, pBuf, &movecount);
629 | }
630 | }
631 | }
632 |
633 | break;
634 | // default:
635 | // printf("Piece type unknown, %d", piece[i]);
636 | // assert(false);
637 | }
638 | }
639 | return movecount;
640 | }
641 |
642 | /* Gen all captures of current_side to move and push them to pBuf, return number of moves
643 | * It's necesary at least ir order to use quiescent in the search */
644 | int
645 | GenCaps (int current_side, MOVE * pBuf)
646 | {
647 | int i; /* Counter for the board squares */
648 | int k; /* Counter for cols */
649 | int y;
650 | int row;
651 | int col;
652 | int capscount; /* Counter for the posible captures */
653 | int xside;
654 | xside = (WHITE + BLACK) - current_side;
655 | capscount = 0;
656 |
657 | for (i = 0; i < 64; i++) /* Scan all board */
658 | if (color[i] == current_side)
659 | {
660 | switch (piece[i])
661 | {
662 |
663 | case PAWN:
664 | col = COL (i);
665 | row = ROW (i);
666 | if (current_side == BLACK)
667 | {
668 | /* This isn't a capture, but it's necesary in order to
669 | * not oversee promotions */
670 | if (row > 7 && color[i + 8] == EMPTY)
671 | /* Pawn advances one square.
672 | * We use Gen_PushPawn because it can be a promotion */
673 | Gen_PushPawn (i, i + 8, pBuf, &capscount);
674 | if (col && color[i + 7] == WHITE)
675 | /* Pawn captures and it can be a promotion */
676 | Gen_PushPawn (i, i + 7, pBuf, &capscount);
677 | if (col < 7 && color[i + 9] == WHITE)
678 | /* Pawn captures and can be a promotion */
679 | Gen_PushPawn (i, i + 9, pBuf, &capscount);
680 | /* For en passant capture */
681 | if (col && piece[i + 7] == EPS_SQUARE)
682 | /* Pawn captures and it can be a promotion */
683 | Gen_PushPawn (i, i + 7, pBuf, &capscount);
684 | if (col < 7 && piece[i + 9] == EPS_SQUARE)
685 | /* Pawn captures and can be a promotion */
686 | Gen_PushPawn (i, i + 9, pBuf, &capscount);
687 | }
688 | else if (current_side == WHITE)
689 | {
690 | if (row < 2 && color[i - 8] == EMPTY)
691 | /* This isn't a capture, but it's necesary in order to
692 | * not oversee promotions */
693 | Gen_PushPawn (i, i - 8, pBuf, &capscount);
694 | /* For captures */
695 | if (col && color[i - 9] == BLACK)
696 | Gen_PushPawn (i, i - 9, pBuf, &capscount);
697 | if (col < 7 && color[i - 7] == BLACK)
698 | Gen_PushPawn (i, i - 7, pBuf, &capscount);
699 | /* For en passant capture */
700 | if (col && piece[i - 9] == EPS_SQUARE)
701 | Gen_PushPawn (i, i - 9, pBuf, &capscount);
702 | if (col < 7 && piece[i - 7] == EPS_SQUARE)
703 | Gen_PushPawn (i, i - 7, pBuf, &capscount);
704 | }
705 | break;
706 |
707 | case KNIGHT:
708 | col = COL (i);
709 | y = i - 6;
710 | if (y >= 0 && col < 6 && color[y] == xside)
711 | Gen_PushNormal (i, y, pBuf, &capscount);
712 | y = i - 10;
713 | if (y >= 0 && col > 1 && color[y] == xside)
714 | Gen_PushNormal (i, y, pBuf, &capscount);
715 | y = i - 15;
716 | if (y >= 0 && col < 7 && color[y] == xside)
717 | Gen_PushNormal (i, y, pBuf, &capscount);
718 | y = i - 17;
719 | if (y >= 0 && col > 0 && color[y] == xside)
720 | Gen_PushNormal (i, y, pBuf, &capscount);
721 | y = i + 6;
722 | if (y < 64 && col > 1 && color[y] == xside)
723 | Gen_PushNormal (i, y, pBuf, &capscount);
724 | y = i + 10;
725 | if (y < 64 && col < 6 && color[y] == xside)
726 | Gen_PushNormal (i, y, pBuf, &capscount);
727 | y = i + 15;
728 | if (y < 64 && col > 0 && color[y] == xside)
729 | Gen_PushNormal (i, y, pBuf, &capscount);
730 | y = i + 17;
731 | if (y < 64 && col < 7 && color[y] == xside)
732 | Gen_PushNormal (i, y, pBuf, &capscount);
733 | break;
734 |
735 | case QUEEN: /* == BISHOP+ROOK */
736 |
737 | case BISHOP:
738 | for (y = i - 9; y >= 0 && COL (y) != 7; y -= 9)
739 | { /* go left up */
740 | if (color[y] != EMPTY)
741 | {
742 | if (color[y] != current_side)
743 | Gen_PushNormal (i, y, pBuf, &capscount);
744 | break;
745 | }
746 | }
747 | for (y = i - 7; y >= 0 && COL (y) != 0; y -= 7)
748 | { /* go right up */
749 | if (color[y] != EMPTY)
750 | {
751 | if (color[y] != current_side)
752 | Gen_PushNormal (i, y, pBuf, &capscount);
753 | break;
754 | }
755 | }
756 | for (y = i + 9; y < 64 && COL (y) != 0; y += 9)
757 | { /* go right down */
758 | if (color[y] != EMPTY)
759 | {
760 | if (color[y] != current_side)
761 | Gen_PushNormal (i, y, pBuf, &capscount);
762 | break;
763 | }
764 | }
765 | for (y = i + 7; y < 64 && COL (y) != 7; y += 7)
766 | { /* go left down */
767 | if (color[y] != EMPTY)
768 | {
769 | if (color[y] != current_side)
770 | Gen_PushNormal (i, y, pBuf, &capscount);
771 | break;
772 | }
773 | }
774 | if (piece[i] == BISHOP) /* In the case of the bishop we're done */
775 | break;
776 |
777 | /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
778 | case ROOK:
779 | col = COL (i);
780 | for (k = i - col, y = i - 1; y >= k; y--)
781 | { /* go left */
782 | if (color[y] != EMPTY)
783 | {
784 | if (color[y] != current_side)
785 | Gen_PushNormal (i, y, pBuf, &capscount);
786 | break;
787 | }
788 | }
789 | for (k = i - col + 7, y = i + 1; y <= k; y++)
790 | { /* go right */
791 | if (color[y] != EMPTY)
792 | {
793 | if (color[y] != current_side)
794 | Gen_PushNormal (i, y, pBuf, &capscount);
795 | break;
796 | }
797 | }
798 | for (y = i - 8; y >= 0; y -= 8)
799 | { /* go up */
800 | if (color[y] != EMPTY)
801 | {
802 | if (color[y] != current_side)
803 | Gen_PushNormal (i, y, pBuf, &capscount);
804 | break;
805 | }
806 | }
807 | for (y = i + 8; y < 64; y += 8)
808 | { /* go down */
809 | if (color[y] != EMPTY)
810 | {
811 | if (color[y] != current_side)
812 | Gen_PushNormal (i, y, pBuf, &capscount);
813 | break;
814 | }
815 | }
816 | break;
817 |
818 | case KING:
819 | ///* the column and rank checks are to make sure it is on the board*/
820 | col = COL (i);
821 | if (col && color[i - 1] == xside)
822 | Gen_PushKing (i, i - 1, pBuf, &capscount); /* left */
823 | if (col < 7 && color[i + 1] == xside)
824 | Gen_PushKing (i, i + 1, pBuf, &capscount); /* right */
825 | if (i > 7 && color[i - 8] == xside)
826 | Gen_PushKing (i, i - 8, pBuf, &capscount); /* up */
827 | if (i < 56 && color[i + 8] == xside)
828 | Gen_PushKing (i, i + 8, pBuf, &capscount); /* down */
829 | if (col && i > 7 && color[i - 9] == xside)
830 | Gen_PushKing (i, i - 9, pBuf, &capscount); /* left up */
831 | if (col < 7 && i > 7 && color[i - 7] == xside)
832 | Gen_PushKing (i, i - 7, pBuf, &capscount); /* right up */
833 | if (col && i < 56 && color[i + 7] == xside)
834 | Gen_PushKing (i, i + 7, pBuf, &capscount); /* left down */
835 | if (col < 7 && i < 56 && color[i + 9] == xside)
836 | Gen_PushKing (i, i + 9, pBuf, &capscount); /* right down */
837 | break;
838 | // default:
839 | // printf("Piece type unknown");
840 | // assert(false);
841 | }
842 | }
843 | return capscount;
844 | }
845 |
846 | /*
847 | ****************************************************************************
848 | * Evaluation for current position - main "brain" function *
849 | * Lack: almost no knowlegde; material value + piece square tables *
850 | ****************************************************************************
851 | */
852 | int
853 | Eval ()
854 | {
855 |
856 | count_evaluations++;
857 |
858 | /* A counter for the board squares */
859 | int i;
860 |
861 | /* The score of the position */
862 | int score = 0;
863 |
864 | /* Check all the squares searching for the pieces */
865 | for (i = 0; i < 64; i++)
866 | {
867 | if (color[i] == WHITE)
868 | {
869 | /* In the current square, add the material
870 | * value of the piece */
871 | score += value_piece[piece[i]];
872 |
873 | /* Now we add to the evaluation the value of the
874 | * piece square tables */
875 | switch (piece[i])
876 | {
877 | case PAWN:
878 | score += pst_pawn[i];
879 | break;
880 | case KNIGHT:
881 | score += pst_knight[i];
882 | break;
883 | case BISHOP:
884 | score += pst_bishop[i];
885 | break;
886 | case ROOK:
887 | score += pst_rook[i];
888 | break;
889 | case KING:
890 | score += pst_king[i];
891 | break;
892 | }
893 | }
894 | /* Now the evaluation for black: note the change of
895 | the sign in the score */
896 | else if (color[i] == BLACK)
897 | {
898 | score -= value_piece[piece[i]];
899 |
900 | switch (piece[i])
901 | {
902 | case PAWN:
903 | score -= pst_pawn[flip[i]];
904 | break;
905 | case KNIGHT:
906 | score -= pst_knight[flip[i]];
907 | break;
908 | case BISHOP:
909 | score -= pst_bishop[flip[i]];
910 | break;
911 | case ROOK:
912 | score -= pst_rook[flip[i]];
913 | break;
914 | case KING:
915 | score -= pst_king[flip[i]];
916 | break;
917 | }
918 | }
919 | }
920 |
921 | /* Finally we return the score, taking into account the side to move */
922 | if (side == WHITE)
923 | return score;
924 | return -score;
925 | }
926 |
927 | /*
928 | ****************************************************************************
929 | * Make and Take back a move, IsInCheck *
930 | ****************************************************************************
931 | */
932 |
933 | /* Check if current side is in check. Necesary in order to check legality of moves
934 | and check if castle is allowed */
935 | int
936 | IsInCheck (int current_side)
937 | {
938 | int k; /* The square where the king is placed */
939 |
940 | /* Find the King of the side to move */
941 | for (k = 0; k < 64; k++)
942 | if ((piece[k] == KING) && color[k] == current_side)
943 | break;
944 |
945 | /* Use IsAttacked in order to know if current_side is under check */
946 | return IsAttacked (current_side, k);
947 | }
948 |
949 | /* Returns 1 if square k is attacked by current_side, 0 otherwise. Necesary, v.g., to check
950 | * castle rules (if king goes from e1 to g1, f1 can't be attacked by an enemy piece) */
951 | int
952 | IsAttacked (int current_side, int k)
953 | {
954 | int h;
955 | int y;
956 | int row; /* Row where the square k is placed */
957 | int col; /* Col where the square k is placed */
958 | int xside;
959 | xside = (WHITE + BLACK) - current_side; /* opposite current_side, who may be attacking */
960 |
961 | /* Situation of the square */
962 | row = ROW (k);
963 | col = COL (k);
964 |
965 | /* Check Knight attack */
966 | if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
967 | return 1;
968 | if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
969 | return 1;
970 | if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
971 | return 1;
972 | if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
973 | return 1;
974 | if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
975 | return 1;
976 | if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
977 | return 1;
978 | if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
979 | return 1;
980 | if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
981 | return 1;
982 |
983 | /* Check horizontal and vertical lines for attacking of Queen, Rook, King */
984 | /* go down */
985 | y = k + 8;
986 | if (y < 64)
987 | {
988 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN
989 | || piece[y] == ROOK))
990 | return 1;
991 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
992 | for (y += 8; y < 64; y += 8)
993 | {
994 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
995 | return 1;
996 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
997 | break;
998 | }
999 | }
1000 | /* go left */
1001 | y = k - 1;
1002 | h = k - col;
1003 | if (y >= h)
1004 | {
1005 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN
1006 | || piece[y] == ROOK))
1007 | return 1;
1008 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1009 | for (y--; y >= h; y--)
1010 | {
1011 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
1012 | return 1;
1013 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1014 | break;
1015 | }
1016 | }
1017 | /* go right */
1018 | y = k + 1;
1019 | h = k - col + 7;
1020 | if (y <= h)
1021 | {
1022 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN
1023 | || piece[y] == ROOK))
1024 | return 1;
1025 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1026 | for (y++; y <= h; y++)
1027 | {
1028 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
1029 | return 1;
1030 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1031 | break;
1032 | }
1033 | }
1034 | /* go up */
1035 | y = k - 8;
1036 | if (y >= 0)
1037 | {
1038 | if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN
1039 | || piece[y] == ROOK))
1040 | return 1;
1041 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1042 | for (y -= 8; y >= 0; y -= 8)
1043 | {
1044 | if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
1045 | return 1;
1046 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1047 | break;
1048 | }
1049 | }
1050 | /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
1051 | /* go right down */
1052 | y = k + 9;
1053 | if (y < 64 && COL (y) != 0)
1054 | {
1055 | if (color[y] == xside)
1056 | {
1057 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
1058 | return 1;
1059 | if (current_side == BLACK && piece[y] == PAWN)
1060 | return 1;
1061 | }
1062 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1063 | for (y += 9; y < 64 && COL (y) != 0; y += 9)
1064 | {
1065 | if (color[y] == xside && (piece[y] == QUEEN || piece[y]
1066 | == BISHOP))
1067 | return 1;
1068 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1069 | break;
1070 | }
1071 | }
1072 | /* go left down */
1073 | y = k + 7;
1074 | if (y < 64 && COL (y) != 7)
1075 | {
1076 | if (color[y] == xside)
1077 | {
1078 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
1079 | return 1;
1080 | if (current_side == BLACK && piece[y] == PAWN)
1081 | return 1;
1082 | }
1083 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1084 | for (y += 7; y < 64 && COL (y) != 7; y += 7)
1085 | {
1086 | if (color[y] == xside && (piece[y] == QUEEN || piece[y]
1087 | == BISHOP))
1088 | return 1;
1089 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1090 | break;
1091 |
1092 | }
1093 | }
1094 | /* go left up */
1095 | y = k - 9;
1096 | if (y >= 0 && COL (y) != 7)
1097 | {
1098 | if (color[y] == xside)
1099 | {
1100 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
1101 | return 1;
1102 | if (current_side == WHITE && piece[y] == PAWN)
1103 | return 1;
1104 | }
1105 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1106 | for (y -= 9; y >= 0 && COL (y) != 7; y -= 9)
1107 | {
1108 | if (color[y] == xside && (piece[y] == QUEEN || piece[y]
1109 | == BISHOP))
1110 | return 1;
1111 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1112 | break;
1113 |
1114 | }
1115 | }
1116 | /* go right up */
1117 | y = k - 7;
1118 | if (y >= 0 && COL (y) != 0)
1119 | {
1120 | if (color[y] == xside)
1121 | {
1122 | if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
1123 | return 1;
1124 | if (current_side == WHITE && piece[y] == PAWN)
1125 | return 1;
1126 | }
1127 | if (piece[y] == EMPTY || piece[y] == EPS_SQUARE)
1128 | for (y -= 7; y >= 0 && COL (y) != 0; y -= 7)
1129 | {
1130 | if (color[y] == xside && (piece[y] == QUEEN || piece[y]
1131 | == BISHOP))
1132 | return 1;
1133 | if (piece[y] != EMPTY && piece[y] != EPS_SQUARE)
1134 | break;
1135 | }
1136 | }
1137 | return 0;
1138 | }
1139 |
1140 | int
1141 | MakeMove (MOVE m)
1142 | {
1143 | int r;
1144 | int i;
1145 |
1146 | count_MakeMove++;
1147 |
1148 | hist[hdp].m = m;
1149 | hist[hdp].cap = piece[m.dest]; /* store in history the piece of the dest square */
1150 | hist[hdp].castle = castle_rights;
1151 |
1152 | piece[m.dest] = piece[m.from]; /* dest piece is the one in the original square */
1153 | color[m.dest] = color[m.from]; /* The dest square color is the one of the origin piece */
1154 | piece[m.from] = EMPTY; /* The original square becomes empty */
1155 | color[m.from] = EMPTY; /* The original color becomes empty */
1156 |
1157 | /* en pasant capture */
1158 | if (m.type == MOVE_TYPE_EPS)
1159 | {
1160 | if (side == WHITE)
1161 | {
1162 | piece[m.dest + 8] = EMPTY;
1163 | color[m.dest + 8] = EMPTY;
1164 | }
1165 | else
1166 | {
1167 | piece[m.dest - 8] = EMPTY;
1168 | color[m.dest - 8] = EMPTY;
1169 | }
1170 | }
1171 |
1172 | /* Remove possible eps piece, remaining from former move */
1173 | if (hist[hdp - 1].m.type == MOVE_TYPE_PAWN_TWO)
1174 | {
1175 | for (i = 16; i <= 23; i++)
1176 | {
1177 | if (piece[i] == EPS_SQUARE)
1178 | {
1179 | piece[i] = EMPTY;
1180 | /* this seems unnecesary, but otherwise a bug occurs:
1181 | * after: a3 Nc6 d4 e6, white isn't allowed to play e4 */
1182 | // color[i] = EMPTY;
1183 | break;
1184 | }
1185 | }
1186 | for (i = 40; i <= 47; i++)
1187 | {
1188 | if (piece[i] == EPS_SQUARE)
1189 | {
1190 | piece[i] = EMPTY;
1191 | // color[i] = EMPTY;
1192 | break;
1193 | }
1194 | }
1195 | }
1196 |
1197 | /* Add the eps square when a pawn moves two squares */
1198 | if (m.type == MOVE_TYPE_PAWN_TWO)
1199 | {
1200 | if (side == BLACK)
1201 | {
1202 | piece[m.from + 8] = EPS_SQUARE;
1203 | color[m.from + 8] = EMPTY;
1204 | }
1205 | else if (side == WHITE)
1206 | {
1207 | piece[m.from - 8] = EPS_SQUARE;
1208 | color[m.from - 8] = EMPTY;
1209 | }
1210 | }
1211 |
1212 | /* Once the move is done we check either this is a promotion */
1213 | if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)
1214 | {
1215 | /* In this case we put in the destiny sq the chosen piece */
1216 | switch (m.type)
1217 | {
1218 | case MOVE_TYPE_PROMOTION_TO_QUEEN:
1219 | piece[m.dest] = QUEEN;
1220 | break;
1221 |
1222 | case MOVE_TYPE_PROMOTION_TO_ROOK:
1223 | piece[m.dest] = ROOK;
1224 | break;
1225 |
1226 | case MOVE_TYPE_PROMOTION_TO_BISHOP:
1227 | piece[m.dest] = BISHOP;
1228 | break;
1229 |
1230 | case MOVE_TYPE_PROMOTION_TO_KNIGHT:
1231 | piece[m.dest] = KNIGHT;
1232 | break;
1233 |
1234 | default:
1235 | puts ("Impossible to get here...");
1236 | assert (false);
1237 | }
1238 | }
1239 |
1240 | if (m.type == MOVE_TYPE_CASTLE)
1241 | {
1242 | if (m.dest == G1)
1243 | {
1244 | /* h1-h8 becomes empty */
1245 | piece[m.from + 3] = EMPTY;
1246 | color[m.from + 3] = EMPTY;
1247 | /* rook to f1-f8 */
1248 | piece[m.from + 1] = ROOK;
1249 | color[m.from + 1] = WHITE;
1250 | }
1251 | else if (m.dest == C1)
1252 | {
1253 | /* h1-h8 becomes empty */
1254 | piece[m.from - 4] = EMPTY;
1255 | color[m.from - 4] = EMPTY;
1256 | /* rook to f1-f8 */
1257 | piece[m.from - 1] = ROOK;
1258 | color[m.from - 1] = WHITE;
1259 | }
1260 | else if (m.dest == G8)
1261 | {
1262 | /* h1-h8 becomes empty */
1263 | piece[m.from + 3] = EMPTY;
1264 | color[m.from + 3] = EMPTY;
1265 | /* rook to f1-f8 */
1266 | piece[m.from + 1] = ROOK;
1267 | color[m.from + 1] = BLACK;
1268 | }
1269 | else if (m.dest == C8)
1270 | {
1271 | /* h1-h8 becomes empty */
1272 | piece[m.from - 4] = EMPTY;
1273 | color[m.from - 4] = EMPTY;
1274 | /* rook to f1-f8 */
1275 | piece[m.from - 1] = ROOK;
1276 | color[m.from - 1] = BLACK;
1277 | }
1278 | }
1279 |
1280 | /* Update ply and hdp */
1281 | ply++;
1282 | hdp++;
1283 |
1284 | /* Update the castle rights */
1285 | castle_rights &= castle_mask[m.from] & castle_mask[m.dest];
1286 |
1287 | /* Checking if after making the move we're in check */
1288 | r = !IsInCheck (side);
1289 |
1290 | /* After making move, give turn to opponent */
1291 | side = (WHITE + BLACK) - side;
1292 |
1293 | return r;
1294 | }
1295 |
1296 | /* Undo what MakeMove did */
1297 | void
1298 | TakeBack ()
1299 | {
1300 |
1301 | int i;
1302 |
1303 | side = (WHITE + BLACK) - side;
1304 | hdp--;
1305 | ply--;
1306 | piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
1307 | piece[hist[hdp].m.dest] = hist[hdp].cap;
1308 | color[hist[hdp].m.from] = side;
1309 |
1310 | /* Update castle rights */
1311 | castle_rights = hist[hdp].castle;
1312 |
1313 | /* Return the captured material */
1314 | if (hist[hdp].cap != EMPTY && hist[hdp].cap != EPS_SQUARE)
1315 | {
1316 | color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
1317 | }
1318 | else
1319 | {
1320 | color[hist[hdp].m.dest] = EMPTY;
1321 | }
1322 |
1323 | /* Promotion */
1324 | if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN)
1325 | {
1326 | piece[hist[hdp].m.from] = PAWN;
1327 | }
1328 |
1329 | /* If pawn moved two squares in the former move, we have to restore
1330 | * the eps square */
1331 | if (hist[hdp - 1].m.type == MOVE_TYPE_PAWN_TWO)
1332 | {
1333 | if (side == WHITE)
1334 | {
1335 | piece[hist[hdp - 1].m.dest - 8] = EPS_SQUARE;
1336 | // color[hist[hdp-1].m.dest - 8] = EMPTY;
1337 | }
1338 | else if (side == BLACK)
1339 | {
1340 | piece[hist[hdp - 1].m.dest + 8] = EPS_SQUARE;
1341 | // color[hist[hdp-1].m.dest + 8] = EMPTY;
1342 | }
1343 | }
1344 |
1345 | /* To remove the eps square after unmaking a pawn
1346 | * moving two squares*/
1347 | if (hist[hdp].m.type == MOVE_TYPE_PAWN_TWO)
1348 | {
1349 | if (side == WHITE)
1350 | {
1351 | piece[hist[hdp].m.from - 8] = EMPTY;
1352 | color[hist[hdp].m.from - 8] = EMPTY;
1353 | }
1354 | else
1355 | {
1356 | piece[hist[hdp].m.from + 8] = EMPTY;
1357 | color[hist[hdp].m.from + 8] = EMPTY;
1358 | }
1359 | }
1360 |
1361 | /* Unmaking an en pasant capture */
1362 | if (hist[hdp].m.type == MOVE_TYPE_EPS)
1363 | {
1364 | if (side == WHITE)
1365 | {
1366 | /* The pawn */
1367 | piece[hist[hdp].m.dest + 8] = PAWN;
1368 | color[hist[hdp].m.dest + 8] = BLACK;
1369 | /* The eps square */
1370 | piece[hist[hdp].m.dest] = EPS_SQUARE;
1371 | // color[hist[hdp].m.dest] = EMPTY;
1372 | }
1373 | else
1374 | {
1375 | /* The pawn */
1376 | piece[hist[hdp].m.dest - 8] = PAWN;
1377 | color[hist[hdp].m.dest - 8] = WHITE;
1378 | /* The eps square */
1379 | piece[hist[hdp].m.dest] = EPS_SQUARE;
1380 | // color[hist[hdp].m.dest] = EMPTY;
1381 | }
1382 | }
1383 |
1384 | /* Undo Castle: return rook to its original square */
1385 | if (hist[hdp].m.type == MOVE_TYPE_CASTLE)
1386 | {
1387 | /* Take the tower to its poriginal place */
1388 | if (hist[hdp].m.dest == G1 && side == WHITE)
1389 | {
1390 | piece[H1] = ROOK;
1391 | color[H1] = WHITE;
1392 | piece[F1] = EMPTY;
1393 | color[F1] = EMPTY;
1394 | }
1395 | else if (hist[hdp].m.dest == C1 && side == WHITE)
1396 | {
1397 | piece[A1] = ROOK;
1398 | color[A1] = WHITE;
1399 | piece[D1] = EMPTY;
1400 | color[D1] = EMPTY;
1401 | }
1402 | else if (hist[hdp].m.dest == G8 && side == BLACK)
1403 | {
1404 | piece[H8] = ROOK;
1405 | color[H8] = BLACK;
1406 | piece[F8] = EMPTY;
1407 | color[F8] = EMPTY;
1408 | }
1409 | else if (hist[hdp].m.dest == C8 && side == BLACK)
1410 | {
1411 | piece[A8] = ROOK;
1412 | color[A8] = BLACK;
1413 | piece[D8] = EMPTY;
1414 | color[D8] = EMPTY;
1415 | }
1416 | }
1417 | }
1418 |
1419 | /*
1420 | ****************************************************************************
1421 | * Search function - a typical alphabeta, main search function *
1422 | * Lack: no move ordering *
1423 | ****************************************************************************
1424 | */
1425 |
1426 | int
1427 | Search (int alpha, int beta, int depth, MOVE * pBestMove)
1428 | {
1429 | int i;
1430 | int value; /* To store the evaluation */
1431 | int havemove; /* Either we have or not a legal move available */
1432 | int movecnt; /* The number of available moves */
1433 |
1434 | MOVE moveBuf[200]; /* List of movements */
1435 | MOVE tmpMove;
1436 |
1437 | // nodes++; /* visiting a node, count it */
1438 | havemove = 0; /* is there a move available? */
1439 | pBestMove->type = MOVE_TYPE_NONE;
1440 |
1441 | /* Generate and count all moves for current position */
1442 | movecnt = GenMoves (side, moveBuf);
1443 | assert (movecnt < 201);
1444 |
1445 | /* Once we have all the moves available, we loop through the posible
1446 | * moves and apply an alpha-beta search */
1447 | for (i = 0; i < movecnt; ++i)
1448 | {
1449 |
1450 | if (!MakeMove (moveBuf[i]))
1451 | {
1452 | /* If the current move isn't legal, we take it back
1453 | * and take the next move in the list */
1454 | TakeBack ();
1455 | continue;
1456 | }
1457 |
1458 | /* If we've reached this far, then we have a move available */
1459 | havemove = 1;
1460 |
1461 | /* This 'if' takes us to the deep of the position, the leaf nodes */
1462 | if (depth - 1 > 0)
1463 | {
1464 | value = -Search (-beta, -alpha, depth - 1, &tmpMove);
1465 | }
1466 | /* If no depth left (leaf node), we evalute the position
1467 | and apply the alpha-beta search.
1468 | In the case of existing a quiescent function, it should be
1469 | called here instead of Eval() */
1470 | else
1471 | {
1472 | value = -Quiescent (-beta, -alpha);
1473 | // value = -Eval();
1474 | }
1475 |
1476 | /* We've evaluated the position, so we return to the previous position in such a way
1477 | that when we take the next move from moveBuf everything is in order */
1478 | TakeBack ();
1479 |
1480 | /* Once we have an evaluation, we use it in in an alpha-beta search */
1481 | if (value > alpha)
1482 | {
1483 | /* This move is so good and caused a cutoff */
1484 | if (value >= beta)
1485 | {
1486 | return beta;
1487 | }
1488 | alpha = value;
1489 | /* So far, current move is the best reaction for current position */
1490 | *pBestMove = moveBuf[i];
1491 | }
1492 | }
1493 |
1494 | /* Once we've checked all the moves, if we have no legal moves,
1495 | * then that's checkmate or stalemate */
1496 | if (!havemove)
1497 | {
1498 | if (IsInCheck (side))
1499 | return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */
1500 | else
1501 | return 0;
1502 | }
1503 |
1504 | /* Finally we return alpha, the score value */
1505 | return alpha;
1506 | }
1507 |
1508 | int
1509 | Quiescent (int alpha, int beta)
1510 | {
1511 | int i;
1512 | int capscnt;
1513 | int stand_pat;
1514 | int score;
1515 | MOVE cBuf[200];
1516 |
1517 | count_quies_calls++;
1518 |
1519 | /* First we just try the evaluation function */
1520 | stand_pat = Eval ();
1521 | if (stand_pat >= beta)
1522 | return beta;
1523 | if (alpha < stand_pat)
1524 | alpha = stand_pat;
1525 |
1526 | /* If we haven't got a cut off we generate the captures and
1527 | * store them in cBuf */
1528 | capscnt = GenCaps (side, cBuf);
1529 |
1530 | count_cap_calls++;
1531 |
1532 | for (i = 0; i < capscnt; ++i)
1533 | {
1534 | if (!MakeMove (cBuf[i]))
1535 | {
1536 | /* If the current move isn't legal, we take it back
1537 | * and take the next move in the list */
1538 | TakeBack ();
1539 | continue;
1540 | }
1541 | score = -Quiescent (-beta, -alpha);
1542 | TakeBack ();
1543 | if (score >= beta)
1544 | return beta;
1545 | if (score > alpha)
1546 | alpha = score;
1547 | }
1548 | return alpha;
1549 | }
1550 |
1551 |
1552 |
1553 | MOVE
1554 | ComputerThink (int depth)
1555 | {
1556 | /* It returns the move the computer makes */
1557 | MOVE m;
1558 | int score;
1559 | double knps;
1560 |
1561 | /* Reset some values before searching */
1562 | ply = 0;
1563 | nodes = 0;
1564 | count_evaluations = 0;
1565 | count_MakeMove = 0;
1566 | count_quies_calls = 0;
1567 | count_cap_calls = 0;
1568 |
1569 | clock_t start;
1570 | clock_t stop;
1571 | double t = 0.0;
1572 |
1573 | /* Start timer */
1574 | start = clock ();
1575 | assert (start != -1);
1576 |
1577 | /* Search now */
1578 | score = Search (-MATE, MATE, depth, &m);
1579 |
1580 | /* Stop timer */
1581 | stop = clock ();
1582 | t = (double) (stop - start) / CLOCKS_PER_SEC;
1583 | knps = ((double) count_quies_calls / t) / 1000.;
1584 |
1585 | double ratio_Qsearc_Capcalls =
1586 | (double) count_quies_calls / (double) count_cap_calls;
1587 |
1588 | double decimal_score = ((double) score) / 100.;
1589 | if (side == BLACK)
1590 | {
1591 | decimal_score = -decimal_score;
1592 | }
1593 |
1594 | /* After searching, print results */
1595 | printf
1596 | ("Search result: move = %c%d%c%d; depth = %d, score = %.2f, time = %.2fs knps = %.2f\n countCapCalls = %d\n countQSearch = %d\n moves made = %d\n ratio_Qsearc_Capcalls = %.2f\n",
1597 | 'a' + COL (m.from), 8 - ROW (m.from), 'a' + COL (m.dest),
1598 | 8 - ROW (m.dest), depth, decimal_score, t, knps, count_cap_calls,
1599 | count_quies_calls, count_MakeMove, ratio_Qsearc_Capcalls);
1600 | return m;
1601 | }
1602 |
1603 | /*
1604 | ****************************************************************************
1605 | * Utilities *
1606 | ****************************************************************************
1607 | */
1608 |
1609 | void
1610 | PrintBoard ()
1611 | {
1612 | char pieceName[] = "PNBRQKpnbrqk";
1613 | int i;
1614 | for (i = 0; i < 64; i++)
1615 | {
1616 | if ((i & 7) == 0)
1617 | {
1618 | printf (" +---+---+---+---+---+---+---+---+\n");
1619 | if (i <= 56)
1620 | {
1621 | printf (" %d |", 8 - (((unsigned) i) >> 3));
1622 | }
1623 | }
1624 |
1625 | if (piece[i] == EMPTY && ((((unsigned) i) >> 3) % 2 == 0 && i % 2 == 0))
1626 | printf (" |");
1627 | else if (piece[i] == EMPTY
1628 | && ((((unsigned) i) >> 3) % 2 != 0 && i % 2 != 0))
1629 | printf (" |");
1630 | else if (piece[i] == EMPTY)
1631 | printf (" |");
1632 | else if (piece[i] == EPS_SQUARE)
1633 | printf (" * |");
1634 | else
1635 | {
1636 | if (color[i] == WHITE)
1637 | printf (" %c |", pieceName[piece[i]]);
1638 | else
1639 | printf ("<%c>|", pieceName[piece[i] + 6]);
1640 | }
1641 | if ((i & 7) == 7)
1642 | printf ("\n");
1643 | }
1644 | printf
1645 | (" +---+---+---+---+---+---+---+---+\n a b c d e f g h\n");
1646 | }
1647 |
1648 |
1649 | /* Returns the number of posible positions to a given depth. Based on the
1650 | perft function on Danasah */
1651 | unsigned long long
1652 | perft (int depth)
1653 | {
1654 | int i;
1655 | int movecnt; /* The number of available moves */
1656 | unsigned long long nodes = 0;
1657 |
1658 | if (!depth)
1659 | return 1;
1660 |
1661 | MOVE moveBuf[200]; /* List of movements */
1662 |
1663 | /* Generate and count all moves for current position */
1664 | movecnt = GenMoves (side, moveBuf);
1665 |
1666 | /* Once we have all the moves available, we loop through them */
1667 | for (i = 0; i < movecnt; ++i)
1668 | {
1669 | /* Not a legal move? Then we unmake it and continue to the next one in the list */
1670 | if (!MakeMove (moveBuf[i]))
1671 | {
1672 | TakeBack ();
1673 | continue;
1674 | }
1675 |
1676 | /* Just in case we want to count for checks */
1677 | // if (IsInCheck(side))
1678 | // {
1679 | // count_checks++;
1680 | // }
1681 |
1682 | /* This 'if' takes us to the deep of the position */
1683 | nodes += perft (depth - 1);
1684 | TakeBack ();
1685 | }
1686 |
1687 | return nodes;
1688 | }
1689 |
1690 |
1691 | /*
1692 | ****************************************************************************
1693 | * Main program *
1694 | ****************************************************************************
1695 | */
1696 |
1697 | void
1698 | startgame ()
1699 | {
1700 | int i;
1701 | for (i = 0; i < 64; ++i)
1702 | {
1703 | piece[i] = init_piece[i];
1704 | color[i] = init_color[i];
1705 | }
1706 |
1707 | side = WHITE;
1708 | computer_side = BLACK; /* Human is white side */
1709 | hdp = 0;
1710 | castle_rights = 15;
1711 | }
1712 |
1713 | void
1714 | xboard ()
1715 | {
1716 | char line[256], command[256], c;
1717 | int from, dest, i;
1718 | MOVE moveBuf[200], bestMove;
1719 | int movecnt;
1720 | //int illegal_king = 0;
1721 |
1722 | printf ("\n");
1723 |
1724 | startgame ();
1725 |
1726 | for (;;)
1727 | {
1728 | fflush (stdout);
1729 | if (side == computer_side)
1730 | { /* computer's turn */
1731 | /* Find out the best move to react the current position */
1732 | bestMove = ComputerThink (max_depth);
1733 | MakeMove (bestMove);
1734 | /* send move */
1735 | switch (bestMove.type)
1736 | {
1737 | case MOVE_TYPE_PROMOTION_TO_QUEEN:
1738 | c = 'q';
1739 | break;
1740 | case MOVE_TYPE_PROMOTION_TO_ROOK:
1741 | c = 'r';
1742 | break;
1743 | case MOVE_TYPE_PROMOTION_TO_BISHOP:
1744 | c = 'b';
1745 | break;
1746 | case MOVE_TYPE_PROMOTION_TO_KNIGHT:
1747 | c = 'n';
1748 | break;
1749 | default:
1750 | c = ' ';
1751 | }
1752 | printf ("move %c%d%c%d%c\n", 'a' + COL (bestMove.from), 8
1753 | - ROW (bestMove.from), 'a' + COL (bestMove.dest), 8
1754 | - ROW (bestMove.dest), c);
1755 | continue;
1756 | }
1757 |
1758 | if (!fgets (line, 256, stdin))
1759 | return;
1760 | if (line[0] == '\n')
1761 | continue;
1762 | sscanf (line, "%s", command);
1763 | if (!strcmp (command, "xboard"))
1764 | {
1765 | continue;
1766 | }
1767 | if (!strcmp (command, "new"))
1768 | {
1769 | startgame ();
1770 | continue;
1771 | }
1772 | if (!strcmp (command, "quit"))
1773 | {
1774 | return;
1775 | }
1776 | if (!strcmp (command, "force"))
1777 | {
1778 | computer_side = EMPTY;
1779 | continue;
1780 | }
1781 | if (!strcmp (command, "white"))
1782 | {
1783 | side = WHITE;
1784 | computer_side = BLACK;
1785 | continue;
1786 | }
1787 | if (!strcmp (command, "black"))
1788 | {
1789 | side = BLACK;
1790 | computer_side = WHITE;
1791 | continue;
1792 | }
1793 | if (!strcmp (command, "sd"))
1794 | {
1795 | sscanf (line, "sd %d", &max_depth);
1796 | continue;
1797 | }
1798 | if (!strcmp (command, "go"))
1799 | {
1800 | computer_side = side;
1801 | continue;
1802 | }
1803 | if (!strcmp (command, "undo"))
1804 | {
1805 | if (hdp == 0)
1806 | continue;
1807 | TakeBack ();
1808 | continue;
1809 | }
1810 | if (!strcmp (command, "remove"))
1811 | {
1812 | if (hdp <= 1)
1813 | continue;
1814 | TakeBack ();
1815 | TakeBack ();
1816 | continue;
1817 | }
1818 |
1819 | /* maybe the user entered a move? */
1820 |
1821 | /* is a move? */
1822 | if (command[0] < 'a' || command[0] > 'h' ||
1823 | command[1] < '0' || command[1] > '9' ||
1824 | command[2] < 'a' || command[2] > 'h' ||
1825 | command[3] < '0' || command[3] > '9')
1826 | {
1827 | printf("Error (unknown command): %s\n", command); /*no move, unknown command */
1828 | continue;
1829 | }
1830 |
1831 | from = command[0] - 'a';
1832 | from += 8 * (8 - (command[1] - '0'));
1833 | dest = command[2] - 'a';
1834 | dest += 8 * (8 - (command[3] - '0'));
1835 | ply = 0;
1836 | movecnt = GenMoves (side, moveBuf);
1837 |
1838 | /* loop through the moves to see if it's legal */
1839 | for (i = 0; i < movecnt; ++i) {
1840 | if (moveBuf[i].from == from && moveBuf[i].dest == dest)
1841 | {
1842 | if (piece[from] == PAWN && (dest < 8 || dest > 55))
1843 | {
1844 | if (command[4] != 'q' && command[4] != 'r' && command[4] != 'b' && command[4] != 'n')
1845 | {
1846 | printf ("Illegal move. Bad letter for promo\n");
1847 | goto goon;
1848 | }
1849 | switch (command[4])
1850 | {
1851 | case 'q':
1852 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
1853 | break;
1854 | case 'r':
1855 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
1856 | break;
1857 | case 'b':
1858 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
1859 | break;
1860 | case 'n':
1861 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
1862 | break;
1863 | }
1864 | }
1865 |
1866 | if (MakeMove (moveBuf[i]))
1867 | {
1868 | goto goon; /* legal move */
1869 | }
1870 | else {
1871 | printf ("Illegal move. King is in check\n");
1872 | goto goon;
1873 | }
1874 | }
1875 | }
1876 | printf ("Illegal move.\n"); /* illegal move */
1877 |
1878 | goon:
1879 | continue;
1880 | }
1881 | }
1882 |
1883 | int
1884 | main ()
1885 | {
1886 |
1887 | setlocale (LC_ALL, "");
1888 |
1889 | /* It mainly calls ComputerThink(maxdepth) to the desired ply */
1890 |
1891 | char s[256];
1892 | int from;
1893 | int dest;
1894 | int i;
1895 | //int computer_side;
1896 |
1897 | startgame ();
1898 |
1899 | max_depth = 4; /* max depth to search */
1900 | MOVE moveBuf[200];
1901 | int movecnt;
1902 |
1903 | puts ("Second Chess, by Emilio Diaz");
1904 | puts (" Help");
1905 | puts (" d: display board");
1906 | puts (" MOVE: make a move (e.g. b1c3, a7a8q, e1g1)");
1907 | puts (" on: force computer to move");
1908 | puts (" quit: exit");
1909 | puts (" sd n: set engine depth to n plies (default 4)");
1910 | puts (" undo: take back last move");
1911 |
1912 | side = WHITE;
1913 | computer_side = BLACK; /* Human is white side */
1914 |
1915 | hdp = 0; /* Current move order */
1916 | for (;;)
1917 | {
1918 | if (side == computer_side)
1919 | { /* Computer's turn */
1920 | /* Find out the best move to react the current position */
1921 | MOVE bestMove = ComputerThink (max_depth);
1922 | MakeMove (bestMove);
1923 | PrintBoard ();
1924 | printf ("CASTLE: %d\n", castle_rights);
1925 | continue;
1926 | }
1927 |
1928 | /* Get user input */
1929 | printf ("sc> ");
1930 | if (scanf ("%s", s) == EOF) /* close program */
1931 | return 0;
1932 | if (!strcmp (s, "d"))
1933 | {
1934 | PrintBoard ();
1935 | continue;
1936 | }
1937 | if (!strcmp (s, "undo"))
1938 | {
1939 | TakeBack ();
1940 | PrintBoard ();
1941 | computer_side = (WHITE + BLACK) - computer_side;
1942 | continue;
1943 | }
1944 | if (!strcmp (s, "xboard"))
1945 | {
1946 | xboard ();
1947 | return 0;
1948 | }
1949 | if (!strcmp (s, "on"))
1950 | {
1951 | computer_side = side;
1952 | continue;
1953 | }
1954 | if (!strcmp (s, "pass"))
1955 | {
1956 | side = (WHITE + BLACK) - side;
1957 | continue;
1958 | }
1959 | if (!strcmp (s, "sd"))
1960 | {
1961 | scanf ("%d", &max_depth);
1962 | continue;
1963 | }
1964 | if (!strcmp (s, "perft"))
1965 | {
1966 | scanf ("%d", &max_depth);
1967 | clock_t start;
1968 | clock_t stop;
1969 | double t = 0.0;
1970 | /* Start timer */
1971 | start = clock ();
1972 | unsigned long long count = perft (max_depth);
1973 | /* Stop timer */
1974 | stop = clock ();
1975 | t = (double) (stop - start) / CLOCKS_PER_SEC;
1976 | printf ("nodes = %llu\n", count);
1977 | printf ("time = %.2f s\n", t);
1978 | double Mnps = (count/t)/1000000;
1979 | printf ("MegaNodes/second = %.2f Mnps\n", Mnps);
1980 | continue;
1981 | }
1982 | if (!strcmp (s, "quit"))
1983 | {
1984 | printf ("Good bye!\n");
1985 | return 0;
1986 | }
1987 |
1988 | /* Maybe the user entered a move? */
1989 | from = s[0] - 'a';
1990 | from += 8 * (8 - (s[1] - '0'));
1991 | dest = s[2] - 'a';
1992 | dest += 8 * (8 - (s[3] - '0'));
1993 | ply = 0;
1994 | movecnt = GenMoves (side, moveBuf);
1995 |
1996 | /* Loop through the moves to see if it's legal */
1997 | for (i = 0; i < movecnt; i++)
1998 | if (moveBuf[i].from == from && moveBuf[i].dest == dest)
1999 | {
2000 | /* Promotion move? */
2001 | if (piece[from] == PAWN && (dest < 8 || dest > 55))
2002 | {
2003 | switch (s[4])
2004 | {
2005 | case 'q':
2006 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
2007 | break;
2008 |
2009 | case 'r':
2010 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
2011 | break;
2012 |
2013 | case 'b':
2014 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
2015 | break;
2016 |
2017 | case 'n':
2018 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
2019 | break;
2020 |
2021 | default:
2022 | puts
2023 | ("promoting to a McGuffin..., I'll give you a queen");
2024 | moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
2025 | }
2026 | }
2027 | if (!MakeMove (moveBuf[i]))
2028 | {
2029 | TakeBack ();
2030 | printf ("Illegal move.\n");
2031 | }
2032 | break;
2033 | }
2034 | PrintBoard ();
2035 | }
2036 | }
2037 |
--------------------------------------------------------------------------------
/secondchessW32.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emdio/secondchess/03c8514fa79f923473150c51b82c9279692ceeb8/secondchessW32.exe
--------------------------------------------------------------------------------