Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / move.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     move.c
8
9 Abstract:
10
11     Functions to make and unmake moves.
12
13 Author:
14
15     Scott Gasch ([email protected]) 09 May 2004
16
17 Revision History:
18
19     $Id: move.c 345 2007-12-02 22:56:42Z scott $
20
21 **/
22
23 #include "chess.h"
24
25 void 
26 SlidePiece(POSITION *pos, COOR cFrom, COOR cTo)
27 /**
28
29 Routine description:
30
31     Slide a piece (i.e. not a pawn) from cFrom to cTo.  This is much
32     faster than LiftPiece / PlacePiece.
33
34 Parameters:
35
36     POSITION *pos : the board
37     COOR cFrom : square moving from
38     COOR cTo : square moving to
39
40 Return value:
41
42     void
43
44 **/
45 {
46     register PIECE p;
47     register ULONG c;
48     ULONG uIndex;
49     
50 #ifdef DEBUG
51     VerifyPositionConsistency(pos, FALSE);
52     ASSERT(IS_ON_BOARD(cFrom));
53     ASSERT(IS_ON_BOARD(cTo));
54     ASSERT(IS_EMPTY(pos->rgSquare[cTo].pPiece));
55 #endif
56     p = pos->rgSquare[cFrom].pPiece;
57     pos->rgSquare[cFrom].pPiece = EMPTY;
58     ASSERT(!IS_PAWN(p));
59     ASSERT(IS_VALID_PIECE(p));
60     uIndex = pos->rgSquare[cFrom].uIndex;
61     c = GET_COLOR(p);
62     ASSERT(IS_VALID_COLOR(c));
63     ASSERT(pos->cNonPawns[c][uIndex] == cFrom);
64     pos->cNonPawns[c][uIndex] = cTo;
65     pos->u64NonPawnSig ^= g_u64SigSeeds[cFrom][PIECE_TYPE(p)][c];
66     pos->u64NonPawnSig ^= g_u64SigSeeds[cTo][PIECE_TYPE(p)][c];
67 #ifdef DEBUG
68     if (IS_BISHOP(p) && (IS_SQUARE_WHITE(cFrom)))
69     {
70         ASSERT(IS_SQUARE_WHITE(cTo));
71     }
72 #endif
73     pos->rgSquare[cTo].pPiece = p;
74     pos->rgSquare[cTo].uIndex = uIndex;
75 #ifdef DEBUG
76     pos->rgSquare[cFrom].uIndex = INVALID_PIECE_INDEX;
77     VerifyPositionConsistency(pos, FALSE);
78 #endif
79 }
80
81
82 void 
83 SlidePawn(POSITION *pos, COOR cFrom, COOR cTo)
84 /**
85
86 Routine description:
87
88     Slide a pawn (i.e. not a piece) from cFrom to cTo.  This is much
89     faster than LiftPiece / PlacePiece.
90
91 Parameters:
92
93     POSITION *pos : the board
94     COOR cFrom : square moving from
95     COOR cTo : square moving to
96
97 Return value:
98
99     void
100
101 **/
102 {
103     register PIECE p;
104     register ULONG c;
105     ULONG uIndex;
106     
107 #ifdef DEBUG
108     VerifyPositionConsistency(pos, FALSE);
109     ASSERT(IS_ON_BOARD(cFrom));
110     ASSERT(IS_ON_BOARD(cTo));
111     ASSERT(IS_EMPTY(pos->rgSquare[cTo].pPiece));
112 #endif
113     p = pos->rgSquare[cFrom].pPiece;
114     pos->rgSquare[cFrom].pPiece = EMPTY;
115     ASSERT(IS_PAWN(p));
116     ASSERT(IS_VALID_PIECE(p));
117     uIndex = pos->rgSquare[cFrom].uIndex;
118     c = GET_COLOR(p);
119     ASSERT(IS_VALID_COLOR(c));
120     ASSERT(pos->cPawns[c][uIndex] == cFrom);
121     pos->cPawns[c][uIndex] = cTo;
122     pos->u64PawnSig ^= g_u64PawnSigSeeds[cFrom][c];
123     pos->u64PawnSig ^= g_u64PawnSigSeeds[cTo][c];
124     pos->rgSquare[cTo].pPiece = p;
125     pos->rgSquare[cTo].uIndex = uIndex;
126 #ifdef DEBUG
127     pos->rgSquare[cFrom].uIndex = INVALID_PIECE_INDEX;
128     VerifyPositionConsistency(pos, FALSE);
129 #endif
130 }
131
132
133 void 
134 SlidePieceWithoutSigs(POSITION *pos, COOR cFrom, COOR cTo)
135 /**
136
137 Routine description:
138
139     Slide a piece (i.e. not a pawn) from cFrom to cTo.  This is way
140     faster than LiftPiece / PlacePiece.  Also note that this version
141     of the routine doesn't maintain the consistency of the position
142     signatures and should therefore only be called from UnmakeMove.
143
144 Parameters:
145
146     POSITION *pos : the board
147     COOR cFrom : square moving from
148     COOR cTo : square moving to
149
150 Return value:
151
152     void
153
154 **/
155 {
156     register PIECE p;
157     register ULONG c;
158     ULONG uIndex;
159     
160 #ifdef DEBUG
161     ASSERT(IS_ON_BOARD(cFrom));
162     ASSERT(IS_ON_BOARD(cTo));
163     ASSERT(IS_EMPTY(pos->rgSquare[cTo].pPiece));
164 #endif
165     p = pos->rgSquare[cFrom].pPiece;
166     pos->rgSquare[cFrom].pPiece = EMPTY;
167     ASSERT(IS_VALID_PIECE(p));
168     ASSERT(!IS_PAWN(p));
169     uIndex = pos->rgSquare[cFrom].uIndex;
170     c = GET_COLOR(p);
171     ASSERT(IS_VALID_COLOR(c));
172     ASSERT(pos->cNonPawns[c][uIndex] == cFrom);
173     pos->cNonPawns[c][uIndex] = cTo;
174     pos->rgSquare[cTo].pPiece = p;
175     pos->rgSquare[cTo].uIndex = uIndex;
176 #ifdef DEBUG
177     pos->rgSquare[cFrom].uIndex = INVALID_PIECE_INDEX;
178 #endif
179 }
180
181
182 void 
183 SlidePawnWithoutSigs(POSITION *pos, COOR cFrom, COOR cTo)
184 /**
185
186 Routine description:
187
188     Slide a pawn (i.e. not a piece) from cFrom to cTo.  This is way
189     faster than LiftPiece / PlacePiece.  Also note that this version
190     of the routine doesn't maintain the consistency of the position
191     signatures and should therefore only be called from UnmakeMove.
192
193 Parameters:
194
195     POSITION *pos : the board
196     COOR cFrom : square moving from
197     COOR cTo : square moving to
198
199 Return value:
200
201     void
202
203 **/
204 {
205     register PIECE p;
206     register ULONG c;
207     ULONG uIndex;
208     
209 #ifdef DEBUG
210     ASSERT(IS_ON_BOARD(cFrom));
211     ASSERT(IS_ON_BOARD(cTo));
212     ASSERT(IS_EMPTY(pos->rgSquare[cTo].pPiece));
213 #endif
214     p = pos->rgSquare[cFrom].pPiece;
215     pos->rgSquare[cFrom].pPiece = EMPTY;
216     ASSERT(IS_VALID_PIECE(p));
217     ASSERT(IS_PAWN(p));
218     uIndex = pos->rgSquare[cFrom].uIndex;
219     c = GET_COLOR(p);
220     ASSERT(IS_VALID_COLOR(c));
221     ASSERT(pos->cPawns[c][uIndex] == cFrom);
222     pos->cPawns[c][uIndex] = cTo;
223     pos->rgSquare[cTo].pPiece = p;
224     pos->rgSquare[cTo].uIndex = uIndex;
225 #ifdef DEBUG
226     pos->rgSquare[cFrom].uIndex = INVALID_PIECE_INDEX;
227 #endif
228 }
229
230
231 PIECE 
232 LiftPiece(POSITION *pos, COOR cSquare)
233 /**
234
235 Routine description:
236
237     Remove the piece at square cSquare from the board.  Update POSITION
238     (piece lists, counts, material, etc...) accordingly.
239
240 Parameters:
241
242     POSITION *pos,
243     COOR cSquare
244
245 Return value:
246
247     PIECE
248
249 **/
250 {
251     register PIECE pLifted;
252     ULONG color;
253     register SCORE pv;
254     ULONG uLastIndex;
255     ULONG uIndex;
256     COOR c;
257     ULONG u;
258 #ifdef DEBUG
259     VerifyPositionConsistency(pos, FALSE);
260     ASSERT(IS_ON_BOARD(cSquare));
261 #endif
262     pLifted = pos->rgSquare[cSquare].pPiece;
263     if (IS_EMPTY(pLifted))
264     {
265         return(pLifted);                        // ok to return an empty square
266     }
267     pos->rgSquare[cSquare].pPiece = EMPTY;
268     ASSERT(IS_VALID_PIECE(pLifted));
269     ASSERT(!IS_KING(pLifted));
270     uIndex = pos->rgSquare[cSquare].uIndex;
271 #ifdef DEBUG
272     ASSERT(IS_VALID_PIECE_INDEX(uIndex));
273     pos->rgSquare[cSquare].uIndex = INVALID_PIECE_INDEX;
274 #endif
275     color = GET_COLOR(pLifted);
276     ASSERT(IS_VALID_COLOR(color));
277     pv = PIECE_VALUE(pLifted);
278     ASSERT(pv > 0);
279     pos->iMaterialBalance[color] -= pv;
280     pos->iMaterialBalance[FLIP(color)] += pv;
281     ASSERT(pos->iMaterialBalance[WHITE] * -1 == pos->iMaterialBalance[BLACK]);
282     
283     if (IS_PAWN(pLifted))
284     {
285         ASSERT(pos->cPawns[color][uIndex] == cSquare);
286         ASSERT(pv == VALUE_PAWN);
287         
288         pos->uPawnMaterial[color] -= pv;
289         ASSERT(pos->uPawnMaterial[color] <= (7 * VALUE_PAWN));
290
291         pos->u64PawnSig ^= g_u64PawnSigSeeds[cSquare][color];
292
293         //
294         // Remove this pawn from the pawn list.
295         // 
296         pos->uPawnCount[color]--;
297         ASSERT(pos->uPawnCount[color] < 8);
298         uLastIndex = pos->uPawnCount[color];
299         
300         //
301         // Assume that the pawn being lifted is not the last pawn on
302         // the list.  We can't have a hole in the list so swap the
303         // last pawn on the list into this guy's spot.
304         //
305         c = pos->cPawns[color][uLastIndex];
306         pos->rgSquare[c].uIndex = uIndex;
307         pos->cPawns[color][uIndex] = c;
308 #ifdef DEBUG
309         pos->cPawns[color][uLastIndex] = ILLEGAL_COOR;
310 #endif
311     }
312     else 
313     {
314         //
315         // Piece is not a pawn
316         //
317         ASSERT(pos->cNonPawns[color][uIndex] == cSquare);
318         ASSERT(pos->uNonPawnMaterial[color] >= VALUE_KING);
319         ASSERT(pv > VALUE_PAWN);
320         pos->uNonPawnMaterial[color] -= pv;
321         ASSERT(pos->uNonPawnMaterial[color] <= VALUE_MAX_ARMY);
322        
323         //
324         // Remove this piece from the list.
325         // 
326         pos->uNonPawnCount[color][0]--;
327         ASSERT(pos->uNonPawnCount[color] > 0);
328         uLastIndex = pos->uNonPawnCount[color][0]; // optimized...
329         //
330         // Assume that it is NOT the last piece in the list ... swap
331         // the last piece into this one's spot.
332         // 
333         c = pos->cNonPawns[color][uLastIndex];
334         pos->rgSquare[c].uIndex = uIndex;
335         pos->cNonPawns[color][uIndex] = c;
336 #ifdef DEBUG
337         pos->cNonPawns[color][uLastIndex] = ILLEGAL_COOR;
338 #endif
339
340         //
341         // Change per-piece counters.
342         //
343         u = PIECE_TYPE(pLifted);
344         ASSERT((u >= KNIGHT) && (u < KING));
345         pos->u64NonPawnSig ^= g_u64SigSeeds[cSquare][u][color];
346         pos->uNonPawnCount[color][u]--;
347         ASSERT(pos->uNonPawnCount[color][u] <= 9);
348         pos->uWhiteSqBishopCount[color] -= (IS_BISHOP(pLifted) &
349                                             IS_SQUARE_WHITE(cSquare));
350         ASSERT(pos->uWhiteSqBishopCount[color] <= 9);
351     }
352     
353 #ifdef DEBUG
354     VerifyPositionConsistency(pos, FALSE);
355 #endif
356     return(pLifted);
357 }
358
359
360 PIECE 
361 LiftPieceWithoutSigs(POSITION *pos, COOR cSquare)
362 /**
363
364 Routine description:
365
366     Remove the piece at square cSquare from the board.  Update POSITION
367     (piece lists, counts, material, etc...) accordingly.
368
369     Note: LiftPieceWithoutSigs can _only_ be called from UnmakeMove.
370     It is used to unmake a previously made move and therefore does
371     not worry about updating position signatures.  UnmakeMove has
372     the pre-move signature in a history list and will klobber the
373     position signature soon anyway.
374     
375 Parameters:
376
377     POSITION *pos,
378     COOR cSquare
379
380 Return value:
381
382     PIECE
383
384 **/
385 {
386     register PIECE pLifted;
387     ULONG color;
388     register SCORE pv;
389     ULONG uLastIndex;
390     ULONG uIndex;
391     COOR c;
392     ULONG u;
393
394     ASSERT(IS_ON_BOARD(cSquare));
395     pLifted = pos->rgSquare[cSquare].pPiece;
396     if (IS_EMPTY(pLifted))
397     {
398         return(pLifted);                        // ok to return an empty square
399     }
400     pos->rgSquare[cSquare].pPiece = EMPTY;
401     ASSERT(IS_VALID_PIECE(pLifted));
402     ASSERT(!IS_KING(pLifted));
403     
404     uIndex = pos->rgSquare[cSquare].uIndex;
405 #ifdef DEBUG
406     ASSERT(IS_VALID_PIECE_INDEX(uIndex));
407     pos->rgSquare[cSquare].uIndex = INVALID_PIECE_INDEX;
408 #endif
409     color = GET_COLOR(pLifted);
410     ASSERT(IS_VALID_COLOR(color));
411     pv = PIECE_VALUE(pLifted);
412     ASSERT(pv > 0);
413     pos->iMaterialBalance[color] -= pv;
414     pos->iMaterialBalance[FLIP(color)] += pv;
415     ASSERT(pos->iMaterialBalance[WHITE] * -1 == pos->iMaterialBalance[BLACK]);
416     
417     if (IS_PAWN(pLifted))
418     {
419         ASSERT(pos->cPawns[color][uIndex] == cSquare);
420         ASSERT(pv == VALUE_PAWN);
421         
422         pos->uPawnMaterial[color] -= pv;
423         ASSERT(pos->uPawnMaterial[color] <= (7 * VALUE_PAWN));
424         
425         //
426         // Remove this pawn from the pawn list.
427         // 
428         pos->uPawnCount[color]--;
429         ASSERT(pos->uPawnCount[color] < 8);
430         uLastIndex = pos->uPawnCount[color];  // optimized...
431         
432         //
433         // Assume that the pawn being lifted is not the last pawn on
434         // the list.  We can't have a hole in the list so swap the
435         // last pawn on the list into this guy's spot.
436         //
437         c = pos->cPawns[color][uLastIndex];
438         pos->rgSquare[c].uIndex = uIndex;
439         pos->cPawns[color][uIndex] = c;
440 #ifdef DEBUG
441         pos->cPawns[color][uLastIndex] = ILLEGAL_COOR;
442 #endif
443     }
444     else 
445     {
446         //
447         // Piece is not a pawn
448         //
449         ASSERT(pos->cNonPawns[color][uIndex] == cSquare);
450         ASSERT(pos->uNonPawnMaterial[color] >= VALUE_KING);
451         ASSERT(pv > VALUE_PAWN);
452         pos->uNonPawnMaterial[color] -= pv;
453         ASSERT(pos->uNonPawnMaterial[color] <= VALUE_MAX_ARMY);
454        
455         //
456         // Remove this piece from the list.
457         // 
458         pos->uNonPawnCount[color][0]--;
459         ASSERT(pos->uNonPawnCount[color] > 0);
460         uLastIndex = pos->uNonPawnCount[color][0]; // optimized...
461         
462         //
463         // Assume that it is NOT the last piece in the list ... swap
464         // the last piece into this one's spot.
465         // 
466         c = pos->cNonPawns[color][uLastIndex];
467         pos->rgSquare[c].uIndex = uIndex;
468         pos->cNonPawns[color][uIndex] = c;
469 #ifdef DEBUG
470         pos->cNonPawns[color][uLastIndex] = ILLEGAL_COOR;
471 #endif
472
473         //
474         // Change per-piece counters.
475         //
476         u = PIECE_TYPE(pLifted);
477         ASSERT((u >= KNIGHT) && (u < KING));
478         pos->uNonPawnCount[color][u]--;
479         ASSERT(pos->uNonPawnCount[color][u] <= 9);
480         pos->uWhiteSqBishopCount[color] -= (IS_BISHOP(pLifted) & 
481                                             IS_SQUARE_WHITE(cSquare));
482         ASSERT(pos->uWhiteSqBishopCount[color] <= 9);
483     }
484     
485     return(pLifted);
486 }
487
488
489 void 
490 PlacePiece(POSITION *pos, COOR cSquare, PIECE pPiece)
491 /**
492
493 Routine description:
494
495     Place a piece back on the board.  Link it into the right piece list.
496
497 Parameters:
498
499     POSITION *pos,
500     COOR cSquare,
501     PIECE pPiece
502
503 Return value:
504
505     void
506
507 **/
508 {
509     register ULONG color = GET_COLOR(pPiece);
510     register ULONG uIndex;
511     register SCORE pv;
512     ULONG u;
513     
514 #ifdef DEBUG
515     VerifyPositionConsistency(pos, FALSE);
516     ASSERT(IS_EMPTY(pos->rgSquare[cSquare].pPiece));
517     ASSERT(!IS_KING(pPiece));
518 #endif
519    
520     pv = PIECE_VALUE(pPiece);
521     pos->iMaterialBalance[color] += pv;
522     pos->iMaterialBalance[FLIP(color)] -= pv;
523     ASSERT(pos->iMaterialBalance[WHITE] * -1 == pos->iMaterialBalance[BLACK]);
524     
525     if (IS_PAWN(pPiece))
526     {
527         //
528         // Piece is a pawn
529         //
530         ASSERT(pv == VALUE_PAWN);
531         pos->uPawnMaterial[color] += pv;
532         ASSERT(pos->uPawnMaterial[color] <= (8 * VALUE_PAWN));
533         
534         uIndex = pos->uPawnCount[color];
535         ASSERT((uIndex >= 0) && (uIndex <= 7));
536         pos->uPawnCount[color]++;
537         ASSERT(pos->uPawnCount[color] <= 8);
538         pos->cPawns[color][uIndex] = cSquare;
539         pos->u64PawnSig ^= g_u64PawnSigSeeds[cSquare][color];
540     }
541     else
542     {
543         //
544         // Piece is not a pawn
545         //
546         ASSERT(pv > VALUE_PAWN);
547         pos->uNonPawnMaterial[color] += pv;
548         ASSERT(pos->uNonPawnMaterial[color] <= VALUE_MAX_ARMY);
549         uIndex = pos->uNonPawnCount[color][0];
550         pos->uNonPawnCount[color][0]++;
551         ASSERT(pos->uNonPawnCount[color][0] <= 16);
552         pos->cNonPawns[color][uIndex] = cSquare;
553         
554         u = PIECE_TYPE(pPiece);
555         ASSERT((u >= KNIGHT) && (u < KING));
556         pos->u64NonPawnSig ^= g_u64SigSeeds[cSquare][u][color];
557         pos->uNonPawnCount[color][u]++;
558         ASSERT(pos->uNonPawnCount[color][u] <= 10);
559         
560         pos->uWhiteSqBishopCount[color] += (IS_BISHOP(pPiece) &
561                                             IS_SQUARE_WHITE(cSquare));
562         ASSERT(pos->uWhiteSqBishopCount[color] <= 10);
563     }
564
565     //
566     // Place the piece on the board
567     // 
568     pos->rgSquare[cSquare].pPiece = pPiece;
569     pos->rgSquare[cSquare].uIndex = uIndex;
570     
571 #ifdef DEBUG
572     VerifyPositionConsistency(pos, FALSE);
573 #endif
574 }
575
576
577 void 
578 PlacePieceWithoutSigs(POSITION *pos, COOR cSquare, PIECE pPiece)
579 /**
580
581 Routine description:
582
583     Place a piece back on the board.  Link it into the right piece list.
584
585     Note: PlacePieceWithoutSigs can _only_ be called from UnmakeMove.
586     It is used to unmake a previously made move and therefore does
587     not worry about updating position signatures.  UnmakeMove has
588     the pre-move signature in a history list and will klobber the
589     position signature soon anyway.
590     
591 Parameters:
592
593     POSITION *pos,
594     COOR cSquare,
595     PIECE pPiece
596
597 Return value:
598
599     void
600
601 **/
602 {
603     register ULONG color = GET_COLOR(pPiece);
604     register ULONG uIndex;
605     register SCORE pv;
606     ULONG u;
607     
608     ASSERT(IS_EMPTY(pos->rgSquare[cSquare].pPiece));
609     ASSERT(!IS_KING(pPiece));
610    
611     pv = PIECE_VALUE(pPiece);
612     pos->iMaterialBalance[color] += pv;
613     pos->iMaterialBalance[FLIP(color)] -= pv;
614     ASSERT(pos->iMaterialBalance[WHITE] * -1 == pos->iMaterialBalance[BLACK]);
615     
616     if (IS_PAWN(pPiece))
617     {
618         //
619         // Piece is a pawn
620         //
621         ASSERT(pv == VALUE_PAWN);
622         pos->uPawnMaterial[color] += pv;
623         ASSERT(pos->uPawnMaterial[color] <= (8 * VALUE_PAWN));
624         
625         uIndex = pos->uPawnCount[color];
626         ASSERT((uIndex >= 0) && (uIndex <= 7));
627         pos->uPawnCount[color]++;
628         ASSERT(pos->uPawnCount[color] <= 8);
629         pos->cPawns[color][uIndex] = cSquare;
630     }
631     else
632     {
633         //
634         // Piece is not a pawn
635         //
636         ASSERT(pv > VALUE_PAWN);
637         pos->uNonPawnMaterial[color] += pv;
638         ASSERT(pos->uNonPawnMaterial[color] <= VALUE_MAX_ARMY);
639         uIndex = pos->uNonPawnCount[color][0];
640         pos->uNonPawnCount[color][0]++;
641         ASSERT(pos->uNonPawnCount[color][0] <= 16);
642         pos->cNonPawns[color][uIndex] = cSquare;
643         
644         u = PIECE_TYPE(pPiece);
645         ASSERT((u >= KNIGHT) && (u < KING));
646         pos->uNonPawnCount[color][u]++;
647         ASSERT(pos->uNonPawnCount[color][u] <= 10);
648         
649         pos->uWhiteSqBishopCount[color] += (IS_BISHOP(pPiece) &
650                                             IS_SQUARE_WHITE(cSquare));
651         ASSERT(pos->uWhiteSqBishopCount[color] <= 10);
652     }
653
654     //
655     // Place the piece on the board
656     // 
657     pos->rgSquare[cSquare].pPiece = pPiece;
658     pos->rgSquare[cSquare].uIndex = uIndex;
659 }
660
661
662 void 
663 SaveCurrentPositionHistoryInContext(SEARCHER_THREAD_CONTEXT *ctx,
664                                     MOVE mv)
665 /**
666
667 Routine description:
668
669     This routine is called just before MakeMove to record some
670     information about the current board position to help unmake the
671     move later.  It's also used to detect draws in the search.
672     
673     Note: when this function is called, ply has not been incremented.
674
675 Parameters:
676
677     SEARCHER_THREAD_CONTEXT *ctx
678
679 Return value:
680
681     void
682
683 **/
684 {
685     ULONG uPly = ctx->uPly;
686     POSITION *pos = &(ctx->sPosition);
687     PLY_INFO *pi = &ctx->sPlyInfo[uPly];
688     
689     //
690     // Save data about the position we are leaving.
691     //
692     ASSERT(ctx->uPly < MAX_PLY_PER_SEARCH);
693     ASSERT((pos->u64NonPawnSig & 1) == pos->uToMove);
694     pi->u64NonPawnSig = pos->u64NonPawnSig;
695     pi->u64PawnSig = pos->u64PawnSig;
696     pi->u64Sig = (pos->u64NonPawnSig ^ pos->u64PawnSig);
697     pi->uFifty = pos->uFifty;
698     pi->fCastled[BLACK] = pos->fCastled[BLACK];
699     pi->fCastled[WHITE] = pos->fCastled[WHITE];
700     pi->uTotalNonPawns = (pos->uNonPawnCount[BLACK][0] + 
701                           pos->uNonPawnCount[WHITE][0]);
702     ASSERT(IS_VALID_FLAG(pos->fCastled[WHITE]) &&
703            IS_VALID_FLAG(pos->fCastled[BLACK]));
704     ASSERT((pos->bvCastleInfo & ~CASTLE_ALL_POSSIBLE) == 0);
705     pi->bvCastleInfo = pos->bvCastleInfo;
706     ASSERT(VALID_EP_SQUARE(pos->cEpSquare));
707     pi->cEpSquare = pos->cEpSquare;
708     (pi+1)->fInQsearch = pi->fInQsearch;
709 }
710
711
712 static ULONG g_uCastleMask[128] = 
713 {
714     0x7, 0xF, 0xF, 0xF, 0x3, 0xF, 0xF, 0xB,        0,0,0,0,0,0,0,0,
715     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
716     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
717     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
718     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
719     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
720     0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF,        0,0,0,0,0,0,0,0,
721     0xD, 0xF, 0xF, 0xF, 0xC, 0xF, 0xF, 0xE,        0,0,0,0,0,0,0,0
722 };
723
724
725 FLAG 
726 MakeMove(SEARCHER_THREAD_CONTEXT *ctx,
727          MOVE mv)
728 /**
729
730 Routine description:
731
732     Attempts to make MOVE mv on the POSITION in ctx.  Returns TRUE if
733     the move was successful, FALSE if it was illegal.  If the move was
734     successful, this function affects the POSITION (piece locations,
735     piece lists, castling perms, en-passant square, signatures etc...)
736     and also increments the ply in ctx.  These changes can be reverted
737     at a later point by using UnmakeMove.
738     
739     Note: This function only does a very limited amount of legality
740     checking in order to save time because it is designed to take
741     moves from the move generator (which will only make illegal moves
742     in certain, known ways).  If the move is coming from the user
743     (and is therefore of dubious legality)) it should be passed to
744     MakeUserMove, not MakeMove.  MakeUserMove verifies that it is a
745     legal chess move in every way.
746
747 Parameters:
748
749     SEARCHER_THREAD_CONTEXT *ctx
750     MOVE mv
751
752 Return value:
753
754     FLAG
755
756 **/
757 {
758     POSITION *pos = &ctx->sPosition;
759     PIECE pPiece;
760     PIECE pCaptured;
761     PIECE pPromoted;
762     COOR c;
763     COOR cRookFrom;
764     COOR cRookTo;
765     COOR cKing;
766     PIECE xPawn;
767     FLAG fMoveIsLegal = FALSE;
768     static int iSign[2] = { -1, +1 };
769
770 #ifdef DEBUG
771     cRookFrom = cRookTo = ILLEGAL_COOR;       // Satisfy overzealous compiler
772     VerifyPositionConsistency(pos, FALSE);
773     SanityCheckMove(pos, mv);
774     ASSERT(!InCheck(pos, FLIP(pos->uToMove)));
775     if (InCheck(pos, pos->uToMove))
776     {
777         ASSERT(IS_ESCAPING_CHECK(mv));
778     }
779 #endif
780     SaveCurrentPositionHistoryInContext(ctx, mv);
781     if (mv.uMove == 0)
782     {
783         pos->uFifty++;
784         goto clear_ep;
785     }
786
787     pPiece = mv.pMoved;
788     pCaptured = mv.pCaptured;
789     ASSERT(!IS_EMPTY(pPiece));
790     ASSERT(pPiece == pos->rgSquare[mv.cFrom].pPiece);
791     ASSERT(GET_COLOR(pPiece) == pos->uToMove);
792     
793     //
794     // Is this a special move?  Special moves are: promotions, enpassant,
795     // castling and double pawn moves.
796     // 
797     if (IS_SPECIAL_MOVE(mv))
798     {
799         if (IS_PAWN(pPiece))
800         {
801             pPromoted = mv.pPromoted;
802             if (pPromoted)
803             {
804                 ASSERT(!IS_PAWN(pPromoted));
805                 ASSERT(GET_COLOR(pPromoted) == GET_COLOR(pPiece));
806                 pPiece = LiftPiece(pos, mv.cFrom);
807                 pCaptured = LiftPiece(pos, mv.cTo);
808                 ASSERT(!pCaptured || (OPPOSITE_COLORS(pCaptured, pPiece)));
809                 PlacePiece(pos, mv.cTo, pPromoted);
810                 pos->uFifty = 0;
811                 goto update_castle_and_clear_ep;
812             }
813             
814             //
815             // Is this an enpassant capture?
816             // 
817             else if (pCaptured)
818             {
819                 ASSERT(mv.cTo == pos->cEpSquare);
820                 pCaptured = LiftPiece(pos, mv.cTo +
821                                       iSign[GET_COLOR(pPiece)] * 16);
822                 ASSERT(IS_PAWN(pCaptured));
823                 ASSERT(OPPOSITE_COLORS(pPiece, pCaptured));
824                 ASSERT(IS_EMPTY(pos->rgSquare[mv.cTo].pPiece));
825                 ASSERT(IS_PAWN(pPiece));
826                 SlidePawn(pos, mv.cFrom, mv.cTo);
827                 pos->uFifty = 0;
828                 goto clear_ep;
829             }
830             
831             //
832             // A special pawn move other than promotion and enpassant
833             // capture must be a double initial jump.
834             // 
835             else
836             {
837                 c = mv.cFrom;
838                 c += (iSign[GET_COLOR(pPiece)] * -16);
839                 ASSERT(RANK3(c) || RANK6(c));
840                 ASSERT(c + (iSign[GET_COLOR(pPiece)] * -16) == mv.cTo);
841                 ASSERT(IS_EMPTY(pos->rgSquare[c].pPiece));
842                 ASSERT(IS_EMPTY(pos->rgSquare[mv.cTo].pPiece));
843                 ASSERT(IS_PAWN(pPiece));
844                 SlidePawn(pos, mv.cFrom, mv.cTo);
845                 pos->uFifty = 0;
846                 
847                 //
848                 // Only change the position signature to reflect the
849                 // possible en-passant if there's an enemy who can
850                 // take advantage of it.
851                 //
852                 xPawn = BLACK_PAWN | FLIP(GET_COLOR(pPiece));
853                 if (((!IS_ON_BOARD(mv.cTo - 1)) ||
854                      (pos->rgSquare[mv.cTo - 1].pPiece != xPawn)) &&
855                     ((!IS_ON_BOARD(mv.cTo + 1)) ||
856                      (pos->rgSquare[mv.cTo + 1].pPiece != xPawn)))
857                 {
858                     goto clear_ep;
859                 }
860                 pos->u64NonPawnSig ^= g_u64EpSigSeeds[FILE(pos->cEpSquare)];
861                 ASSERT(VALID_EP_SQUARE(c));
862                 pos->cEpSquare = c;
863                 pos->u64NonPawnSig ^= g_u64EpSigSeeds[FILE(pos->cEpSquare)];
864                 goto update_board;
865             }
866         }
867         else if (IS_KING(pPiece))
868         {
869             ASSERT(!IS_ESCAPING_CHECK(mv));
870             
871             // 
872             // The only special king move is a castle.
873             // 
874             switch (mv.cTo)
875             {
876             case C1:
877                 ASSERT(pos->bvCastleInfo & CASTLE_WHITE_LONG);
878                 ASSERT(IS_EMPTY(pos->rgSquare[B1].pPiece) &&
879                        IS_EMPTY(pos->rgSquare[C1].pPiece) &&
880                        IS_EMPTY(pos->rgSquare[D1].pPiece));
881                 if ((IsAttacked(D1, pos, BLACK)) ||
882                     (IsAttacked(C1, pos, BLACK))) 
883                 {
884                     goto illegal;
885                 }
886                 cRookFrom = A1;
887                 cRookTo = D1;
888                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
889                 pos->bvCastleInfo &= ~(WHITE_CAN_CASTLE);
890                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
891                 pos->fCastled[WHITE] = TRUE;
892                 break;
893             case G1:
894                 ASSERT(pos->bvCastleInfo & CASTLE_WHITE_SHORT);
895                 ASSERT(IS_EMPTY(pos->rgSquare[F1].pPiece) &&
896                        IS_EMPTY(pos->rgSquare[G1].pPiece));
897                 if ((IsAttacked(F1, pos, BLACK)) ||
898                     (IsAttacked(G1, pos, BLACK))) 
899                 {
900                     goto illegal;
901                 }
902                 cRookFrom = H1;
903                 cRookTo = F1;
904                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
905                 pos->bvCastleInfo &= ~(WHITE_CAN_CASTLE);
906                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
907                 pos->fCastled[WHITE] = TRUE;
908                 break;
909             case C8:
910                 ASSERT(pos->bvCastleInfo & CASTLE_BLACK_LONG);
911                 ASSERT(IS_EMPTY(pos->rgSquare[B8].pPiece) &&
912                        IS_EMPTY(pos->rgSquare[C8].pPiece) &&
913                        IS_EMPTY(pos->rgSquare[D8].pPiece));
914                 if ((IsAttacked(D8, pos, WHITE)) ||
915                     (IsAttacked(C8, pos, WHITE))) 
916                 {
917                     goto illegal;
918                 }
919                 cRookFrom = A8;
920                 cRookTo = D8;
921                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
922                 pos->bvCastleInfo &= ~(BLACK_CAN_CASTLE);
923                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
924                 pos->fCastled[BLACK] = TRUE;
925                 break;
926             case G8:
927                 ASSERT(pos->bvCastleInfo & CASTLE_BLACK_SHORT);
928                 ASSERT(IS_EMPTY(pos->rgSquare[F8].pPiece) &&
929                        IS_EMPTY(pos->rgSquare[G8].pPiece));
930                 if ((IsAttacked(F8, pos, WHITE)) ||
931                     (IsAttacked(G8, pos, WHITE))) 
932                 {
933                     goto illegal;
934                 }
935                 cRookFrom = H8;
936                 cRookTo = F8;
937                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
938                 pos->bvCastleInfo &= ~(BLACK_CAN_CASTLE);
939                 pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
940                 pos->fCastled[BLACK] = TRUE;
941                 break;
942 #ifdef DEBUG
943             default:
944                 cRookFrom = cRookTo = ILLEGAL_COOR;
945                 ASSERT(FALSE);
946                 goto illegal;
947 #endif
948             }
949             ASSERT(IS_EMPTY(pos->rgSquare[mv.cTo].pPiece));
950             ASSERT(IS_ROOK(pos->rgSquare[cRookFrom].pPiece));
951             ASSERT(IS_EMPTY(pos->rgSquare[cRookTo].pPiece));
952             SlidePiece(pos, mv.cFrom, mv.cTo);   // king
953             SlidePiece(pos, cRookFrom, cRookTo); // rook
954             pos->uFifty = 0;
955             goto clear_ep;
956         }
957 #ifdef DEBUG
958         else
959         {
960             ASSERT(FALSE);
961             goto illegal;
962         }
963 #endif
964     }
965     
966     //
967     // Normal move or normal capture
968     //
969     pos->uFifty++;
970     if (pCaptured)
971     {
972         pos->uFifty = 0;
973         pCaptured = LiftPiece(pos, mv.cTo);
974         ASSERT(!IS_KING(pCaptured));
975         ASSERT(!IS_EMPTY(pCaptured));
976         ASSERT(OPPOSITE_COLORS(pCaptured, pPiece));
977     }
978     if (IS_PAWN(pPiece)) 
979     {
980         pos->uFifty = 0;
981         SlidePawn(pos, mv.cFrom, mv.cTo);
982     }
983     else 
984     {
985         SlidePiece(pos, mv.cFrom, mv.cTo);
986     }
987     
988  update_castle_and_clear_ep:
989     pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
990     pos->bvCastleInfo &= g_uCastleMask[mv.cFrom];
991     pos->bvCastleInfo &= g_uCastleMask[mv.cTo];
992     pos->u64NonPawnSig ^= g_u64CastleSigSeeds[pos->bvCastleInfo];
993
994  clear_ep:
995     if (pos->cEpSquare != ILLEGAL_COOR)
996     {
997         pos->u64NonPawnSig ^= g_u64EpSigSeeds[FILE(pos->cEpSquare)];
998         pos->cEpSquare = ILLEGAL_COOR;
999         pos->u64NonPawnSig ^= g_u64EpSigSeeds[FILE(pos->cEpSquare)];
1000     }
1001
1002  update_board:
1003     // 
1004     // At this point we have made the move on the board (moved pieces,
1005     // updated castling permissions, updated 50 move count, updated
1006     // signature with respect to piece location etc...)
1007     // 
1008     // Now we switch the side on move and flip a bit in the signature
1009     // to indicate that it's the other side's turn now.  We also
1010     // record this position in the movelist (for later detection of
1011     // repetition of position draws) and increment either the ply or
1012     // move num.
1013     // 
1014     pos->u64NonPawnSig ^= 1;
1015     pos->uToMove = FLIP(pos->uToMove);
1016     ASSERT((pos->u64NonPawnSig & 1) == pos->uToMove);
1017     ASSERT(ctx->uPly < MAX_PLY_PER_SEARCH - 1);
1018     ctx->sPlyInfo[ctx->uPly].mv = mv;
1019     ctx->uPly++;
1020     ASSERT(ctx->uPly < MAX_PLY_PER_SEARCH);
1021     
1022     //
1023     // Make sure the move doesn't leave his own king in check.
1024     //
1025     if (mv.uMove != 0)
1026     {
1027         cKing = pos->cNonPawns[FLIP(pos->uToMove)][0];
1028         ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
1029
1030         if (IS_KING(mv.pMoved) || IS_ESCAPING_CHECK(mv))
1031         {
1032             //
1033             // If this guy just moved his king OR he was in check
1034             // before making this move we need to do a full check
1035             // check now... this involves using the attack vector
1036             // table to test ALL pieces in the enemy army and see if
1037             // they are attacking the just-moved king.
1038             //
1039             ASSERT(GET_COLOR(mv.pMoved) == FLIP(pos->uToMove));
1040             if (InCheck(pos, GET_COLOR(mv.pMoved)))
1041             {
1042                 goto takeback;
1043             }
1044         }
1045
1046         //
1047         // else he did not move the king and he was not in check
1048         // before he made this move.  To determine if he is in check
1049         // now should be cheaper because all we have to consider is
1050         // whether the move he just made exposed his king to check.
1051         // 
1052         else
1053         {
1054             //
1055             // This call will also catch positions like:
1056             //
1057             // 3K4/8/8/8/1k1Pp1R1/8/8/8 w - d3 0 1
1058             //
1059             // ... where the black pawn capturing on d3 exposes his
1060             // own king to the white rook's horizontal attack.
1061             // Because the pawn captured en passant has already been
1062             // lifted.
1063             //
1064             if (IS_ON_BOARD(ExposesCheck(pos, mv.cFrom, cKing)))
1065             {
1066                 ASSERT(InCheck(pos, GET_COLOR(mv.pMoved)));
1067                 goto takeback;
1068             }
1069             
1070             //
1071             // This is a special case -- if the move was enpassant the
1072             // guy might have exposed his king to check by removing
1073             // the enemy pawn (i.e. exposes a diagonal attack on his
1074             // own king)
1075             // 
1076             if (IS_ENPASSANT(mv))
1077             {
1078                 ASSERT(IS_SPECIAL_MOVE(mv));
1079                 ASSERT(!IS_PROMOTION(mv));
1080                 ASSERT(mv.pCaptured);
1081                 ASSERT(IS_PAWN(mv.pMoved));
1082                 ASSERT(IS_PAWN(mv.pCaptured));
1083                 if (IS_ON_BOARD(ExposesCheck(pos,
1084                                              ((pos->uToMove == WHITE) ?
1085                                               (mv.cTo + 16) : 
1086                                               (mv.cTo - 16)), 
1087                                              cKing)))
1088                 {
1089                     ASSERT(InCheck(pos, GET_COLOR(mv.pMoved)));
1090                     goto takeback;
1091                 }
1092             }
1093         }
1094         ASSERT(IS_EMPTY(pos->rgSquare[mv.cFrom].pPiece));
1095         ASSERT(!IS_EMPTY(pos->rgSquare[mv.cTo].pPiece));
1096         ASSERT((pos->rgSquare[mv.cTo].pPiece == mv.pMoved) ||
1097                (pos->rgSquare[mv.cTo].pPiece == mv.pPromoted));
1098     }
1099     ASSERT(!InCheck(pos, GET_COLOR(mv.pMoved)));
1100     fMoveIsLegal = TRUE;
1101 #ifdef DEBUG
1102     VerifyPositionConsistency(pos, FALSE);
1103 #endif
1104     //
1105     // Fall into illegal... but don't worry: we're legal!
1106     //
1107
1108  illegal:
1109     return(fMoveIsLegal);
1110     
1111  takeback:
1112     //
1113     // If we goto here it means that the guy is trying to move into
1114     // check.  We didn't determine this until after we already made
1115     // the whole move so we can't just return false (illegal move)
1116     // from there.  First we have to unmake the move we just made.
1117     //
1118     ASSERT(InCheck(pos, FLIP(pos->uToMove)));
1119     UnmakeMove(ctx, mv);
1120 #ifdef DEBUG
1121     VerifyPositionConsistency(pos, FALSE);
1122 #endif
1123     return(FALSE);
1124 }
1125
1126
1127 FLAG 
1128 MakeUserMove(SEARCHER_THREAD_CONTEXT *ctx, 
1129              MOVE mvUser)
1130 /**
1131
1132 Routine description:
1133
1134     This function should be called to make a move of dubious quality.
1135     The engine calls MakeMove directly for moves it generated itself
1136     because these are _mostly_ legal.  The only exceptions being:
1137
1138         1. moves that expose the friendly king to check
1139         2. castles through check
1140
1141     This function is intended for moves from a user or ICS.  It
1142     screens these moves by first generating available moves at this
1143     ply and making sure it looks like one of them.  It returns 
1144     TRUE if the move is legal and was played, FALSE otherwise.
1145
1146     Both moves made with MakeMove and MakeUserMove can be unmade
1147     with UnmakeMove.
1148
1149 Parameters:
1150
1151     SEARCHER_THREAD_CONTEXT *ctx,
1152     MOVE mvUser
1153
1154 Return value:
1155
1156     FLAG
1157
1158 **/
1159 {
1160     POSITION *pos = &ctx->sPosition;
1161     FLAG fInCheck = InCheck(pos, pos->uToMove);
1162     FLAG fRet = FALSE;
1163     MOVE mv;
1164     ULONG x;
1165
1166     //
1167     // Ask the generator to give us a list of moves here
1168     //
1169     mv.uMove = 0;
1170     GenerateMoves(ctx, mv, (fInCheck ? GENERATE_ESCAPES : GENERATE_ALL_MOVES));
1171     for (x = ctx->sMoveStack.uBegin[ctx->uPly];
1172          x < ctx->sMoveStack.uEnd[ctx->uPly];
1173          x++)
1174     {
1175         mv = ctx->sMoveStack.mvf[x].mv;
1176         if (IS_SAME_MOVE(mvUser, mv))
1177         {
1178             if (TRUE == MakeMove(ctx, mv))
1179             {
1180                 fRet = TRUE;
1181                 goto end;
1182             }
1183         }
1184     }
1185     
1186  end:
1187     return(fRet);
1188 }
1189
1190
1191 void
1192 UnmakeMove(SEARCHER_THREAD_CONTEXT *ctx, 
1193            MOVE mv)
1194 /**
1195
1196 Routine description:
1197
1198     Reverses a move made by MakeMove.
1199
1200 Parameters:
1201
1202     SEARCHER_THREAD_CONTEXT *ctx,
1203     MOVE mv
1204
1205 Return value:
1206
1207     void
1208
1209 **/
1210 {
1211     PIECE pPiece;
1212     PIECE pCaptured;
1213     PLY_INFO *pi;
1214     POSITION *pos = &(ctx->sPosition);
1215     static int iSign[2] = { -1, +1 };
1216
1217 #ifdef DEBUG
1218     VerifyPositionConsistency(pos, FALSE);
1219     ASSERT(IS_ON_BOARD(mv.cTo));
1220     ASSERT(IS_ON_BOARD(mv.cFrom));
1221 #endif
1222     if (mv.uMove == 0) 
1223     {
1224         goto restore_saved_position_data;
1225     }
1226     
1227     pPiece = mv.pMoved;
1228     pCaptured = mv.pCaptured;
1229     if (IS_CASTLE(mv))
1230     {
1231         ASSERT(IS_KING(pPiece));
1232         ASSERT(IS_SPECIAL_MOVE(mv));
1233         
1234         switch (mv.cTo)
1235         {
1236             case C1:
1237                 //
1238                 // No need to call SlidePiece here, the signatures will
1239                 // get reset to their pre-move state below
1240                 //
1241                 SlidePieceWithoutSigs(pos, D1, A1); // rook
1242                 SlidePieceWithoutSigs(pos, C1, E1); // king
1243                 ASSERT(IS_KING(pos->rgSquare[E1].pPiece));
1244                 ASSERT(IS_ROOK(pos->rgSquare[A1].pPiece));
1245                 break;
1246             case G1:
1247                 SlidePieceWithoutSigs(pos, F1, H1); // rook
1248                 SlidePieceWithoutSigs(pos, G1, E1); // king
1249                 ASSERT(IS_KING(pos->rgSquare[E1].pPiece));
1250                 ASSERT(IS_ROOK(pos->rgSquare[H1].pPiece));
1251                 break;
1252             case C8:
1253                 SlidePieceWithoutSigs(pos, D8, A8); // rook
1254                 SlidePieceWithoutSigs(pos, C8, E8); // king
1255                 ASSERT(IS_KING(pos->rgSquare[E8].pPiece));
1256                 ASSERT(IS_ROOK(pos->rgSquare[A8].pPiece));
1257                 break;
1258             case G8:
1259                 SlidePieceWithoutSigs(pos, F8, H8); // rook
1260                 SlidePieceWithoutSigs(pos, G8, E8); // king
1261                 ASSERT(IS_KING(pos->rgSquare[E8].pPiece));
1262                 ASSERT(IS_ROOK(pos->rgSquare[H8].pPiece));
1263                 break;
1264 #ifdef DEBUG
1265             default:
1266                 ASSERT(FALSE);
1267                 break;
1268 #endif
1269         }
1270     }
1271     else
1272     {
1273         if (IS_PROMOTION(mv))
1274         {
1275             ASSERT(IS_SPECIAL_MOVE(mv));
1276             ASSERT(mv.pPromoted);
1277             
1278             //
1279             // LiftPiece/PlacePiece must be done here to maintain
1280             // piece list integrity.
1281             //
1282             (void)LiftPieceWithoutSigs(pos, mv.cTo);
1283             pPiece |= 2;
1284             pPiece &= 3;
1285             ASSERT(pPiece == mv.pMoved);
1286             PlacePieceWithoutSigs(pos, mv.cFrom, pPiece);
1287         }
1288         else
1289         {
1290             if (IS_PAWN(pPiece))
1291             {
1292                 SlidePawnWithoutSigs(pos, mv.cTo, mv.cFrom);
1293             }
1294             else
1295             {
1296                 SlidePieceWithoutSigs(pos, mv.cTo, mv.cFrom);
1297             }
1298         }
1299         
1300         if (pCaptured)
1301         {
1302             //
1303             // If this was an enpassant capture, put the pawn back to the
1304             // right square.
1305             // 
1306             if (IS_ENPASSANT(mv))
1307             {
1308                 ASSERT(IS_SPECIAL_MOVE(mv));
1309                 ASSERT(IS_PAWN(mv.pMoved));
1310                 ASSERT(IS_PAWN(pCaptured));
1311                 ASSERT(IS_ON_BOARD(mv.cTo) + 16);
1312                 ASSERT(IS_ON_BOARD(mv.cTo) - 16);
1313                 
1314                 //
1315                 // Resurrect the dead piece in the enpassant location 
1316                 // where it died (not the same as where the killer moved).
1317                 // 
1318                 ASSERT(IS_EMPTY(pos->rgSquare[mv.cTo + 16 * 
1319                                        iSign[GET_COLOR(mv.pMoved)]].pPiece));
1320                 PlacePieceWithoutSigs(pos, 
1321                                      mv.cTo + 16 * iSign[GET_COLOR(mv.pMoved)],
1322                                       pCaptured);
1323             }
1324             else
1325             {
1326                 //
1327                 // Normal capture... resurrect the dead piece where the
1328                 // killer moved.
1329                 // 
1330                 ASSERT(IS_EMPTY(pos->rgSquare[mv.cTo].pPiece));
1331                 PlacePieceWithoutSigs(pos, mv.cTo, pCaptured);
1332             }
1333         }
1334     }
1335     
1336  restore_saved_position_data:
1337     ctx->uPly--;
1338     ASSERT(ctx->uPly < MAX_PLY_PER_SEARCH);
1339
1340     pi = &ctx->sPlyInfo[ctx->uPly];
1341     pos->u64NonPawnSig = pi->u64NonPawnSig;
1342     pos->u64PawnSig = pi->u64PawnSig;
1343     ASSERT((pos->u64NonPawnSig & WHITE) == FLIP(pos->uToMove));
1344     pos->uFifty = pi->uFifty;
1345     pos->fCastled[WHITE] = pi->fCastled[WHITE];
1346     pos->fCastled[BLACK] = pi->fCastled[BLACK];
1347     ASSERT((pi->bvCastleInfo & ~CASTLE_ALL_POSSIBLE) == 0);
1348     pos->bvCastleInfo = pi->bvCastleInfo;
1349     ASSERT(VALID_EP_SQUARE(pi->cEpSquare));
1350     ASSERT(VALID_EP_SQUARE(pos->cEpSquare));
1351     pos->cEpSquare = pi->cEpSquare;
1352     pos->uToMove = FLIP(pos->uToMove);
1353 #ifdef DEBUG
1354     VerifyPositionConsistency(pos, FALSE);
1355 #endif
1356 }
1357
1358
1359 static char *
1360 _MoveFlagsToString(BITV bv)
1361 /**
1362
1363 Routine description:
1364
1365     Support routing for DumpMove.  Translates bvFlags component of a
1366     MOVE into a nice string.  Not thread safe.
1367
1368 Parameters:
1369
1370     BITV bv
1371
1372 Return value:
1373
1374     char
1375
1376 **/
1377 {
1378     static char buf[5];
1379     char *p = buf;
1380     
1381     if (bv & MOVE_FLAG_SPECIAL)
1382     {
1383         *p++ = 'S';
1384     }
1385     if (bv & MOVE_FLAG_ESCAPING_CHECK)
1386     {
1387         *p++ = 'E';
1388     }
1389     if (bv & MOVE_FLAG_CHECKING)
1390     {
1391         *p++ = '+';
1392     }
1393     if (bv & MOVE_FLAG_KILLERMATE)
1394     {
1395         *p++ = '!';
1396     }
1397     *p++ = '\0';
1398     return(buf);
1399 }
1400
1401
1402 void 
1403 DumpMove(ULONG u)
1404 /**
1405
1406 Routine description:
1407
1408     Dump a move on stdout.  This function takes a ULONG instead of a
1409     MOVE becasue both gdb and msdev do not like to pass unions to
1410     functions invoked at debugtime.
1411
1412 Parameters:
1413
1414     ULONG u
1415
1416 Return value:
1417
1418     void
1419
1420 **/
1421 {
1422     MOVE mv;
1423     
1424     mv.uMove = u;
1425     Trace("--------------------------------------------------------------------------------\n"
1426           "MOVE:\n"
1427           "  +0x000 uMove                     : 0x%x\n"
1428           "  +0x000 cFrom      <pos 0, 8 bits>: 0x%x (%s)\n",
1429           mv.uMove,
1430           mv.cFrom, CoorToString(mv.cFrom));
1431     Trace("  +0x001 cTo        <pos 0, 8 bits>: 0x%x (%s)\n"
1432           "  +0x002 pMoved     <pos 0, 4 Bits>: 0x%x (%s)\n",
1433           mv.cTo, CoorToString(mv.cTo),
1434           mv.pMoved, PieceAbbrev(mv.pMoved));
1435     Trace("  +0x002 pCaptured  <pos 4, 4 Bits>: 0x%x (%s)\n",
1436           mv.pCaptured, PieceAbbrev(mv.pCaptured));
1437     Trace("  +0x003 pPromoted  <pos 0, 4 Bits>: 0x%x (%s)\n",
1438           mv.pPromoted, PieceAbbrev(mv.pPromoted));
1439     Trace("  +0x003 bvFlags    <pos 4, 4 Bits>: 0x%x (%s)\n", 
1440           mv.bvFlags, _MoveFlagsToString(mv.bvFlags));
1441 }