1 #include "includes.h"
2 #include "knightcap.h"
3
4 #define ADD_GEN(to) \
5 { \
6 b->topieces[to] |= mask; \
7 }
8
9 #if USE_SLIDING_CONTROL
10 #define XRAY_ADD_GEN(to) \
11 { \
12 b->xray_topieces[to] |= mask; \
13 }
14
15
16 /* returns a mask of all the pieces that have an xray attack on
17 sq2 through sq1 */
xray_attack(Position * b,Square sq1,Square sq2)18 static inline uint32 xray_attack(Position *b, Square sq1, Square sq2)
19 {
20 uint32 mask;
21 unsigned dir = sliding_map[sq1][sq2];
22
23 if (dir == 0)
24 return 0;
25
26 /* first look for all pieces that directly attack sq1 and
27 xray attack sq2. to be sure in the case of queens, you need to
28 check for xray attacks on 2 adjacent squares when sq1 and sq2 are
29 not themselves adjacent */
30 if (sq2 - dir != sq1) {
31 mask = (b->topieces[sq1] &
32 b->xray_topieces[sq2] &
33 b->xray_topieces[sq2-dir]);
34 } else {
35 mask = (b->topieces[sq1] &
36 b->xray_topieces[sq2]);
37 }
38
39 /* the next bit is a hack for R---Q---R(sq1)--sq2 type combinations.
40 The signature we use for this is sq2 being xrayed by a major piece
41 through sq1 (which has already been detected in mask). Then we just
42 include any other major piece of the same colour that xray attacks
43 square 2. */
44 if (mask & MAJOR_MASK) {
45 if (is_white(b->board[sq1])) {
46 mask |= b->xray_topieces[sq2] & WMAJOR_MASK;
47 } else {
48 mask |= b->xray_topieces[sq2] & BMAJOR_MASK;
49 }
50 }
51
52 return mask;
53 }
54
55 /* this tells us whether there is a piece at sq2
56 that would block a sliding xray coming from sq1.
57 if either suqare doesn't have a piece we
58 just answer "no" */
xray_through(Position * b,Square sq1,Square sq2)59 static inline int xray_through(Position *b, Square sq1, Square sq2)
60 {
61 Piece piece1 = b->board[sq1], piece2 = b->board[sq2];
62
63 if (!piece1 || !piece2)
64 return 1;
65 return ((b->sliding_mask & (1<<b->pboard[sq2])) &&
66 same_color(piece1, piece2) &&
67 capture_map[KING+piece2][sq2][sq1]);
68 }
69
70 #else
71
72
old_bishop_generate(Position * b,int pi)73 static void old_bishop_generate(Position *b, int pi)
74 {
75 uint32 mask = (1<<pi);
76 PieceStruct *p = &b->pieces[pi];
77 Square from = p->pos;
78 int x = XPOS(from);
79 int y = YPOS(from);
80 int l;
81 Square to;
82
83 l = imin(7-x, 7-y);
84 to = from + NORTH_EAST;
85
86 while (l--) {
87 ADD_GEN(to);
88 if (b->board[to]) break;
89 to += NORTH_EAST;
90 }
91
92 l = imin(x, 7-y);
93 to = from + NORTH_WEST;
94
95 while (l--) {
96 ADD_GEN(to);
97 if (b->board[to]) break;
98 to += NORTH_WEST;
99 }
100
101 l = imin(x, y);
102 to = from + SOUTH_WEST;
103
104 while (l--) {
105 ADD_GEN(to);
106 if (b->board[to]) break;
107 to += SOUTH_WEST;
108 }
109
110 l = imin(7-x, y);
111 to = from + SOUTH_EAST;
112
113 while (l--) {
114 ADD_GEN(to);
115 if (b->board[to]) break;
116 to += SOUTH_EAST;
117 }
118 }
119
120
old_rook_generate(Position * b,int pi)121 static void old_rook_generate(Position *b, int pi)
122 {
123 uint32 mask = (1<<pi);
124 PieceStruct *p = &b->pieces[pi];
125 Square from = p->pos;
126 int x = XPOS(from);
127 int y = YPOS(from);
128 int l;
129 Square to;
130
131 l = 7-y;
132 to = from + NORTH;
133
134 while (l--) {
135 ADD_GEN(to);
136 if (b->board[to]) break;
137 to += NORTH;
138 }
139
140 l = x;
141 to = from + WEST;
142
143 while (l--) {
144 ADD_GEN(to);
145 if (b->board[to]) break;
146 to += WEST;
147 }
148
149 l = y;
150 to = from + SOUTH;
151
152 while (l--) {
153 ADD_GEN(to);
154 if (b->board[to]) break;
155 to += SOUTH;
156 }
157
158 l = 7-x;
159 to = from + EAST;
160
161 while (l--) {
162 ADD_GEN(to);
163 if (b->board[to]) break;
164 to += EAST;
165 }
166 }
167
168 #endif
169
pawn_generate(Position * b,int pi)170 static void pawn_generate(Position *b, int pi)
171 {
172 uint32 mask = (1<<pi);
173 PieceStruct *p = &b->pieces[pi];
174 Square from = p->pos;
175 int x = XPOS(from);
176
177 if (p->p > 0) {
178 /* white pawns */
179 if (x != 0) {
180 ADD_GEN(from + NORTH_WEST);
181 }
182 if (x != 7) {
183 ADD_GEN(from + NORTH_EAST);
184 }
185 } else {
186 /* black panws */
187 if (x != 0) {
188 ADD_GEN(from + SOUTH_WEST);
189 }
190 if (x != 7) {
191 ADD_GEN(from + SOUTH_EAST);
192 }
193 }
194 }
195
196
bishop_generate(Position * b,int pi)197 static void bishop_generate(Position *b, int pi)
198 {
199 #if !USE_SLIDING_CONTROL
200 old_bishop_generate(b, pi);
201 return;
202 #else
203 uint32 mask = (1<<pi);
204 PieceStruct *p = &b->pieces[pi];
205 Square from = p->pos;
206 int x = XPOS(from);
207 int y = YPOS(from);
208 int l;
209 Square to;
210
211 l = imin(7-x, 7-y);
212 to = from + NORTH_EAST;
213
214 while (l--) {
215 ADD_GEN(to);
216 if (b->board[to]) break;
217 to += NORTH_EAST;
218 }
219
220 if (l>0) {
221 while (l-- && xray_through(b,from,to)) {
222 to += NORTH_EAST;
223 XRAY_ADD_GEN(to);
224 }
225 }
226
227 l = imin(x, 7-y);
228 to = from + NORTH_WEST;
229
230 while (l--) {
231 ADD_GEN(to);
232 if (b->board[to]) break;
233 to += NORTH_WEST;
234 }
235
236 if (l>0) {
237 while (l-- && xray_through(b,from,to)) {
238 to += NORTH_WEST;
239 XRAY_ADD_GEN(to);
240 }
241 }
242
243 l = imin(x, y);
244 to = from + SOUTH_WEST;
245
246 while (l--) {
247 ADD_GEN(to);
248 if (b->board[to]) break;
249 to += SOUTH_WEST;
250 }
251
252 if (l>0) {
253 while (l-- && xray_through(b,from,to)) {
254 to += SOUTH_WEST;
255 XRAY_ADD_GEN(to);
256 }
257 }
258
259 l = imin(7-x, y);
260 to = from + SOUTH_EAST;
261
262 while (l--) {
263 ADD_GEN(to);
264 if (b->board[to]) break;
265 to += SOUTH_EAST;
266 }
267
268 if (l>0) {
269 while (l-- && xray_through(b,from,to)) {
270 to += SOUTH_EAST;
271 XRAY_ADD_GEN(to);
272 }
273 }
274 #endif
275 }
276
277
rook_generate(Position * b,int pi)278 static void rook_generate(Position *b, int pi)
279 {
280 #if !USE_SLIDING_CONTROL
281 old_rook_generate(b, pi);
282 return;
283 #else
284 uint32 mask = (1<<pi);
285 PieceStruct *p = &b->pieces[pi];
286 Square from = p->pos;
287 int x = XPOS(from);
288 int y = YPOS(from);
289 int l;
290 Square to;
291
292 l = 7-y;
293 to = from + NORTH;
294
295 while (l--) {
296 ADD_GEN(to);
297 if (b->board[to]) break;
298 to += NORTH;
299 }
300
301 if (l>0) {
302 while (l-- && xray_through(b, from, to)) {
303 to += NORTH;
304 XRAY_ADD_GEN(to);
305 }
306 }
307
308 l = x;
309 to = from + WEST;
310
311 while (l--) {
312 ADD_GEN(to);
313 if (b->board[to]) break;
314 to += WEST;
315 }
316
317 if (l>0) {
318 while (l-- && xray_through(b, from, to)) {
319 to += WEST;
320 XRAY_ADD_GEN(to);
321 }
322 }
323
324 l = y;
325 to = from + SOUTH;
326
327 while (l--) {
328 ADD_GEN(to);
329 if (b->board[to]) break;
330 to += SOUTH;
331 }
332
333 if (l>0) {
334 while (l-- && xray_through(b, from, to)) {
335 to += SOUTH;
336 XRAY_ADD_GEN(to);
337 }
338 }
339
340 l = 7-x;
341 to = from + EAST;
342
343 while (l--) {
344 ADD_GEN(to);
345 if (b->board[to]) break;
346 to += EAST;
347 }
348
349 if (l>0) {
350 while (l-- && xray_through(b, from, to)) {
351 to += EAST;
352 XRAY_ADD_GEN(to);
353 }
354 }
355 #endif
356 }
357
358
knight_generate(Position * b,int pi)359 static void knight_generate(Position *b, int pi)
360 {
361 uint32 mask = (1<<pi);
362 PieceStruct *p = &b->pieces[pi];
363 Square from = p->pos;
364 int x = XPOS(from);
365 int y = YPOS(from);
366 Square to;
367
368 if (x == 7) goto west;
369
370 if (y<6) {
371 to = from + 2*NORTH + EAST;
372 ADD_GEN(to);
373 }
374
375 if (y>1) {
376 to = from + EAST + 2*SOUTH;
377 ADD_GEN(to);
378 }
379
380 if (x == 6) goto west;
381
382 if (y<7) {
383 to = from + NORTH + 2*EAST;
384 ADD_GEN(to);
385 }
386
387 if (y>0) {
388 to = from + SOUTH + 2*EAST;
389 ADD_GEN(to);
390 }
391
392 west:
393 if (x == 0) return;
394
395 if (y>1) {
396 to = from + WEST + 2*SOUTH;
397 ADD_GEN(to);
398 }
399
400 if (y<6) {
401 to = from + WEST + 2*NORTH;
402 ADD_GEN(to);
403 }
404
405 if (x == 1) return;
406
407 if (y>0) {
408 to = from + 2*WEST + SOUTH;
409 ADD_GEN(to);
410 }
411
412 if (y<7) {
413 to = from + 2*WEST + NORTH;
414 ADD_GEN(to);
415 }
416 }
417
418
king_generate(Position * b,int pi)419 static void king_generate(Position *b, int pi)
420 {
421 uint32 mask = (1<<pi);
422 PieceStruct *p = &b->pieces[pi];
423 Square from = p->pos;
424 int x = XPOS(from);
425 int y = YPOS(from);
426 Square to;
427
428 if (x != 0) {
429 to = from + WEST;
430 ADD_GEN(to);
431 }
432
433 if (x != 7) {
434 to = from + EAST;
435 ADD_GEN(to);
436 }
437
438 if (y == 7) goto south;
439
440 if (x != 0) {
441 to = from + NORTH_WEST;
442 ADD_GEN(to);
443 }
444
445 if (x != 7) {
446 to = from + NORTH_EAST;
447 ADD_GEN(to);
448 }
449
450 to = from + NORTH;
451 ADD_GEN(to);
452
453 south:
454 if (y == 0) return;
455
456 if (x != 0) {
457 to = from + SOUTH_WEST;
458 ADD_GEN(to);
459 }
460
461 if (x != 7) {
462 to = from + SOUTH_EAST;
463 ADD_GEN(to);
464 }
465
466 to = from + SOUTH;
467 ADD_GEN(to);
468 }
469
470
queen_generate(Position * b,int pi)471 static void queen_generate(Position *b, int pi)
472 {
473 rook_generate(b, pi);
474 bishop_generate(b, pi);
475 }
476
477
piece_generate(Position * b,int pi)478 static void piece_generate(Position *b, int pi)
479 {
480 b->piece_change |= (1<<pi);
481
482 switch (abs(b->pieces[pi].p)) {
483 case PAWN:
484 pawn_generate(b, pi);
485 break;
486
487 case BISHOP:
488 bishop_generate(b, pi);
489 break;
490
491 case KNIGHT:
492 knight_generate(b, pi);
493 break;
494
495 case ROOK:
496 rook_generate(b, pi);
497 break;
498
499 case QUEEN:
500 queen_generate(b, pi);
501 break;
502
503 case KING:
504 king_generate(b, pi);
505 break;
506
507 default:
508 lprintf(0, "unknown pi %d p=%d pos=%s in piece_generate\n",
509 pi, b->pieces[pi].p, posstr(b->pieces[pi].pos));
510 break;
511 }
512 }
513
old_update_moves(Position * b,Position * oldb,Move * move)514 void old_update_moves(Position *b, Position *oldb, Move *move)
515 {
516 unsigned pi, dir;
517 uint32 mask_from, mask_to, mask;
518 Square pos, p2;
519
520 /* wipe the piece that is moving */
521 mask = (1<<oldb->pboard[move->from]);
522
523 /* a piece being captured - always wipe */
524 if (oldb->pboard[move->to] != -1) {
525 mask |= (1<<oldb->pboard[move->to]);
526 }
527
528 mask = ~mask;
529
530 for (pos=A1;pos<=H8;pos+=4) {
531 b->topieces[pos] = oldb->topieces[pos] & mask;
532 b->topieces[pos+1] = oldb->topieces[pos+1] & mask;
533 b->topieces[pos+2] = oldb->topieces[pos+2] & mask;
534 b->topieces[pos+3] = oldb->topieces[pos+3] & mask;
535 }
536
537 mask_from = b->topieces[move->from] & b->sliding_mask;
538 mask_to = b->topieces[move->to] & b->sliding_mask;
539
540 /* sliding pieces that can move to the from square */
541 mask = mask_from;
542 while (mask) {
543 pi = ff_one(mask);
544 mask &= ~(1<<pi);
545
546 pos = b->pieces[pi].pos;
547
548 if (same_line(move->from, move->to, pos)) {
549 /* if we are moving towards this piece then it
550 removes some topieces elements */
551 dir = sliding_map[move->from][move->to];
552 p2 = move->from;
553 while (p2 != move->to) {
554 b->topieces[p2] &= ~(1<<pi);
555 p2 += dir;
556 }
557 } else if (same_line(pos, move->from, move->to)) {
558 /* if we are moving away from this piece then
559 it adds some topieces elements */
560 dir = sliding_map[move->from][move->to];
561 p2 = move->from;
562 while (p2 != move->to) {
563 p2 += dir;
564 b->topieces[p2] |= (1<<pi);
565 }
566 } else {
567 /* we are moving off the line of this piece
568 we add some topieces elements */
569 dir = sliding_map[pos][move->from];
570 p2 = move->from;
571 while (!off_board(p2, dir) && !b->board[p2]) {
572 p2 += dir;
573 b->topieces[p2] |= (1<<pi);
574 }
575 }
576 }
577
578
579 /* sliding pieces that can move to the to square - their moves
580 along that line might get truncated */
581 mask = mask_to;
582
583 while (mask) {
584 pi = ff_one(mask);
585 mask &= ~(1<<pi);
586
587 pos = b->pieces[pi].pos;
588
589 dir = sliding_map[pos][move->to];
590 p2 = move->to;
591 while (!off_board(p2, dir)) {
592 p2 += dir;
593 b->topieces[p2] &= ~(1<<pi);
594 if (b->board[p2]) break;
595 }
596 }
597
598 /* finally regenerate the piece that is moving */
599 piece_generate(b, b->pboard[move->to]);
600
601
602 /* ugly. we need to recalc pawns because of changes in doubled,
603 isolated or passed pawns */
604 {
605 int minx=0, maxx=0, i;
606 if (abs(oldb->board[move->from]) == PAWN) {
607 minx = XPOS(move->from) - 1;
608 maxx = XPOS(move->from) + 1;
609 if (XPOS(move->to) != XPOS(move->from)) {
610 minx = imin(minx, XPOS(move->to) - 1);
611 maxx = imax(maxx, XPOS(move->to) + 1);
612 }
613 } else if (abs(oldb->board[move->to]) == PAWN) {
614 minx = XPOS(move->to) - 1;
615 maxx = XPOS(move->to) + 1;
616 }
617
618 if (maxx != 0) {
619 for (i=8;i<16;i++) {
620 if (b->pieces[i].p == PAWN &&
621 XPOS(b->pieces[i].pos) >= minx &&
622 XPOS(b->pieces[i].pos) <= maxx)
623 b->piece_change |= (1<<i);
624 }
625
626 for (i=24;i<32;i++) {
627 if (b->pieces[i].p == -PAWN &&
628 XPOS(b->pieces[i].pos) >= minx &&
629 XPOS(b->pieces[i].pos) <= maxx)
630 b->piece_change |= (1<<i);
631 }
632 }
633 }
634 }
635
636
637 /* this routine is the core of the move generator. It is incremental,
638 the topieces[] array always contains a bitmap of what pieces can move
639 to that square. update_moves() is called to update the topieces[]
640 array after each move. It is only called for "simple moves", ie not
641 enpassent captures or castling */
update_moves(Position * b,Position * oldb,Move * move)642 void update_moves(Position *b, Position *oldb, Move *move)
643 {
644 #if !USE_SLIDING_CONTROL
645 old_update_moves(b,oldb,move);
646 return;
647 #else
648 unsigned pi, dir;
649 uint32 mask_from, mask_to, mask, xray_mask;
650 Square pos, p2;
651 int sc, case2;
652 Piece piece1, piece2;
653
654
655 /* the piece that is moving */
656 piece1 = oldb->board[move->from];
657
658 /* wipe the piece that is moving */
659 mask = (1<<oldb->pboard[move->from]);
660
661 /* a piece being captured - always wipe */
662 if (oldb->pboard[move->to] != -1) {
663 mask |= (1<<oldb->pboard[move->to]);
664 }
665
666 mask = ~mask;
667
668 for (pos=A1;pos<=H8;pos+=4) {
669 b->topieces[pos] = oldb->topieces[pos] & mask;
670 b->topieces[pos+1] = oldb->topieces[pos+1] & mask;
671 b->topieces[pos+2] = oldb->topieces[pos+2] & mask;
672 b->topieces[pos+3] = oldb->topieces[pos+3] & mask;
673 b->xray_topieces[pos] = oldb->xray_topieces[pos] & mask;
674 b->xray_topieces[pos+1] = oldb->xray_topieces[pos+1] & mask;
675 b->xray_topieces[pos+2] = oldb->xray_topieces[pos+2] & mask;
676 b->xray_topieces[pos+3] = oldb->xray_topieces[pos+3] & mask;
677 }
678
679 mask_from = b->topieces[move->from] & b->sliding_mask;
680 mask_to = b->topieces[move->to] & b->sliding_mask;
681
682 /* sliding pieces that can move to the from square */
683 mask = mask_from;
684 while (mask) {
685 pi = ff_one(mask);
686 mask &= ~(1<<pi);
687
688 pos = b->pieces[pi].pos;
689 piece2 = b->pieces[pi].p;
690
691 sc = same_color(piece1,piece2);
692
693 if (same_line(move->from, move->to, pos)) {
694 /* if we are moving towards this piece then it
695 removes some topieces elements */
696 dir = sliding_map[move->from][move->to];
697 p2 = move->from;
698
699 xray_mask = ~xray_attack(oldb, pos, move->to);
700
701 while (p2 != move->to) {
702 b->topieces[p2] &= ~(1<<pi);
703 /* if the pieces are the same colour
704 then the same squares become
705 xray attacked by piece2. If not, we must
706 remove any xray attack on
707 those squares by pieces through
708 piece2. */
709 if (sc) {
710 b->xray_topieces[p2] |= (1<<pi);
711 } else {
712 b->xray_topieces[p2] &= xray_mask;
713 }
714 p2 += dir;
715 }
716 } else if (same_line(pos, move->from, move->to)) {
717 /* if we are moving away from this piece then
718 it adds some topieces elements */
719 dir = sliding_map[move->from][move->to];
720 p2 = move->from;
721
722 xray_mask = xray_attack(oldb, pos, move->from);
723
724 while (p2 != move->to) {
725 p2 += dir;
726 b->topieces[p2] |= (1<<pi);
727 /* the same squares are no longer
728 xray attacked by piece2.
729 we must include any xray attack on
730 those squares by pieces through
731 piece2. */
732 b->xray_topieces[p2] &= ~(1<<pi);
733 b->xray_topieces[p2] |= xray_mask;
734 }
735
736 /* If a piece has been captured it may open
737 up some more xray_attacks on the other side
738 of the to square */
739 if (oldb->pboard[move->to] != -1) {
740 xray_mask |= (1<<pi);
741 while (!off_board(p2, dir) && xray_through(b,pos,p2)) {
742 p2 += dir;
743 b->xray_topieces[p2] |= xray_mask;
744 }
745 }
746 } else {
747 /* we are moving off the line of this piece. we
748 add some topieces elements. */
749
750 /* This is complicated for xray attacks. Here is
751 the logic:
752 1) any xray attacks through piece2 and
753 the from square get extended along
754 that line.
755 2) any xray attacks originating at piece2
756 and propagating through a piece on
757 the other side of the from square get
758 included.
759 3) any xray attacks on the other side of
760 the from square by piece2 are removed
761 (up to the next piece). */
762
763
764 dir = sliding_map[pos][move->from];
765 p2 = move->from;
766
767 xray_mask = xray_attack(oldb, pos, move->from);
768 while (!off_board(p2, dir)) {
769 p2 += dir;
770 b->topieces[p2] |= (1<<pi);
771 b->xray_topieces[p2] |= xray_mask; /* 1 */
772 b->xray_topieces[p2] &= ~(1<<pi); /* 3 */
773 if (b->board[p2])
774 break;
775 }
776
777 /* if we stopped because of a piece, we might have to
778 add xray attacks to the squares on the other side of
779 that piece. */
780
781 xray_mask |= (1<<pi);
782 while (!off_board(p2, dir) && xray_through(b,pos,p2)) {
783 p2 += dir;
784 b->xray_topieces[p2] |= xray_mask; /* 2 */
785 }
786 }
787 }
788
789
790 /* sliding pieces that can move to the to square - their moves
791 along that line might get truncated. */
792
793 /* This is complicated for xray attacks. Here is the
794 logic:
795 1) if the pieces are different colours, or they are the same colour but
796 piece1 does not attack piece2 or piece1 is not a sliding piece:
797 1a) any xray attacks through piece2 and the to square get truncated
798 at the to square.
799 1b) any xray attacks originating at piece2 and propagating through a
800 piece on the other side of the to square get truncated at that piece
801 (i.e. removed altogether).
802 2) if not 1) then the pieces are the same colour and they mutually attack:
803 2a) piece2 and any xray attacks through piece2
804 now xray-attack the squares on the other side of the to
805 square.
806 */
807
808 mask = mask_to;
809
810 while (mask) {
811 pi = ff_one(mask);
812 mask &= ~(1<<pi);
813
814 pos = b->pieces[pi].pos;
815 piece2 = b->pieces[pi].p;
816
817 sc = same_color(piece1,piece2);
818 case2 = sc && capture_map[KING + piece1][move->to][pos] &&
819 (b->sliding_mask & (1<<oldb->pboard[move->from]));
820
821 dir = sliding_map[pos][move->to];
822
823 xray_mask = xray_attack(oldb, pos, move->to) | (1<<pi);
824 p2 = move->to;
825 while (!off_board(p2, dir)) {
826 p2 += dir;
827 b->topieces[p2] &= ~(1<<pi);
828 if (case2) {
829 b->xray_topieces[p2] |= xray_mask; /* 2a */
830 } else {
831 b->xray_topieces[p2] &= ~xray_mask; /* 1a */
832 }
833 if (b->board[p2])
834 break;
835 }
836
837 /* if we stopped becuase of a piece we need to check that
838 xray attacks don't go through that piece */
839
840 while (!off_board(p2, dir) && xray_through(b, pos, p2)) {
841 p2 += dir;
842 if (case2) {
843 b->xray_topieces[p2] |= xray_mask; /* 2a */
844 } else {
845 b->xray_topieces[p2] &= ~xray_mask; /* 1b */
846 }
847 }
848 }
849
850 /* finally regenerate the piece that is moving */
851 piece_generate(b, b->pboard[move->to]);
852
853
854 /* ugly. we need to recalc pawns because of changes in doubled,
855 isolated or passed pawns */
856 {
857 int minx=0, maxx=0, i;
858 if (abs(oldb->board[move->from]) == PAWN) {
859 minx = XPOS(move->from) - 1;
860 maxx = XPOS(move->from) + 1;
861 if (XPOS(move->to) != XPOS(move->from)) {
862 minx = imin(minx, XPOS(move->to) - 1);
863 maxx = imax(maxx, XPOS(move->to) + 1);
864 }
865 } else if (abs(oldb->board[move->to]) == PAWN) {
866 minx = XPOS(move->to) - 1;
867 maxx = XPOS(move->to) + 1;
868 }
869
870 if (maxx != 0) {
871 for (i=8;i<16;i++) {
872 if (b->pieces[i].p == PAWN &&
873 XPOS(b->pieces[i].pos) >= minx &&
874 XPOS(b->pieces[i].pos) <= maxx)
875 b->piece_change |= (1<<i);
876 }
877
878 for (i=24;i<32;i++) {
879 if (b->pieces[i].p == -PAWN &&
880 XPOS(b->pieces[i].pos) >= minx &&
881 XPOS(b->pieces[i].pos) <= maxx)
882 b->piece_change |= (1<<i);
883 }
884 }
885 }
886 #endif
887 }
888
889
890 /* this is test code to see that update moves is working absolutely
891 correctly */
update_moves1(Position * b,Position * oldb,Move * move)892 void update_moves1(Position *b, Position *oldb, Move *move)
893 {
894 Square i;
895 Position b1;
896 int bad=0, xray_bad=0;
897
898 b1 = (*b);
899
900 update_moves1(b, oldb, move);
901 regen_moves(&b1);
902
903 for (i=A1;i<=H8;i++) {
904 if (b->topieces[i] != b1.topieces[i]) {
905 lprintf(0,"%s %08x %08x\n",
906 posstr(i), b->topieces[i],
907 b1.topieces[i]);
908 bad++;
909 }
910 #if USE_SLIDING_CONTROL
911 if (b->xray_topieces[i] != b1.xray_topieces[i]) {
912 lprintf(0,"%s %08x %08x %08x\n",
913 posstr(i), b->xray_topieces[i],
914 b1.xray_topieces[i], oldb->xray_topieces[i]);
915 xray_bad++;
916 }
917 #endif
918 }
919
920 if (bad) {
921 lprintf(0,"%s %d bad\n", short_movestr(oldb, move), bad);
922 print_board(oldb->board);
923 }
924 #if USE_SLIDING_CONTROL
925 if (xray_bad) {
926 lprintf(0,"%s %d xray bad\n", short_movestr(oldb, move), xray_bad);
927 print_board(oldb->board);
928 }
929 #endif
930 }
931
932
933 /* this is called when the topieces[] array needs to be completely redone */
regen_moves(Position * b)934 void regen_moves(Position *b)
935 {
936 int pi;
937 memset(b->topieces, 0, sizeof(b->topieces));
938 #if USE_SLIDING_CONTROL
939 memset(b->xray_topieces, 0, sizeof(b->xray_topieces));
940 #endif
941 b->oldb = NULL;
942
943 for (pi=0;pi<32;pi++) {
944 if (!b->pieces[pi].p) continue;
945 piece_generate(b, pi);
946 }
947
948 b->flags &= ~FLAG_EVAL_DONE;
949 b->flags &= ~FLAG_DONE_TACTICS;
950 b->piece_change = b->material_mask;
951
952 eval(b, INFINITY, MAX_DEPTH);
953 }
954
955
956 /* return the number of moves, and put all the moves in moves[].
957 This assumes that moves[] is big enough to hold all the moves */
generate_moves(Position * b,Move * moves)958 int generate_moves(Position *b, Move *moves)
959 {
960 int n, i;
961 PieceStruct *p;
962 uint32 pieces;
963 Square to;
964
965 n = 0;
966
967 if (whites_move(b)) {
968 p = WHITEPIECES(b);
969
970 for (to=A1;to<=H8;to++) {
971 if (b->board[to]>0) continue;
972 pieces = b->topieces[to] & WHITE_MASK;
973 if (b->board[to]==0)
974 pieces &= b->piece_mask;
975 while (pieces) {
976 i = ff_one(pieces);
977 moves->from = p[i].pos;
978 moves->to = to;
979 moves++;
980 n++;
981 pieces &= ~(1<<i);
982 }
983 }
984
985 if ((to=b->enpassent) && (b->topieces[to] & WPAWN_MASK)) {
986 if (XPOS(to) != 0 && b->board[to+SOUTH_WEST] == PAWN) {
987 moves->from = to+SOUTH_WEST;
988 moves->to = to;
989 moves++;
990 n++;
991 }
992 if (XPOS(to) != 7 && b->board[to+SOUTH_EAST] == PAWN) {
993 moves->from = to+SOUTH_EAST;
994 moves->to = to;
995 moves++;
996 n++;
997 }
998 }
999
1000
1001 if (b->flags & WHITE_CASTLE_SHORT) {
1002 if (b->board[F1] == 0 && b->board[G1] == 0 &&
1003 !(b->topieces[E1] & BLACK_MASK) &&
1004 !(b->topieces[F1] & BLACK_MASK) &&
1005 !(b->topieces[G1] & BLACK_MASK)) {
1006 moves->from = E1;
1007 moves->to = G1;
1008 moves++;
1009 n++;
1010 }
1011 }
1012 if (b->flags & WHITE_CASTLE_LONG) {
1013 if (b->board[D1] == 0 && b->board[C1] == 0 &&
1014 b->board[B1] == 0 &&
1015 !(b->topieces[E1] & BLACK_MASK) &&
1016 !(b->topieces[D1] & BLACK_MASK) &&
1017 !(b->topieces[C1] & BLACK_MASK)) {
1018 moves->from = E1;
1019 moves->to = C1;
1020 moves++;
1021 n++;
1022 }
1023 }
1024
1025 p = &WHITEPIECES(b)[8];
1026 for (i=0;i<8;i++, p++) {
1027 if (p->p != PAWN) continue;
1028 if (b->board[p->pos+NORTH]) continue;
1029 moves->from = p->pos;
1030 moves->to = p->pos+NORTH;
1031 moves++;
1032 n++;
1033 if (YPOS(p->pos) != 1 || b->board[p->pos+2*NORTH]) continue;
1034 moves->from = p->pos;
1035 moves->to = p->pos+2*NORTH;
1036 moves++;
1037 n++;
1038 }
1039 } else {
1040 p = WHITEPIECES(b);
1041
1042 for (to=A1;to<=H8;to++) {
1043 if (b->board[to]<0) continue;
1044 pieces = b->topieces[to] & BLACK_MASK;
1045 if (b->board[to]==0)
1046 pieces &= b->piece_mask;
1047 while (pieces) {
1048 i = ff_one(pieces);
1049 moves->from = p[i].pos;
1050 moves->to = to;
1051 moves++;
1052 n++;
1053 pieces &= ~(1<<i);
1054 }
1055 }
1056
1057 if ((to=b->enpassent) && (b->topieces[to] & BPAWN_MASK)) {
1058 if (XPOS(to) != 0 && b->board[to+NORTH_WEST] == -PAWN) {
1059 moves->from = to+NORTH_WEST;
1060 moves->to = to;
1061 moves++;
1062 n++;
1063 }
1064 if (XPOS(to) != 7 && b->board[to+NORTH_EAST] == -PAWN) {
1065 moves->from = to+NORTH_EAST;
1066 moves->to = to;
1067 moves++;
1068 n++;
1069 }
1070 }
1071
1072
1073 if (b->flags & BLACK_CASTLE_SHORT) {
1074 if (b->board[F8] == 0 && b->board[G8] == 0 &&
1075 !(b->topieces[E8] & WHITE_MASK) &&
1076 !(b->topieces[F8] & WHITE_MASK) &&
1077 !(b->topieces[G8] & WHITE_MASK)) {
1078 moves->from = E8;
1079 moves->to = G8;
1080 moves++;
1081 n++;
1082 }
1083 }
1084 if (b->flags & BLACK_CASTLE_LONG) {
1085 if (b->board[D8] == 0 && b->board[C8] == 0 &&
1086 b->board[B8] == 0 &&
1087 !(b->topieces[E8] & WHITE_MASK) &&
1088 !(b->topieces[D8] & WHITE_MASK) &&
1089 !(b->topieces[C8] & WHITE_MASK)) {
1090 moves->from = E8;
1091 moves->to = C8;
1092 moves++;
1093 n++;
1094 }
1095 }
1096
1097 p = &BLACKPIECES(b)[8];
1098 for (i=0;i<8;i++, p++) {
1099 if (p->p != -PAWN) continue;
1100 if (b->board[p->pos+SOUTH]) continue;
1101 moves->from = p->pos;
1102 moves->to = p->pos+SOUTH;
1103 moves++;
1104 n++;
1105 if (YPOS(p->pos) != 6 || b->board[p->pos+2*SOUTH]) continue;
1106 moves->from = p->pos;
1107 moves->to = p->pos+2*SOUTH;
1108 moves++;
1109 n++;
1110 }
1111 }
1112
1113 return n;
1114 }
1115
generate_check_avoidance(Position * b,Move * moves)1116 int generate_check_avoidance(Position *b, Move *moves)
1117 {
1118 int n=0;
1119 int kpos, pos, pi, pi2, dx, dy, to, dir;
1120 int x1, x2, y1, y2, x, y;
1121 uint32 giving_check, pieces;
1122
1123 if (whites_move(b)) {
1124 kpos = WHITEPIECES(b)[IKING].pos;
1125 giving_check = b->topieces[kpos] & BLACK_MASK;
1126 } else {
1127 kpos = BLACKPIECES(b)[IKING].pos;
1128 giving_check = b->topieces[kpos] & WHITE_MASK;
1129 }
1130
1131 pos = kpos;
1132
1133 /* which piece is giving check? */
1134 pi = ff_one(giving_check);
1135 if (giving_check & ~(1<<pi))
1136 goto king_moves; /* its double check */
1137
1138 pos = b->pieces[pi].pos;
1139
1140 /* try to capture it */
1141 pieces = b->topieces[pos];
1142
1143 /* a special case - if its a pawn and enpassent is possible then
1144 take enpassent */
1145 if (b->enpassent && !(giving_check & b->piece_mask)) {
1146 pieces |= b->topieces[b->enpassent] & ~b->piece_mask;
1147 }
1148
1149 if (whites_move(b)) {
1150 pieces &= WHITE_MASK;
1151 } else {
1152 pieces &= BLACK_MASK;
1153 }
1154
1155 while (pieces) {
1156 pi2 = ff_one(pieces);
1157 moves->from = b->pieces[pi2].pos;
1158 if (abs(b->board[moves->from]) == PAWN &&
1159 YPOS(pos) == YPOS(moves->from))
1160 moves->to = b->enpassent;
1161 else
1162 moves->to = pos;
1163 moves++;
1164 n++;
1165 pieces &= ~(1<<pi2);
1166 }
1167
1168
1169 /* now try to block it if its a sliding piece */
1170 if (!(giving_check & b->sliding_mask))
1171 goto king_moves;
1172
1173 dx = XPOS(kpos) - XPOS(pos);
1174 dy = YPOS(kpos) - YPOS(pos);
1175
1176 dir = 0;
1177 if (dy > 0)
1178 dir += SOUTH;
1179 else if (dy < 0)
1180 dir += NORTH;
1181
1182 if (dx > 0)
1183 dir += WEST;
1184 else if (dx < 0)
1185 dir += EAST;
1186
1187 to = kpos + dir;
1188 while (to != pos) {
1189 if (whites_move(b)) {
1190 pieces = (b->topieces[to] & WHITE_MASK) & ~WKING_MASK;
1191 pieces &= b->piece_mask;
1192 if (b->board[to+SOUTH] == PAWN) {
1193 pieces |= (1<<b->pboard[to+SOUTH]);
1194 } else if (YPOS(to) == 3 && b->board[to+SOUTH] == 0 &&
1195 b->board[to+2*SOUTH] == PAWN) {
1196 pieces |= (1<<b->pboard[to+2*SOUTH]);
1197 }
1198 } else {
1199 pieces = (b->topieces[to] & BLACK_MASK) & ~BKING_MASK;
1200 pieces &= b->piece_mask;
1201 if (b->board[to+NORTH] == -PAWN) {
1202 pieces |= (1<<b->pboard[to+NORTH]);
1203 } else if (YPOS(to) == 4 && b->board[to+NORTH] == 0 &&
1204 b->board[to+2*NORTH] == -PAWN) {
1205 pieces |= (1<<b->pboard[to+2*NORTH]);
1206 }
1207 }
1208 while (pieces) {
1209 pi2 = ff_one(pieces);
1210 moves->from = b->pieces[pi2].pos;
1211 moves->to = to;
1212 moves++;
1213 n++;
1214 pieces &= ~(1<<pi2);
1215 }
1216 to += dir;
1217 }
1218
1219
1220 king_moves:
1221 /* try to move the king */
1222 x1 = XPOS(kpos) - 1;
1223 x2 = x1 + 2;
1224 y1 = YPOS(kpos) - 1;
1225 y2 = y1 + 2;
1226
1227 if (x1 < 0) x1 = 0;
1228 if (y1 < 0) y1 = 0;
1229 if (x2 == 8) x2 = 7;
1230 if (y2 == 8) y2 = 7;
1231
1232 for (x=x1;x<=x2;x++)
1233 for (y=y1;y<=y2;y++) {
1234 int pos2 = POSN(x,y);
1235 if (pos2 == kpos || pos2 == pos) continue;
1236 pieces = b->topieces[pos2];
1237 if (whites_move(b)) {
1238 if (pieces & BLACK_MASK) continue;
1239 if (b->board[pos2] > 0) continue;
1240 } else {
1241 if (pieces & WHITE_MASK) continue;
1242 if (b->board[pos2] < 0) continue;
1243 }
1244
1245 /* the king can't move to any square that is in the
1246 capture map of the pieces giving check */
1247 pieces = giving_check & b->sliding_mask;
1248 while (pieces) {
1249 Square ppos;
1250 pi = ff_one(pieces);
1251 ppos = b->pieces[pi].pos;
1252 if (same_line(ppos, kpos, pos2))
1253 break;
1254 pieces &= ~(1<<pi);
1255 }
1256
1257 moves->from = kpos;
1258 moves->to = pos2;
1259
1260 if (pieces) {
1261 #if 0
1262 Position b1;
1263 if (do_move(&b1, b, moves)) {
1264 lprintf(0, "legal move %s\n",
1265 short_movestr(b, moves));
1266 print_board(b->board);
1267 }
1268 #endif
1269 continue;
1270 }
1271
1272 #if 0
1273 {
1274 Position b1;
1275 if (!do_move(&b1, b, moves)) {
1276 lprintf(0, "illegal move %s\n",
1277 short_movestr(b, moves));
1278 print_board(b->board);
1279 }
1280 }
1281 #endif
1282
1283 moves++;
1284 n++;
1285 }
1286
1287 return n;
1288 }
1289
1290
1291
1292
1293
1294 /* this is used to make sure the player didn't make an illegal move -
1295 it is not speed critical */
legal_move(Position * b,Move * move)1296 int legal_move(Position *b, Move *move)
1297 {
1298 Move moves[MAX_MOVES];
1299 int num_moves;
1300 int m;
1301 Position b1;
1302
1303 num_moves = generate_moves(b, moves);
1304
1305 for (m=0;m<num_moves;m++)
1306 if (moves[m].from == move->from &&
1307 moves[m].to == move->to) break;
1308
1309 if (m == num_moves) return 0;
1310
1311 if (!do_move(&b1, b, move))
1312 return 0;
1313
1314 return 1;
1315 }
1316
1317
get_move_list(int ply)1318 static Move *get_move_list(int ply)
1319 {
1320 static int num_move_lists;
1321 static Move **move_lists;
1322 int j;
1323
1324 if (num_move_lists > ply) {
1325 return move_lists[ply];
1326 }
1327
1328 move_lists = (Move **)Realloc(move_lists,
1329 (num_move_lists+30)*sizeof(Move *));
1330 for (j=num_move_lists;j<num_move_lists+30;j++) {
1331 move_lists[j] = (Move *)Realloc(NULL, MAX_MOVES*sizeof(Move));
1332 }
1333
1334 num_move_lists += 30;
1335
1336 return move_lists[ply];
1337 }
1338
1339
gen_move_list(Position * b,int ply,Move * m1,Eval testv)1340 void gen_move_list(Position *b, int ply, Move *m1, Eval testv)
1341 {
1342 int n;
1343 Move *moves;
1344
1345 if (b->moves) {
1346 lprintf(0,"already has a moves list\n");
1347 }
1348
1349 b->moves = get_move_list(ply);
1350 moves = b->moves;
1351
1352 if (b->flags & FLAG_CHECK) {
1353 n = generate_check_avoidance(b, moves);
1354 } else {
1355 n = generate_moves(b, moves);
1356 }
1357
1358 b->num_moves = n;
1359 order_moves(b, moves, n, ply, m1, testv);
1360 }
1361
1362
possible_move(Position * b,int ply,Move * m)1363 int possible_move(Position *b, int ply, Move *m)
1364 {
1365 int n, i;
1366 Move *moves;
1367
1368 moves = get_move_list(ply+1);
1369
1370 n = generate_moves(b, moves);
1371
1372 for (i=0;i<n;i++)
1373 if (same_move(m, &moves[i])) return 1;
1374
1375 return 0;
1376 }
1377
1378
1379