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