Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / save / util.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     util.c
8
9 Abstract:
10
11     General purpose utility code to support the engine.
12
13 Author:
14
15     Scott Gasch ([email protected]) 8 Apr 2004
16
17 Revision History:
18
19     $Id: util.c 345 2007-12-02 22:56:42Z scott $
20
21 **/
22
23 #include "chess.h"
24
25 extern ULONG g_uIterateDepth;
26 extern ULONG g_uFullWidthDepth;
27
28 #define STATE_UNKNOWN  (0)
29 #define STATE_HEADER   (1)
30 #define STATE_MOVELIST (2)
31
32 CHAR *
33 ReadNextGameFromPgnFile(FILE *pf)
34 /**
35
36 Routine description:
37
38     Reads the next game in a PGN file and returns a pointer to it.
39
40 Parameters:
41
42     FILE *pf : open file pointer
43
44 Return value:
45
46     CHAR * : NULL on error, else caller must free via SystemFreeMemory.
47
48 **/
49 {
50     CHAR buf[MEDIUM_STRING_LEN_CHAR];
51     CHAR *p;
52     long lStartOfGame = -1;
53     long lEndOfGame = -1;
54     long lBefore;
55     ULONG uBytes;
56     ULONG uState = STATE_UNKNOWN;
57
58     while(1)
59     {
60         lBefore = ftell(pf);
61         if (fgets(buf, ARRAY_LENGTH(buf), pf) <= 0)
62         {
63             //Trace("fgets failed, errno=%u.\n", errno);
64             break;
65         }
66
67         //
68         // Skip leading whitespace on this line...
69         //
70         p = buf;
71         while(*p && isspace(*p)) p++;
72
73         if (*p == '\0')
74         {
75             //
76             // We just read a blank line
77             //
78             switch(uState)
79             {
80                 case STATE_UNKNOWN:
81                     break;
82
83                 case STATE_HEADER:
84                     uState = STATE_MOVELIST;
85                     break;
86
87                 case STATE_MOVELIST:
88                     lEndOfGame = lBefore;
89                     uBytes = lEndOfGame - lStartOfGame;
90                     if (uBytes <= 0)
91                     {
92                         return(NULL);
93                     }
94
95                     p = SystemAllocateMemory(uBytes + 1);
96                     ASSERT(p);
97                     fseek(pf, lStartOfGame, SEEK_SET);
98                     if (1 != fread(p, uBytes, 1, pf))
99                     {
100                         SystemFreeMemory(p);
101                         return(NULL);
102                     }
103                     p[uBytes] = '\0';
104                     return(p);
105             }
106         }
107         else
108         {
109             //
110             // We saw a non-blank line
111             //
112             switch(uState)
113             {
114                 case STATE_HEADER:
115                 case STATE_MOVELIST:
116                     break;
117
118                 case STATE_UNKNOWN:
119                     if (*p == '[')
120                     {
121                         uState = STATE_HEADER;
122                         lStartOfGame = lBefore;
123                     }
124                     break;
125             }
126         }
127     }
128     return(NULL);
129 }
130
131
132 COMMAND(LearnPsqtFromPgn)
133 /**
134
135 Routine description:
136
137 Parameters:
138
139     CHAR *szFilename,
140
141 Return value:
142
143     FLAG
144
145 **/
146 {
147     CHAR *szFilename;
148     ULONG uPSQT[12][128];
149     CHAR *pPGN;
150     FILE *pf = NULL;
151     DLIST_ENTRY *p;
152     GAME_MOVE *q;
153     ULONG x, y, z;
154     double d;
155     struct stat s;
156 #ifdef DEBUG
157     ULONG uHeap;
158 #endif
159
160     if (argc < 2)
161     {
162         Trace("Error (missing filename)\n");
163         return;
164     }
165     szFilename = argv[1];
166
167     if (FALSE == SystemDoesFileExist(szFilename))
168     {
169         Trace("LearnPsqtFromPgn: file \"%s\" doesn't exist.\n",
170               szFilename);
171         return;
172     }
173
174     if (0 != stat(szFilename, &s))
175     {
176         Trace("Stat failed.\n");
177         return;
178     }
179
180     pf = fopen(szFilename, "rb");
181     if (NULL == pf)
182     {
183         Trace("LearnPsqtFromPgn: error reading file \"%s\".\n",
184               szFilename);
185         return;
186     }
187
188     memset(uPSQT, 0, sizeof(uPSQT));
189 #ifdef DEBUG
190     ResetGameList();
191     uHeap = GetHeapMemoryUsage();
192 #endif
193     while((pPGN = ReadNextGameFromPgnFile(pf)) != NULL)
194     {
195         d = (double)ftell(pf);
196         d /= (double)s.st_size;
197         d *= 100.0;
198         printf("(%5.2f%% done)\r", d);
199
200         if (TRUE == LoadPgn(pPGN))
201         {
202             p = g_GameData.sMoveList.pFlink;
203             while(p != &(g_GameData.sMoveList))
204             {
205                 q = CONTAINING_STRUCT(p, GAME_MOVE, links);
206                 if ((q->uNumber > 10) &&
207                     (q->uNumber < 50) &&
208                     (!q->mv.pCaptured))
209                 {
210                     uPSQT[q->mv.pMoved - 2][q->mv.cTo] += 1;
211                 }
212                 p = p->pFlink;
213             }
214         }
215         SystemFreeMemory(pPGN);
216 #ifdef DEBUG
217         ResetGameList();
218         ASSERT(uHeap == GetHeapMemoryUsage());
219 #endif
220     }
221     fclose(pf);
222
223     z = 0;
224     for (x = 0; x < 12; x++)
225     {
226         for (y = 0; y < 128; y++)
227         {
228             if (uPSQT[x][y] > z)
229             {
230                 z = uPSQT[x][y];
231             }
232         }
233     }
234
235     Trace("ULONG g_PSQT[12][128] = {\n");
236     for (x = 0; x < 12; x++)
237     {
238         Trace("// Piece 0x%x (%s)\n", x + 2, PieceAbbrev((PIECE)(x + 2)));
239         Trace("{\n");
240
241         for (y = 0; y < 128; y++)
242         {
243             if (y % 16 == 0) Trace("\n");
244             d = (double)uPSQT[x][y];
245             d /= (double)z;
246             d *= (double)1000.0;
247             Trace("%4u,", (ULONG)d);
248         }
249         Trace("},\n");
250     }
251     Trace("};\n");
252 }
253
254
255 COMMAND(GeneratePositionAndBestMoveSuite)
256 /**
257
258 Routine description:
259
260 Parameters:
261
262     CHAR *szFilename,
263
264 Return value:
265
266     FLAG
267
268 **/
269 {
270     CHAR *szFilename;
271     CHAR *pPGN;
272     FILE *pf = NULL;
273     DLIST_ENTRY *p;
274     GAME_MOVE *q;
275     SEARCHER_THREAD_CONTEXT *ctx = NULL;
276     FLAG fPost = g_Options.fShouldPost;
277     struct stat s;
278     double d;
279     POSITION board;
280
281     if (argc < 2)
282     {
283         Trace("Error (missing filename)\n");
284         goto end;
285     }
286     szFilename = argv[1];
287
288     if (FALSE == SystemDoesFileExist(szFilename))
289     {
290         Trace("LearnPsqtFromPgn: file \"%s\" doesn't exist.\n",
291               szFilename);
292         goto end;
293     }
294
295     if (0 != stat(szFilename, &s))
296     {
297         Trace("Stat failed.\n");
298         goto end;
299     }
300
301     pf = fopen(szFilename, "rb");
302     if (NULL == pf)
303     {
304         Trace("LearnPsqtFromPgn: error reading file \"%s\".\n",
305               szFilename);
306         goto end;
307     }
308
309     ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
310     if (NULL == ctx)
311     {
312         Trace("Out of memory.\n");
313         goto end;
314     }
315
316     g_Options.fShouldPost = FALSE;
317     while((pPGN = ReadNextGameFromPgnFile(pf)) != NULL)
318     {
319         d = (double)ftell(pf);
320         d /= (double)s.st_size;
321         d *= 100.0;
322         printf("(%5.2f%% done)\r", d);
323
324         if (TRUE == LoadPgn(pPGN))
325         {
326             p = g_GameData.sMoveList.pFlink;
327             while(p != &(g_GameData.sMoveList))
328             {
329                 q = CONTAINING_STRUCT(p, GAME_MOVE, links);
330                 if ((q->uNumber > 20) && (q->uNumber < 60))
331                 {
332                     if (FenToPosition(&board, q->szUndoPositionFen))
333                     {
334                         InitializeSearcherContext(&board, ctx);
335                         g_MoveTimer.bvFlags = 0;
336                         g_Options.fPondering = FALSE;
337                         g_Options.fThinking = TRUE;
338                         g_Options.fSuccessfulPonder = FALSE;
339
340                         MaintainDynamicMoveOrdering();
341                         DirtyHashTable();
342
343                         g_MoveTimer.uNodeCheckMask = 0x1000 - 1;
344                         g_MoveTimer.dStartTime = SystemTimeStamp();
345                         g_MoveTimer.bvFlags = 0;
346                         g_MoveTimer.dSoftTimeLimit =
347                             g_MoveTimer.dStartTime + 3.0;
348                         g_MoveTimer.dHardTimeLimit =
349                             g_MoveTimer.dStartTime + 3.0;
350                         g_Options.uMaxDepth = MAX_DEPTH_PER_SEARCH - 1;
351
352                         //
353                         // TODO: Set draw value
354                         //
355 #if (PERF_COUNTERS && MP)
356                         ClearHelperThreadIdleness();
357 #endif
358                         GAME_RESULT result = Iterate(ctx);
359                         if (result.eResult == RESULT_IN_PROGRESS) {
360                             ASSERT(SanityCheckMove(&board,
361                                                    ctx->sPlyInfo[0].PV[0]));
362                             Trace("setboard %s\n", q->szUndoPositionFen);
363                             Trace("gmmove %s\n", q->szMoveInSan);
364                             Trace("solution %s\n",
365                                   MoveToSan(ctx->sPlyInfo[0].PV[0], &board));
366                         }
367                     }
368                 }
369                 p = p->pFlink;
370             }
371         }
372         SystemFreeMemory(pPGN);
373     }
374
375  end:
376     if (NULL != pf)
377     {
378         fclose(pf);
379     }
380
381     if (NULL != ctx)
382     {
383         SystemFreeMemory(ctx);
384     }
385
386     g_Options.fShouldPost = fPost;
387 }
388
389
390 char *
391 FindChunk(char *sz, ULONG uTargetChunk)
392 /**
393
394 Routine description:
395
396     A support routine used by FenToPosition.  Used to parse apart a
397     string and return the Nth chunk of text (delimited by whitespace)
398
399 Parameters:
400
401     char *sz,
402     ULONG uTargetChunk
403
404 Return value:
405
406     char *
407
408 **/
409 {
410     char *p = sz;
411     ULONG u = 0;
412
413     if (0 == uTargetChunk) return(p);
414
415     do
416     {
417         //
418         // Skip whitespace between chunks
419         //
420         while(isspace(*p) && *p) p++;
421         if (!*p) return(NULL);
422
423         u++;
424         if (u == uTargetChunk) return(p);
425
426         //
427         // Skip chunks
428         //
429         while(!isspace(*p) && &p) p++;
430         if (!*p) return(NULL);
431     }
432     while(1);
433
434 #ifdef DEBUG
435     UtilPanic(SHOULD_NOT_GET_HERE,
436               NULL, NULL, NULL, NULL,
437               __FILE__, __LINE__);
438 #endif
439     return(NULL);
440 }
441
442
443
444 CHAR *
445 ScoreToString(SCORE iScore)
446 /**
447
448 Routine description:
449
450     Format a chess score as a string that looks like:
451
452         +0.100
453         -4.951
454         +MATE20
455         -MATE4
456         +0.000
457
458     etc...
459
460     Note: NOT thread safe.
461
462 Parameters:
463
464     SCORE iScore
465
466 Return value:
467
468     CHAR *
469
470 **/
471 {
472     static char szBuf[10];
473     ULONG uDist;
474
475     if (abs(iScore) < +NMATE)
476     {
477         snprintf(szBuf, ARRAY_LENGTH(szBuf),
478                  "%c%u.%02u",
479                  (iScore < 0) ? '-' : '+',
480                  abs(iScore / 100),
481                  abs(iScore % 100));
482         return(szBuf);
483     }
484
485     if (iScore > 0)
486     {
487         uDist = +INFINITY - iScore;
488         uDist /= 2;
489         if (uDist)
490         {
491             snprintf(szBuf, ARRAY_LENGTH(szBuf), "+MATE%u", uDist);
492         }
493         else
494         {
495             snprintf(szBuf, ARRAY_LENGTH(szBuf), "+MATE");
496         }
497     }
498     else
499     {
500         uDist = +INFINITY + iScore;
501         uDist /= 2;
502         if (uDist)
503         {
504             snprintf(szBuf, ARRAY_LENGTH(szBuf), "-MATE%u", uDist);
505         }
506         else
507         {
508             snprintf(szBuf, ARRAY_LENGTH(szBuf), "-MATE");
509         }
510     }
511     return(szBuf);
512 }
513
514
515
516 CHAR *
517 CoorToString(COOR c)
518 /**
519
520 Routine description:
521
522     Take a chessboard coordinate and convert it into a string.  Note:
523     NOT thread safe.
524
525 Parameters:
526
527     COOR c
528
529 Return value:
530
531     CHAR *
532
533 **/
534 {
535     static char buf[3];
536
537     if (IS_ON_BOARD(c))
538     {
539         buf[0] = 'a' + FILE(c);
540         buf[1] = '0' + RANK(c);
541         buf[2] = '\0';
542     }
543     else
544     {
545         buf[0] = '-';
546         buf[1] = '\0';
547     }
548     return(buf);
549 }
550
551
552 CHAR *
553 ColorToString(ULONG u)
554 /**
555
556 Routine description:
557
558     Convert a color into a string ("WHITE" or "BLACK").  Callers
559     should not mess with the contents of the buffer returned!
560
561 Parameters:
562
563     ULONG u
564
565 Return value:
566
567     char
568
569 **/
570 {
571     static CHAR *szColor[2] =
572     {
573         "BLACK",
574         "WHITE"
575     };
576     ASSERT(IS_VALID_COLOR(u));
577     return(szColor[u]);
578 }
579
580
581 CHAR *
582 TimeToString(double d)
583 /**
584
585 Routine description:
586
587     Convert a time value into a string.  e.g.
588
589         00:00:01.021                          // seconds with ms
590         00:15:21.998                          // minutes+seconds
591         01:59:23.232                          // hours+minutes+sec
592         27:08:11:103                          // we don't do days
593
594     Note: NOT thread safe.  The caller should not mess with the
595     buffer returned.
596
597 Parameters:
598
599     double d
600
601 Return value:
602
603     CHAR *
604
605 **/
606 {
607     ULONG uTotalSecs = (ULONG)d;
608     double dFract = d - (double)uTotalSecs;
609     ULONG uHours;
610     ULONG uMinutes;
611     ULONG uFract;
612     static char buf[13];
613
614     dFract *= 1000;
615     uFract = (int)dFract;
616     uHours = uTotalSecs / 60 / 60;
617     uTotalSecs -= uHours * 60 * 60;
618     uMinutes = uTotalSecs / 60;
619     uTotalSecs -= uMinutes * 60;
620     ASSERT(uTotalSecs < 60);
621
622     if (uHours != 0)
623     {
624         snprintf(buf, ARRAY_LENGTH(buf),
625                  "%2u:%02u:%02u.%03u",
626                  uHours, uMinutes, uTotalSecs, uFract);
627     }
628     else
629     {
630         snprintf(buf, ARRAY_LENGTH(buf),
631                  "%02u:%02u.%03u",
632                  uMinutes, uTotalSecs, uFract);
633     }
634     return(buf);
635 }
636
637
638 FLAG
639 BufferIsZeroed(BYTE *p, ULONG u)
640 /**
641
642 Routine description:
643
644     Verify that a buffer is zeroed out.
645
646 Parameters:
647
648     BYTE *p : buffer start
649     ULONG u : buffer length
650
651 Return value:
652
653     FLAG
654
655 **/
656 {
657     while(u)
658     {
659         if (*p != (BYTE)0)
660         {
661             return(FALSE);
662         }
663         p++;
664         u--;
665     }
666     return(TRUE);
667 }
668
669
670 void CDECL
671 Trace(CHAR *szMessage, ...)
672 /**
673
674 Routine description:
675
676     Trace a logging message on stdout and to the logfile
677
678 Parameters:
679
680     CHAR *szMessage,
681     ...
682
683 Return value:
684
685     void
686
687 **/
688 {
689     va_list ap;                            // Variable argument list
690     CHAR buf[MEDIUM_STRING_LEN_CHAR];
691
692     memset(buf, 0, sizeof(buf));
693
694     //
695     // Populate buffer
696     //
697     va_start(ap, szMessage);
698     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
699     va_end(ap);
700
701     //
702     // Send to logfile
703     //
704     if (NULL != g_pfLogfile)
705     {
706         fprintf(g_pfLogfile, buf);
707     }
708
709     //
710     // Send to stdout
711     //
712     fprintf(stdout, buf);
713     fflush(stdout);
714 }
715
716
717 void CDECL
718 Log(CHAR *szMessage, ...)
719 /**
720
721 Routine description:
722
723     Trace a logging message to the logfile only
724
725 Parameters:
726
727     CHAR *szMessage,
728     ...
729
730 Return value:
731
732     void
733
734 **/
735 {
736     va_list ap;                            // Variable argument list
737     CHAR buf[MEDIUM_STRING_LEN_CHAR];
738     memset(buf, 0, sizeof(buf));
739
740     //
741     // Populate buffer
742     //
743     va_start(ap, szMessage);
744     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
745     va_end(ap);
746
747     //
748     // Send to logfile
749     //
750     if (NULL != g_pfLogfile)
751     {
752         fprintf(g_pfLogfile, buf);
753     }
754 }
755
756
757 void CDECL
758 Bug(CHAR *szMessage, ...)
759 /**
760
761 Routine description:
762
763     Trace an error message to stderr and the logfile
764
765 Parameters:
766
767     CHAR *szMessage,
768     ...
769
770 Return value:
771
772     void
773
774 **/
775 {
776     va_list ap;                            // Variable argument list
777     CHAR buf[MEDIUM_STRING_LEN_CHAR];
778
779     memset(buf, 0, sizeof(buf));
780
781     //
782     // Populate buffer
783     //
784     va_start(ap, szMessage);
785     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
786     va_end(ap);
787
788     //
789     // Send it to logfile
790     //
791     if (NULL != g_pfLogfile)
792     {
793         fprintf(g_pfLogfile, buf);
794         fflush(g_pfLogfile);
795     }
796
797     //
798     // Send it to stderr
799     //
800     fprintf(stderr, buf);
801     fflush(stderr);
802 }
803
804
805 #ifdef DEBUG
806 void
807 _assert(CHAR *szFile, ULONG uLine)
808 /**
809
810 Routine description:
811
812     An assertion handler
813
814 Parameters:
815
816     CHAR *szFile,
817     UINT uLine
818
819 Return value:
820
821     void
822
823 **/
824 {
825     Bug("Assertion failure in %s, line %u.\n", szFile, uLine);
826     BREAKPOINT;
827 }
828 #endif
829
830
831 ULONG
832 AcquireSpinLock(volatile ULONG *pSpinlock)
833 /**
834
835 Routine description:
836
837     Atomically acquire a lock or spin trying.
838
839 Parameters:
840
841     ULONG *pSpinlock : a pointer to the lock
842
843 Return value:
844
845     ULONG : the number of times we had to spin
846
847 **/
848 {
849     ULONG uLoops = 0;
850     while(0 != LockCompareExchange(pSpinlock, 1, 0))
851     {
852         uLoops++;
853     }
854     ASSERT(*pSpinlock == 1);
855     return(uLoops);
856 }
857
858 FLAG
859 TryAcquireSpinLock(volatile ULONG *pSpinlock)
860 {
861     return(0 != LockCompareExchange(pSpinlock, 1, 0));
862 }
863
864 void
865 ReleaseSpinLock(volatile ULONG *pSpinlock)
866 /**
867
868 Routine description:
869
870     Release a lock so someone else can acquire it.
871
872 Parameters:
873
874     ULONG *pSpinlock : a pointer to the lock
875
876 Return value:
877
878     void
879
880 **/
881 {
882     ULONG u;
883     ASSERT(*pSpinlock == 1);
884     u = LockCompareExchange(pSpinlock, 0, 1);
885     ASSERT(u == 1);
886 }
887
888
889 FLAG
890 BackupFile(CHAR *szFile)
891 /**
892
893 Routine description:
894
895     Backup a file to file.000.  If file.000 already exists, back it up
896     to file.001 etc...
897
898     Note: this function is recursive and can require quite a lot of
899     stack space.  Also it is full of race conditions and should not be
900     used when some other code may be accessing the filesystem at the
901     same time.
902
903 Parameters:
904
905     CHAR *szFile : the file to backup
906
907 Return value:
908
909     FLAG
910
911 **/
912 {
913     ULONG u;
914     CHAR buf[SMALL_STRING_LEN_CHAR];
915     CHAR *p;
916
917     if (TRUE == SystemDoesFileExist(szFile))
918     {
919         if ((strlen(szFile) > 3) &&
920             (isdigit(szFile[0])) &&
921             (isdigit(szFile[1])) &&
922             (isdigit(szFile[2])))
923         {
924             u = (szFile[0] - '0') * 100;
925             u += (szFile[1] - '0') * 10;
926             u += szFile[2] - '0' + 1;
927             p = &(szFile[3]);
928         }
929         else
930         {
931             u = 0;
932             p = szFile;
933         }
934         snprintf(buf, ARRAY_LENGTH(buf), "%03u%s", u, p);
935         if (TRUE == SystemDoesFileExist(buf))
936         {
937             BackupFile(buf);
938         }
939         return(SystemCopyFile(szFile, buf) && SystemDeleteFile(szFile));
940     }
941     return(FALSE);
942 }
943
944
945 BYTE
946 Checksum(BYTE *p, ULONG uSize)
947 /**
948
949 Routine description:
950
951     Compute the checksum of a buffer.
952
953 Parameters:
954
955     BYTE *p,
956     ULONG uSize
957
958 Return value:
959
960     BYTE
961
962 **/
963 {
964     BYTE b = 0;
965     while(uSize)
966     {
967         b ^= *p;
968         p++;
969         uSize--;
970     }
971     return(b);
972 }
973
974 void
975 FinishPVTailFromHash(SEARCHER_THREAD_CONTEXT *ctx,
976                      CHAR *buf,
977                      ULONG uLenRemain)
978 {
979     MOVE PV[MAX_PLY_PER_SEARCH];
980     MOVE mv;
981     ULONG uPly = ctx->uPly;
982     ULONG uLen;
983 #ifdef DEBUG
984     POSITION board;
985     memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
986 #endif
987
988     if (NULL == g_pHashTable) return;
989     do
990     {
991         mv = GetPonderMove(&ctx->sPosition);
992         if (mv.uMove == 0) break;
993         PV[ctx->uPly] = mv;
994
995         uLen = (ULONG)strlen(MoveToSan(mv, &ctx->sPosition)) + 1;
996         ASSERT(uLen <= 11);
997         if (uLenRemain <= uLen) break;
998         strcat(buf, MoveToSan(PV[ctx->uPly], &ctx->sPosition));
999         strcat(buf, " ");
1000         uLenRemain -= uLen;
1001
1002         if (FALSE == MakeMove(ctx, mv)) break;
1003     }
1004     while(1);
1005
1006     //
1007     // Unmake the moves
1008     //
1009     while(ctx->uPly > uPly)
1010     {
1011         UnmakeMove(ctx, PV[ctx->uPly - 1]);
1012     }
1013     ASSERT(ctx->uPly == uPly);
1014     ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
1015 }
1016
1017
1018
1019 char *
1020 WalkPV(SEARCHER_THREAD_CONTEXT *ctx)
1021 /**
1022
1023 Routine description:
1024
1025     Return a string buffer representing the principle variation.
1026
1027 Parameters:
1028
1029     SEARCHER_THREAD_CONTEXT *ctx
1030
1031 Return value:
1032
1033     CHAR *
1034
1035 **/
1036 {
1037     static CHAR buf[SMALL_STRING_LEN_CHAR];
1038     ULONG u = ctx->uPly;
1039     ULONG v = u;
1040     MOVE mv;
1041 #ifdef DEBUG
1042     POSITION board;
1043     memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
1044 #endif
1045
1046     buf[0] = '\0';
1047     while((mv.uMove = ctx->sPlyInfo[v].PV[u].uMove) != 0)
1048     {
1049         if (mv.uMove == HASHMOVE.uMove)
1050         {
1051             strncat(buf, "<TT> ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1052             FinishPVTailFromHash(ctx, buf, ARRAY_LENGTH(buf) - strlen(buf));
1053             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1054             break;
1055         }
1056         else if (mv.uMove == RECOGNMOVE.uMove)
1057         {
1058             strncat(buf, "<REC>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1059             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1060             break;
1061         }
1062         else if (mv.uMove == DRAWMOVE.uMove)
1063         {
1064             strncat(buf, "<=>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1065             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1066             break;
1067         }
1068         else
1069         {
1070             strncat(buf, MoveToSan(mv, &ctx->sPosition),
1071                     ARRAY_LENGTH(buf) - strlen(buf));
1072             strncat(buf, " ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1073         }
1074
1075         if (FALSE == MakeMove(ctx, mv)) break;
1076         u++;
1077
1078         if (strlen(buf) > (SMALL_STRING_LEN_CHAR - 10)) break;
1079     }
1080
1081     //
1082     // Unmake the moves
1083     //
1084     u--;
1085     while(ctx->uPly > v)
1086     {
1087         UnmakeMove(ctx, ctx->sPlyInfo[v].PV[u]);
1088         u--;
1089     }
1090     ASSERT(ctx->uPly == v);
1091     ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
1092     return(buf);
1093 }
1094
1095
1096 void
1097 UtilPanic(ULONG uPanicCode,
1098           POSITION *pos,
1099           void *arg1, void *arg2, void *arg3,
1100           char *szFile, ULONG uLine)
1101 {
1102     Bug("Typhoon PANIC 0x%x (%p, %p, %p, %p)\n"
1103         "Location: %s at line %u\n\n",
1104         uPanicCode, pos, arg1, arg2, arg3, szFile, uLine);
1105     Banner();
1106     Bug("----------------------------------------------------------------\n");
1107     switch(uPanicCode) {
1108         case CANNOT_INITIALIZE_SPLIT:
1109         case GOT_ILLEGAL_MOVE_WHILE_PONDERING:
1110         case CANNOT_OFFICIALLY_MAKE_MOVE:
1111             DumpPosition(pos);
1112             DumpMove((ULONG)arg1);
1113             break;
1114         case INITIALIZATION_FAILURE:
1115             Bug("%s\n", (char *)arg1);
1116             break;
1117         default:
1118             break;
1119     }
1120     fflush(stdout);
1121     fflush(g_pfLogfile);
1122     BREAKPOINT;
1123     exit(-1);
1124 }
1125
1126 void
1127 UtilPrintPV(SEARCHER_THREAD_CONTEXT *ctx,
1128             SCORE iAlpha,
1129             SCORE iBeta,
1130             SCORE iScore,
1131             MOVE mv)
1132 /**
1133
1134 Routine description:
1135
1136     Print a PV out to stdout and the log.
1137
1138 Parameters:
1139
1140     SEARCHER_THREAD_CONTEXT *ctx,
1141     SCORE iAlpha,
1142     SCORE iBeta,
1143     SCORE iScore,
1144     MOVE mv
1145
1146 Return value:
1147
1148     void
1149
1150 **/
1151 {
1152     double dNow = SystemTimeStamp();
1153
1154     ASSERT(ctx->uThreadNumber == 0);
1155     ASSERT(IS_VALID_SCORE(iAlpha));
1156     ASSERT(IS_VALID_SCORE(iBeta));
1157     ASSERT(iAlpha < iBeta);
1158     ASSERT(IS_VALID_SCORE(iScore));
1159
1160     dNow -= g_MoveTimer.dStartTime;
1161
1162     //
1163     // Set the last PV in the context if we have a root PV or a root
1164     // fail high.
1165     //
1166     if ((iAlpha < iScore) && (iScore < iBeta))
1167     {
1168         strncpy(ctx->szLastPV, WalkPV(ctx), SMALL_STRING_LEN_CHAR);
1169     }
1170     else if (iScore > iBeta)
1171     {
1172         strncpy(ctx->szLastPV, MoveToSan(mv, &(ctx->sPosition)),
1173                 SMALL_STRING_LEN_CHAR);
1174     }
1175
1176     if ((TRUE == g_Options.fThinking) && (TRUE == g_Options.fShouldPost))
1177     {
1178         //
1179         // Maybe output the PV.  Note: xboard gets confused by PV
1180         // lines that don't match its requirements exactly; if we are
1181         // running under xboard, match its expected format.  Otherwise
1182         // be more helpful / verbose.
1183         //
1184         if ((dNow > 0.35) || ((dNow > 0.15) && (g_Options.fVerbosePosting)))
1185         {
1186             if (TRUE == g_Options.fRunningUnderXboard)
1187             {
1188                 if ((iAlpha < iScore) && (iScore < iBeta))
1189                 {
1190                     Trace("%2u %6d %5u %-12"
1191                           COMPILER_LONGLONG_UNSIGNED_FORMAT" %s\n",
1192                           g_uIterateDepth,
1193                           iScore,
1194                           (ULONG)(dNow * 100),
1195                           ctx->sCounters.tree.u64TotalNodeCount,
1196                           ctx->szLastPV);
1197                 }
1198                 else if (iScore <= iAlpha)
1199                 {
1200                     Trace("%2u %6d %5u %-12"
1201                           COMPILER_LONGLONG_UNSIGNED_FORMAT" FL --\n",
1202                           g_uIterateDepth,
1203                           iScore,
1204                           (ULONG)(dNow * 100),
1205                           ctx->sCounters.tree.u64TotalNodeCount);
1206                 }
1207                 else
1208                 {
1209                     ASSERT(iScore >= iBeta);
1210                     Trace("%2u %6d %5u %-12"
1211                           COMPILER_LONGLONG_UNSIGNED_FORMAT" %s ++\n",
1212                           g_uIterateDepth,
1213                           iScore,
1214                           (ULONG)(dNow * 100),
1215                           ctx->sCounters.tree.u64TotalNodeCount,
1216                           ctx->szLastPV);
1217                 }
1218             }
1219             else // !running under xboard
1220             {
1221                 if ((iAlpha < iScore) && (iScore < iBeta))
1222                 {
1223                     Trace("%2u  %5s  %-9s  %-11"
1224                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  %s\n",
1225                           g_uIterateDepth,
1226                           ScoreToString(iScore),
1227                           TimeToString(dNow),
1228                           ctx->sCounters.tree.u64TotalNodeCount,
1229                           ctx->szLastPV);
1230                 }
1231                 else if (iScore <= iAlpha)
1232                 {
1233                     Trace("%2u- %5s  %-9s  %-11"
1234                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  FL --\n",
1235                           g_uIterateDepth,
1236                           ScoreToString(iScore),
1237                           TimeToString(dNow),
1238                           ctx->sCounters.tree.u64TotalNodeCount);
1239                 }
1240                 else
1241                 {
1242                     ASSERT(iScore >= iBeta);
1243                     Trace("%2u+ %5s  %-9s  %-11"
1244                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  %s ++\n",
1245                           g_uIterateDepth,
1246                           ScoreToString(iScore),
1247                           TimeToString(dNow),
1248                           ctx->sCounters.tree.u64TotalNodeCount,
1249                           ctx->szLastPV);
1250                 }
1251             }
1252         }
1253     }
1254 }