diff -r 9f25df78925e -r 1b12cf799fee test/gs/bigtest.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gs/bigtest.html Mon Apr 24 20:54:38 2023 +0200
@@ -0,0 +1,865 @@
+
+
+
+
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30 #include "rules.h"
+
31 #include "chess.h"
+
32 #include <string.h>
+
33 #include <stdlib.h>
+
34 #include <sys/time.h>
+
35
+
36 static GameState gamestate_copy_sim(GameState *gamestate) {
+
37 GameState simulation = *gamestate;
+
38 if (simulation.lastmove) {
+
39 MoveList *lastmovecopy = malloc(
sizeof(MoveList));
+
40 *lastmovecopy = *(simulation.lastmove);
+
41 simulation.movelist = simulation.lastmove = lastmovecopy;
+
42 }
+
43
+
44 return simulation;
+
45 }
+
46
+
47 void gamestate_init(GameState *gamestate) {
+
48 memset(gamestate,
0,
sizeof(GameState));
+
49
+
50 Board initboard = {
+
51 {
WROOK,
WKNIGHT,
WBISHOP,
WQUEEN,
WKING,
WBISHOP,
WKNIGHT,
WROOK},
+
52 {
WPAWN,
WPAWN,
WPAWN,
WPAWN,
WPAWN,
WPAWN,
WPAWN,
WPAWN},
+
53 {
0,
0,
0,
0,
0,
0,
0,
0},
+
54 {
0,
0,
0,
0,
0,
0,
0,
0},
+
55 {
0,
0,
0,
0,
0,
0,
0,
0},
+
56 {
0,
0,
0,
0,
0,
0,
0,
0},
+
57 {
BPAWN,
BPAWN,
BPAWN,
BPAWN,
BPAWN,
BPAWN,
BPAWN,
BPAWN},
+
58 {
BROOK,
BKNIGHT,
BBISHOP,
BQUEEN,
BKING,
BBISHOP,
BKNIGHT,
BROOK}
+
59 };
+
60 memcpy(gamestate->board, initboard,
sizeof(Board));
+
61 }
+
62
+
63 void gamestate_cleanup(GameState *gamestate) {
+
64 MoveList *elem;
+
65 elem = gamestate->movelist;
+
66 while (elem) {
+
67 MoveList *cur = elem;
+
68 elem = elem->next;
+
69 free(cur);
+
70 };
+
71 }
+
72
+
73
+
74 static void format_move(GameState *gamestate, Move *move) {
+
75 char *string = move->string;
+
76
+
77
+
78 memset(string,
0,
8);
+
79
+
80
+
81 if ((move->piece&
PIECE_MASK) ==
KING &&
+
82 abs(move->tofile-move->fromfile) ==
2) {
+
83 if (move->tofile==fileidx(
'c')) {
+
84 memcpy(string,
"O-O-O",
5);
+
85 }
else {
+
86 memcpy(string,
"O-O",
3);
+
87 }
+
88 }
+
89
+
90
+
91 string[
0] = getpiecechr(move->piece);
+
92 int idx = string[
0] ?
1 :
0;
+
93
+
94
+
95 uint8_t piece = move->piece &
PIECE_MASK;
+
96 if (piece ==
PAWN) {
+
97 if (move->capture) {
+
98 string[idx++] = filechr(move->fromfile);
+
99 }
+
100 }
else if (piece !=
KING) {
+
101 Move threats[
16];
+
102 uint8_t threatcount;
+
103 get_real_threats(gamestate, move->torow, move->tofile,
+
104 move->piece&
COLOR_MASK, threats, &threatcount);
+
105 if (threatcount >
1) {
+
106 int ambrows =
0, ambfiles =
0;
+
107 for (
uint8_t i =
0 ; i < threatcount ; i++) {
+
108 if (threats[i].fromrow == move->fromrow) {
+
109 ambrows++;
+
110 }
+
111 if (threats[i].fromfile == move->fromfile) {
+
112 ambfiles++;
+
113 }
+
114 }
+
115
+
116 if (ambrows >
1) {
+
117 string[idx++] = filechr(move->fromfile);
+
118 }
+
119
+
120 if (ambfiles >
1) {
+
121 string[idx++] = filechr(move->fromrow);
+
122 }
+
123 }
+
124 }
+
125
+
126
+
127 if (move->capture) {
+
128 string[idx++] =
'x';
+
129 }
+
130
+
131
+
132 string[idx++] = filechr(move->tofile);
+
133 string[idx++] = rowchr(move->torow);
+
134
+
135
+
136 if (move->promotion) {
+
137 string[idx++] =
'=';
+
138 string[idx++] = getpiecechr(move->promotion);
+
139 }
+
140
+
141
+
142 if (move->check) {
+
143
+
144 string[idx++] = gamestate->checkmate?
'#':
'+';
+
145 }
+
146 }
+
147
+
148 static void addmove(GameState* gamestate, Move *move) {
+
149 MoveList *elem = malloc(
sizeof(MoveList));
+
150 elem->next =
NULL;
+
151 elem->move = *move;
+
152
+
153 struct timeval curtimestamp;
+
154 gettimeofday(&curtimestamp,
NULL);
+
155 elem->move.timestamp.tv_sec = curtimestamp.tv_sec;
+
156 elem->move.timestamp.tv_usec = curtimestamp.tv_usec;
+
157
+
158 if (gamestate->lastmove) {
+
159 struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp);
+
160 uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec;
+
161 suseconds_t micros;
+
162 if (curtimestamp.tv_usec < lasttstamp->tv_usec) {
+
163 micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec);
+
164 sec--;
+
165 }
else {
+
166 micros = curtimestamp.tv_usec - lasttstamp->tv_usec;
+
167 }
+
168
+
169 elem->move.movetime.tv_sec = sec;
+
170 elem->move.movetime.tv_usec = micros;
+
171
+
172 gamestate->lastmove->next = elem;
+
173 gamestate->lastmove = elem;
+
174 }
else {
+
175 elem->move.movetime.tv_usec =
0;
+
176 elem->move.movetime.tv_sec =
0;
+
177 gamestate->movelist = gamestate->lastmove = elem;
+
178 }
+
179 }
+
180
+
181 char getpiecechr(
uint8_t piece) {
+
182 switch (piece &
PIECE_MASK) {
+
183 case ROOK:
return 'R';
+
184 case KNIGHT:
return 'N';
+
185 case BISHOP:
return 'B';
+
186 case QUEEN:
return 'Q';
+
187 case KING:
return 'K';
+
188 default:
return '\0';
+
189 }
+
190 }
+
191
+
192 uint8_t getpiece(
char c) {
+
193 switch (c) {
+
194 case 'R':
return ROOK;
+
195 case 'N':
return KNIGHT;
+
196 case 'B':
return BISHOP;
+
197 case 'Q':
return QUEEN;
+
198 case 'K':
return KING;
+
199 default:
return 0;
+
200 }
+
201 }
+
202
+
203 static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) {
+
204 uint8_t piece = move->piece &
PIECE_MASK;
+
205 uint8_t color = move->piece &
COLOR_MASK;
+
206
+
207
+
208 if (move->capture && piece ==
PAWN &&
+
209 mdst(gamestate->board, move) ==
0) {
+
210 gamestate->board[move->fromrow][move->tofile] =
0;
+
211 }
+
212
+
213
+
214 for (
uint8_t file =
0 ; file <
8 ; file++) {
+
215 gamestate->board[
3][file] &= ~
ENPASSANT_THREAT;
+
216 gamestate->board[
4][file] &= ~
ENPASSANT_THREAT;
+
217 }
+
218
+
219
+
220 if (piece ==
PAWN && (
+
221 (move->fromrow ==
1 && move->torow ==
3) ||
+
222 (move->fromrow ==
6 && move->torow ==
4))) {
+
223 move->piece |=
ENPASSANT_THREAT;
+
224 }
+
225
+
226
+
227 msrc(gamestate->board, move) =
0;
+
228 if (move->promotion) {
+
229 mdst(gamestate->board, move) = move->promotion;
+
230 }
else {
+
231 mdst(gamestate->board, move) = move->piece;
+
232 }
+
233
+
234
+
235 if (piece ==
KING && move->fromfile == fileidx(
'e')) {
+
236
+
237 if (move->tofile == fileidx(
'g')) {
+
238 gamestate->board[move->torow][fileidx(
'h')] =
0;
+
239 gamestate->board[move->torow][fileidx(
'f')] = color|
ROOK;
+
240 }
else if (move->tofile == fileidx(
'c')) {
+
241 gamestate->board[move->torow][fileidx(
'a')] =
0;
+
242 gamestate->board[move->torow][fileidx(
'd')] = color|
ROOK;
+
243 }
+
244 }
+
245
+
246 if (!simulate) {
+
247 if (!move->string[
0]) {
+
248 format_move(gamestate, move);
+
249 }
+
250 }
+
251
+
252 addmove(gamestate, move);
+
253 }
+
254
+
255 void apply_move(GameState *gamestate, Move *move) {
+
256 apply_move_impl(gamestate, move,
0);
+
257 }
+
258
+
259 static int validate_move_rules(GameState *gamestate, Move *move) {
+
260
+
261 if (!chkidx(move)) {
+
262 return INVALID_POSITION;
+
263 }
+
264
+
265
+
266 if (move->fromfile == move->tofile && move->fromrow == move->torow) {
+
267 return INVALID_MOVE_SYNTAX;
+
268 }
+
269
+
270
+
271 if ((msrc(gamestate->board, move)&(
PIECE_MASK|
COLOR_MASK))
+
272 != (move->piece&(
PIECE_MASK|
COLOR_MASK))) {
+
273 return INVALID_POSITION;
+
274 }
+
275
+
276
+
277 if ((mdst(gamestate->board, move) &
COLOR_MASK)
+
278 == (move->piece &
COLOR_MASK)) {
+
279 return RULES_VIOLATED;
+
280 }
+
281
+
282
+
283 if ((mdst(gamestate->board, move) ==
0 && move->capture) ||
+
284 (mdst(gamestate->board, move) !=
0 && !move->capture)) {
+
285 return INVALID_MOVE_SYNTAX;
+
286 }
+
287
+
288
+
289 _Bool chkrules;
+
290 switch (move->piece &
PIECE_MASK) {
+
291 case PAWN:
+
292 chkrules = pawn_chkrules(gamestate, move) &&
+
293 !pawn_isblocked(gamestate, move);
+
294 break;
+
295 case ROOK:
+
296 chkrules = rook_chkrules(move) &&
+
297 !rook_isblocked(gamestate, move);
+
298 break;
+
299 case KNIGHT:
+
300 chkrules = knight_chkrules(move);
+
301 break;
+
302 case BISHOP:
+
303 chkrules = bishop_chkrules(move) &&
+
304 !bishop_isblocked(gamestate, move);
+
305 break;
+
306 case QUEEN:
+
307 chkrules = queen_chkrules(move) &&
+
308 !queen_isblocked(gamestate, move);
+
309 break;
+
310 case KING:
+
311 chkrules = king_chkrules(gamestate, move) &&
+
312 !king_isblocked(gamestate, move);
+
313 break;
+
314 default:
+
315 return INVALID_MOVE_SYNTAX;
+
316 }
+
317
+
318 return chkrules ?
VALID_MOVE_SEMANTICS :
RULES_VIOLATED;
+
319 }
+
320
+
321 int validate_move(GameState *gamestate, Move *move) {
+
322
+
323 int result = validate_move_rules(gamestate, move);
+
324
+
325
+
326 if (result !=
VALID_MOVE_SEMANTICS) {
+
327 return result;
+
328 }
+
329
+
330
+
331 uint8_t piececolor = (move->piece &
COLOR_MASK);
+
332
+
333 uint8_t mykingfile =
0, mykingrow =
0, opkingfile =
0, opkingrow =
0;
+
334 for (
uint8_t row =
0 ; row <
8 ; row++) {
+
335 for (
uint8_t file =
0 ; file <
8 ; file++) {
+
336 if (gamestate->board[row][file] ==
+
337 (piececolor ==
WHITE?
WKING:
BKING)) {
+
338 mykingfile = file;
+
339 mykingrow = row;
+
340 }
else if (gamestate->board[row][file] ==
+
341 (piececolor ==
WHITE?
BKING:
WKING)) {
+
342 opkingfile = file;
+
343 opkingrow = row;
+
344 }
+
345 }
+
346 }
+
347
+
348
+
349 GameState simulation = gamestate_copy_sim(gamestate);
+
350 Move simmove = *move;
+
351 apply_move_impl(&simulation, &simmove,
1);
+
352
+
353
+
354 if (is_covered(&simulation, mykingrow, mykingfile,
+
355 opponent_color(piececolor))) {
+
356
+
357 gamestate_cleanup(&simulation);
+
358 if ((move->piece &
PIECE_MASK) ==
KING) {
+
359 return KING_MOVES_INTO_CHECK;
+
360 }
else {
+
361
+
362 return gamestate->lastmove->move.check ?
+
363 KING_IN_CHECK :
PIECE_PINNED;
+
364 }
+
365 }
+
366
+
367
+
368 Move threats[
16];
+
369 uint8_t threatcount;
+
370 move->check = get_threats(&simulation, opkingrow, opkingfile,
+
371 piececolor, threats, &threatcount);
+
372
+
373 if (move->check) {
+
374
+
375 _Bool canescape =
0;
+
376 for (
int dr = -
1 ; dr <=
1 && !canescape ; dr++) {
+
377 for (
int df = -
1 ; df <=
1 && !canescape ; df++) {
+
378 if (!(dr ==
0 && df ==
0) &&
+
379 isidx(opkingrow + dr) && isidx(opkingfile + df)) {
+
380
+
381
+
382 if ((simulation.board[opkingrow + dr][opkingfile + df]
+
383 &
COLOR_MASK) != opponent_color(piececolor)) {
+
384 canescape |= !is_covered(&simulation,
+
385 opkingrow + dr, opkingfile + df, piececolor);
+
386 }
+
387 }
+
388 }
+
389 }
+
390
+
391 if (!canescape && threatcount ==
1) {
+
392 canescape = is_attacked(&simulation, threats[
0].fromrow,
+
393 threats[
0].fromfile, opponent_color(piececolor));
+
394 }
+
395
+
396
+
397 if (!canescape && threatcount ==
1) {
+
398 Move *threat = &(threats[
0]);
+
399 uint8_t threatpiece = threat->piece &
PIECE_MASK;
+
400
+
401
+
402 if (threatpiece ==
BISHOP || threatpiece ==
ROOK
+
403 || threatpiece ==
QUEEN) {
+
404 if (threat->fromrow == threat->torow) {
+
405
+
406 int d = threat->tofile > threat->fromfile ?
1 : -
1;
+
407 uint8_t file = threat->fromfile;
+
408 while (!canescape && file != threat->tofile - d) {
+
409 file += d;
+
410 canescape |= is_protected(&simulation,
+
411 threat->torow, file, opponent_color(piececolor));
+
412 }
+
413 }
else if (threat->fromfile == threat->tofile) {
+
414
+
415 int d = threat->torow > threat->fromrow ?
1 : -
1;
+
416 uint8_t row = threat->fromrow;
+
417 while (!canescape && row != threat->torow - d) {
+
418 row += d;
+
419 canescape |= is_protected(&simulation,
+
420 row, threat->tofile, opponent_color(piececolor));
+
421 }
+
422 }
else {
+
423
+
424 int dr = threat->torow > threat->fromrow ?
1 : -
1;
+
425 int df = threat->tofile > threat->fromfile ?
1 : -
1;
+
426
+
427 uint8_t row = threat->fromrow;
+
428 uint8_t file = threat->fromfile;
+
429 while (!canescape && file != threat->tofile - df
+
430 && row != threat->torow - dr) {
+
431 row += dr;
+
432 file += df;
+
433 canescape |= is_protected(&simulation, row, file,
+
434 opponent_color(piececolor));
+
435 }
+
436 }
+
437 }
+
438 }
+
439
+
440 if (!canescape) {
+
441 gamestate->checkmate =
1;
+
442 }
+
443 }
+
444
+
445 gamestate_cleanup(&simulation);
+
446
+
447 return VALID_MOVE_SEMANTICS;
+
448 }
+
449
+
450 _Bool get_threats(GameState *gamestate,
uint8_t row,
uint8_t file,
+
451 uint8_t color, Move *threats,
uint8_t *threatcount) {
+
452 Move candidates[
32];
+
453 int candidatecount =
0;
+
454 for (
uint8_t r =
0 ; r <
8 ; r++) {
+
455 for (
uint8_t f =
0 ; f <
8 ; f++) {
+
456 if ((gamestate->board[r][f] &
COLOR_MASK) == color) {
+
457
+
458 memset(&(candidates[candidatecount]),
0,
sizeof(Move));
+
459 candidates[candidatecount].piece = gamestate->board[r][f];
+
460 candidates[candidatecount].fromrow = r;
+
461 candidates[candidatecount].fromfile = f;
+
462 candidates[candidatecount].torow = row;
+
463 candidates[candidatecount].tofile = file;
+
464 candidatecount++;
+
465
+
466
+
467 memcpy(&(candidates[candidatecount]),
+
468 &(candidates[candidatecount-
1]),
sizeof(Move));
+
469 candidates[candidatecount].capture =
1;
+
470 candidatecount++;
+
471 }
+
472 }
+
473 }
+
474
+
475 if (threatcount) {
+
476 *threatcount =
0;
+
477 }
+
478
+
479
+
480 _Bool result =
0;
+
481
+
482 for (
int i =
0 ; i < candidatecount ; i++) {
+
483 if (validate_move_rules(gamestate, &(candidates[i]))
+
484 ==
VALID_MOVE_SEMANTICS) {
+
485 result =
1;
+
486 if (threats && threatcount) {
+
487 threats[(*threatcount)++] = candidates[i];
+
488 }
+
489 }
+
490 }
+
491
+
492 return result;
+
493 }
+
494
+
495 _Bool is_pinned(GameState *gamestate, Move *move) {
+
496 uint8_t color = move->piece &
COLOR_MASK;
+
497
+
498 uint8_t kingfile =
0, kingrow =
0;
+
499 for (
uint8_t row =
0 ; row <
8 ; row++) {
+
500 for (
uint8_t file =
0 ; file <
8 ; file++) {
+
501 if (gamestate->board[row][file] == (color|
KING)) {
+
502 kingfile = file;
+
503 kingrow = row;
+
504 }
+
505 }
+
506 }
+
507
+
508 GameState simulation = gamestate_copy_sim(gamestate);
+
509 Move simmove = *move;
+
510 apply_move(&simulation, &simmove);
+
511 _Bool covered = is_covered(&simulation,
+
512 kingrow, kingfile, opponent_color(color));
+
513 gamestate_cleanup(&simulation);
+
514
+
515 return covered;
+
516 }
+
517
+
518 _Bool get_real_threats(GameState *gamestate,
uint8_t row,
uint8_t file,
+
519 uint8_t color, Move *threats,
uint8_t *threatcount) {
+
520
+
521 if (threatcount) {
+
522 *threatcount =
0;
+
523 }
+
524
+
525 Move candidates[
16];
+
526 uint8_t candidatecount;
+
527 if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) {
+
528
+
529 _Bool result =
0;
+
530 uint8_t kingfile =
0, kingrow =
0;
+
531 for (
uint8_t row =
0 ; row <
8 ; row++) {
+
532 for (
uint8_t file =
0 ; file <
8 ; file++) {
+
533 if (gamestate->board[row][file] == (color|
KING)) {
+
534 kingfile = file;
+
535 kingrow = row;
+
536 }
+
537 }
+
538 }
+
539
+
540 for (
uint8_t i =
0 ; i < candidatecount ; i++) {
+
541 GameState simulation = gamestate_copy_sim(gamestate);
+
542 Move simmove = candidates[i];
+
543 apply_move(&simulation, &simmove);
+
544 if (!is_covered(&simulation, kingrow, kingfile,
+
545 opponent_color(color))) {
+
546 result =
1;
+
547 if (threats && threatcount) {
+
548 threats[(*threatcount)++] = candidates[i];
+
549 }
+
550 }
+
551 }
+
552
+
553 return result;
+
554 }
else {
+
555 return 0;
+
556 }
+
557 }
+
558
+
559 static int getlocation(GameState *gamestate, Move *move) {
+
560
+
561 uint8_t color = move->piece &
COLOR_MASK;
+
562 _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:
0;
+
563
+
564 Move threats[
16], *threat =
NULL;
+
565 uint8_t threatcount;
+
566
+
567 if (get_threats(gamestate, move->torow, move->tofile, color,
+
568 threats, &threatcount)) {
+
569
+
570 int reason =
INVALID_POSITION;
+
571
+
572
+
573 for (
uint8_t i =
0 ; i < threatcount ; i++) {
+
574 if ((threats[i].piece & (
PIECE_MASK |
COLOR_MASK))
+
575 == move->piece &&
+
576 (move->fromrow ==
POS_UNSPECIFIED ||
+
577 move->fromrow == threats[i].fromrow) &&
+
578 (move->fromfile ==
POS_UNSPECIFIED ||
+
579 move->fromfile == threats[i].fromfile)) {
+
580
+
581 if (threat) {
+
582 return AMBIGUOUS_MOVE;
+
583 }
else {
+
584
+
585 if (is_pinned(gamestate, &(threats[i]))) {
+
586 reason = incheck?
KING_IN_CHECK:
PIECE_PINNED;
+
587 }
else {
+
588 threat = &(threats[i]);
+
589 }
+
590 }
+
591 }
+
592 }
+
593
+
594
+
595 if (!threat) {
+
596 return reason;
+
597 }
+
598
+
599 memcpy(move, threat,
sizeof(Move));
+
600 return VALID_MOVE_SYNTAX;
+
601 }
else {
+
602 return INVALID_POSITION;
+
603 }
+
604 }
+
605
+
606 int eval_move(GameState *gamestate,
char *mstr, Move *move,
uint8_t color) {
+
607 memset(move,
0,
sizeof(Move));
+
608 move->fromfile =
POS_UNSPECIFIED;
+
609 move->fromrow =
POS_UNSPECIFIED;
+
610
+
611 size_t len = strlen(mstr);
+
612 if (len <
1 || len >
6) {
+
613 return INVALID_MOVE_SYNTAX;
+
614 }
+
615
+
616
+
617 if (mstr[len-
1] ==
'+') {
+
618 len--; mstr[len] =
'\0';
+
619 move->check =
1;
+
620 }
else if (mstr[len-
1] ==
'#') {
+
621 len--; mstr[len] =
'\0';
+
622
+
623 }
+
624
+
625
+
626 if (len >
3 && mstr[len-
2] ==
'=') {
+
627 move->promotion = getpiece(mstr[len-
1]);
+
628 if (!move->promotion) {
+
629 return INVALID_MOVE_SYNTAX;
+
630 }
else {
+
631 move->promotion |= color;
+
632 len -=
2;
+
633 mstr[len] =
0;
+
634 }
+
635 }
+
636
+
637 if (len ==
2) {
+
638
+
639 move->piece =
PAWN;
+
640 move->tofile = fileidx(mstr[
0]);
+
641 move->torow = rowidx(mstr[
1]);
+
642 }
else if (len ==
3) {
+
643 if (strcmp(mstr,
"O-O") ==
0) {
+
644
+
645 move->piece =
KING;
+
646 move->fromfile = fileidx(
'e');
+
647 move->tofile = fileidx(
'g');
+
648 move->fromrow = move->torow = color ==
WHITE ?
0 :
7;
+
649 }
else {
+
650
+
651 move->piece = getpiece(mstr[
0]);
+
652 move->tofile = fileidx(mstr[
1]);
+
653 move->torow = rowidx(mstr[
2]);
+
654 }
+
655 }
else if (len ==
4) {
+
656 move->piece = getpiece(mstr[
0]);
+
657 if (!move->piece) {
+
658 move->piece =
PAWN;
+
659 move->fromfile = fileidx(mstr[
0]);
+
660 }
+
661 if (mstr[
1] ==
'x') {
+
662
+
663 move->capture =
1;
+
664 }
else {
+
665
+
666 if (isfile(mstr[
1])) {
+
667 move->fromfile = fileidx(mstr[
1]);
+
668 if (move->piece ==
PAWN) {
+
669 move->piece =
0;
+
670 }
+
671 }
else {
+
672 move->fromrow = rowidx(mstr[
1]);
+
673 }
+
674 }
+
675 move->tofile = fileidx(mstr[
2]);
+
676 move->torow = rowidx(mstr[
3]);
+
677 }
else if (len ==
5) {
+
678 if (strcmp(mstr,
"O-O-O") ==
0) {
+
679
+
680 move->piece =
KING;
+
681 move->fromfile = fileidx(
'e');
+
682 move->tofile = fileidx(
'c');
+
683 move->fromrow = move->torow = color ==
WHITE ?
0 :
7;
+
684 }
else {
+
685 move->piece = getpiece(mstr[
0]);
+
686 if (mstr[
2] ==
'x') {
+
687 move->capture =
1;
+
688 if (move->piece) {
+
689
+
690 move->fromfile = fileidx(mstr[
1]);
+
691 }
else {
+
692
+
693 move->piece =
PAWN;
+
694 move->fromfile = fileidx(mstr[
0]);
+
695 move->fromrow = rowidx(mstr[
1]);
+
696 }
+
697 }
else {
+
698
+
699 move->fromfile = fileidx(mstr[
1]);
+
700 move->fromrow = rowidx(mstr[
2]);
+
701 }
+
702 move->tofile = fileidx(mstr[
3]);
+
703 move->torow = rowidx(mstr[
4]);
+
704 }
+
705 }
else if (len ==
6) {
+
706
+
707 if (mstr[
3] ==
'x') {
+
708 move->capture =
1;
+
709 move->piece = getpiece(mstr[
0]);
+
710 move->fromfile = fileidx(mstr[
1]);
+
711 move->fromrow = rowidx(mstr[
2]);
+
712 move->tofile = fileidx(mstr[
4]);
+
713 move->torow = rowidx(mstr[
5]);
+
714 }
+
715 }
+
716
+
717
+
718 if (move->piece) {
+
719 if (move->piece ==
PAWN
+
720 && move->torow == (color==
WHITE?
7:
0)
+
721 && !move->promotion) {
+
722 return NEED_PROMOTION;
+
723 }
+
724
+
725 move->piece |= color;
+
726 if (move->fromfile ==
POS_UNSPECIFIED
+
727 || move->fromrow ==
POS_UNSPECIFIED) {
+
728 return getlocation(gamestate, move);
+
729 }
else {
+
730 return chkidx(move) ?
VALID_MOVE_SYNTAX :
INVALID_POSITION;
+
731 }
+
732 }
else {
+
733 return INVALID_MOVE_SYNTAX;
+
734 }
+
735 }
+
736
+
737 _Bool is_protected(GameState *gamestate,
uint8_t row,
uint8_t file,
+
738 uint8_t color) {
+
739
+
740 Move threats[
16];
+
741 uint8_t threatcount;
+
742 if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) {
+
743 for (
int i =
0 ; i < threatcount ; i++) {
+
744 if (threats[i].piece != (color|
KING)) {
+
745 return 1;
+
746 }
+
747 }
+
748 return 0;
+
749 }
else {
+
750 return 0;
+
751 }
+
752 }
+
753
+
754 uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate,
+
755 uint8_t color) {
+
756 if (!gameinfo->timecontrol) {
+
757 return 0;
+
758 }
+
759
+
760 if (gamestate->movelist) {
+
761 uint16_t time = gameinfo->time;
+
762 suseconds_t micros =
0;
+
763
+
764 MoveList *movelist = color ==
WHITE ?
+
765 gamestate->movelist : gamestate->movelist->next;
+
766
+
767 while (movelist) {
+
768 time += gameinfo->addtime;
+
769
+
770 struct movetimeval *movetime = &(movelist->move.movetime);
+
771 if (movetime->tv_sec >= time) {
+
772 return 0;
+
773 }
+
774
+
775 time -= movetime->tv_sec;
+
776 micros += movetime->tv_usec;
+
777
+
778 movelist = movelist->next ? movelist->next->next :
NULL;
+
779 }
+
780
+
781 time_t sec;
+
782 movelist = gamestate->lastmove;
+
783 if ((movelist->move.piece &
COLOR_MASK) != color) {
+
784 struct movetimeval *lastmovetstamp = &(movelist->move.timestamp);
+
785 struct timeval currenttstamp;
+
786 gettimeofday(¤ttstamp,
NULL);
+
787 micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec;
+
788 sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec;
+
789 if (sec >= time) {
+
790 return 0;
+
791 }
+
792
+
793 time -= sec;
+
794 }
+
795
+
796 sec = micros / 1e6L;
+
797
+
798 if (sec >= time) {
+
799 return 0;
+
800 }
+
801
+
802 time -= sec;
+
803
+
804 return time;
+
805 }
else {
+
806 return gameinfo->time;
+
807 }
+
808 }
+
+
+
+