Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / 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 355 2008-07-01 15:46:43Z 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         fprintf(g_pfLogfile, "%s", buf);
706     }
707
708     //
709     // Send to stdout
710     //
711     fprintf(stdout, "%s", buf);
712     fflush(stdout);
713 }
714
715
716 void CDECL
717 Log(CHAR *szMessage, ...)
718 /**
719
720 Routine description:
721
722     Trace a logging message to the logfile only
723
724 Parameters:
725
726     CHAR *szMessage,
727     ...
728
729 Return value:
730
731     void
732
733 **/
734 {
735     va_list ap;                            // Variable argument list
736     CHAR buf[MEDIUM_STRING_LEN_CHAR];
737     memset(buf, 0, sizeof(buf));
738
739     //
740     // Populate buffer
741     //
742     va_start(ap, szMessage);
743     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
744     va_end(ap);
745
746     //
747     // Send to logfile
748     //
749     if (NULL != g_pfLogfile) {
750         fprintf(g_pfLogfile, "%s", buf);
751         fflush(g_pfLogfile);
752     }
753 }
754
755
756 void CDECL
757 Bug(CHAR *szMessage, ...)
758 /**
759
760 Routine description:
761
762     Trace an error message to stderr and the logfile
763
764 Parameters:
765
766     CHAR *szMessage,
767     ...
768
769 Return value:
770
771     void
772
773 **/
774 {
775     va_list ap;                            // Variable argument list
776     CHAR buf[MEDIUM_STRING_LEN_CHAR];
777
778     memset(buf, 0, sizeof(buf));
779
780     //
781     // Populate buffer
782     //
783     va_start(ap, szMessage);
784     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 1, szMessage, ap);
785     va_end(ap);
786
787     //
788     // Send it to logfile
789     //
790     if (NULL != g_pfLogfile) {
791         fprintf(g_pfLogfile, "%s", buf);
792         fflush(g_pfLogfile);
793     }
794
795     //
796     // Send it to stderr
797     //
798     fprintf(stderr, "%s", buf);
799     fflush(stderr);
800 }
801
802
803 #ifdef DEBUG
804 void
805 _assert(CHAR *szFile, ULONG uLine)
806 /**
807
808 Routine description:
809
810     An assertion handler
811
812 Parameters:
813
814     CHAR *szFile,
815     UINT uLine
816
817 Return value:
818
819     void
820
821 **/
822 {
823     Bug("Assertion failure in %s, line %u.\n", szFile, uLine);
824     BREAKPOINT;
825 }
826 #endif
827
828
829 ULONG
830 AcquireSpinLock(volatile ULONG *pSpinlock)
831 /**
832
833 Routine description:
834
835     Atomically acquire a lock or spin trying.
836
837 Parameters:
838
839     ULONG *pSpinlock : a pointer to the lock
840
841 Return value:
842
843     ULONG : the number of times we had to spin
844
845 **/
846 {
847     ULONG uLoops = 0;
848     while(0 != LockCompareExchange(pSpinlock, 1, 0))
849     {
850         uLoops++;
851     }
852     ASSERT(*pSpinlock == 1);
853     return(uLoops);
854 }
855
856 FLAG
857 TryAcquireSpinLock(volatile ULONG *pSpinlock)
858 {
859     return(0 != LockCompareExchange(pSpinlock, 1, 0));
860 }
861
862 void
863 ReleaseSpinLock(volatile ULONG *pSpinlock)
864 /**
865
866 Routine description:
867
868     Release a lock so someone else can acquire it.
869
870 Parameters:
871
872     ULONG *pSpinlock : a pointer to the lock
873
874 Return value:
875
876     void
877
878 **/
879 {
880     ULONG u;
881     ASSERT(*pSpinlock == 1);
882     u = LockCompareExchange(pSpinlock, 0, 1);
883     ASSERT(u == 1);
884 }
885
886
887 FLAG
888 BackupFile(CHAR *szFile)
889 /**
890
891 Routine description:
892
893     Backup a file to file.000.  If file.000 already exists, back it up
894     to file.001 etc...
895
896     Note: this function is recursive and can require quite a lot of
897     stack space.  Also it is full of race conditions and should not be
898     used when some other code may be accessing the filesystem at the
899     same time.
900
901 Parameters:
902
903     CHAR *szFile : the file to backup
904
905 Return value:
906
907     FLAG
908
909 **/
910 {
911     ULONG u;
912     CHAR buf[SMALL_STRING_LEN_CHAR];
913     CHAR *p;
914
915     if (TRUE == SystemDoesFileExist(szFile))
916     {
917         if ((strlen(szFile) > 3) &&
918             (isdigit(szFile[0])) &&
919             (isdigit(szFile[1])) &&
920             (isdigit(szFile[2])))
921         {
922             u = (szFile[0] - '0') * 100;
923             u += (szFile[1] - '0') * 10;
924             u += szFile[2] - '0' + 1;
925             p = &(szFile[3]);
926         }
927         else
928         {
929             u = 0;
930             p = szFile;
931         }
932         snprintf(buf, ARRAY_LENGTH(buf), "%03u%s", u, p);
933         if (TRUE == SystemDoesFileExist(buf))
934         {
935             BackupFile(buf);
936         }
937         return(SystemCopyFile(szFile, buf) && SystemDeleteFile(szFile));
938     }
939     return(FALSE);
940 }
941
942
943 BYTE
944 Checksum(BYTE *p, ULONG uSize)
945 /**
946
947 Routine description:
948
949     Compute the checksum of a buffer.
950
951 Parameters:
952
953     BYTE *p,
954     ULONG uSize
955
956 Return value:
957
958     BYTE
959
960 **/
961 {
962     BYTE b = 0;
963     while(uSize)
964     {
965         b ^= *p;
966         p++;
967         uSize--;
968     }
969     return(b);
970 }
971
972 void
973 FinishPVTailFromHash(SEARCHER_THREAD_CONTEXT *ctx,
974                      CHAR *buf,
975                      ULONG uLenRemain)
976 {
977     MOVE PV[MAX_PLY_PER_SEARCH];
978     MOVE mv;
979     ULONG uPly = ctx->uPly;
980     ULONG uLen;
981 #ifdef DEBUG
982     POSITION board;
983     memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
984 #endif
985
986     if (NULL == g_pHashTable) return;
987     do
988     {
989         mv = GetPonderMove(&ctx->sPosition);
990         if (mv.uMove == 0) break;
991         PV[ctx->uPly] = mv;
992
993         uLen = (ULONG)strlen(MoveToSan(mv, &ctx->sPosition)) + 1;
994         ASSERT(uLen <= 11);
995         if (uLenRemain <= uLen) break;
996         strcat(buf, MoveToSan(PV[ctx->uPly], &ctx->sPosition));
997         strcat(buf, " ");
998         uLenRemain -= uLen;
999
1000         if (FALSE == MakeMove(ctx, mv)) break;
1001     }
1002     while(1);
1003
1004     //
1005     // Unmake the moves
1006     //
1007     while(ctx->uPly > uPly)
1008     {
1009         UnmakeMove(ctx, PV[ctx->uPly - 1]);
1010     }
1011     ASSERT(ctx->uPly == uPly);
1012     ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
1013 }
1014
1015
1016
1017 char *
1018 WalkPV(SEARCHER_THREAD_CONTEXT *ctx)
1019 /**
1020
1021 Routine description:
1022
1023     Return a string buffer representing the principle variation.
1024
1025 Parameters:
1026
1027     SEARCHER_THREAD_CONTEXT *ctx
1028
1029 Return value:
1030
1031     CHAR *
1032
1033 **/
1034 {
1035     static CHAR buf[SMALL_STRING_LEN_CHAR];
1036     ULONG u = ctx->uPly;
1037     ULONG v = u;
1038     MOVE mv;
1039 #ifdef DEBUG
1040     POSITION board;
1041     memcpy(&board, &(ctx->sPosition), sizeof(POSITION));
1042 #endif
1043
1044     buf[0] = '\0';
1045     while((mv.uMove = ctx->sPlyInfo[v].PV[u].uMove) != 0)
1046     {
1047         if (mv.uMove == HASHMOVE.uMove)
1048         {
1049             strncat(buf, "<TT> ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1050             FinishPVTailFromHash(ctx, buf, ARRAY_LENGTH(buf) - strlen(buf));
1051             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1052             break;
1053         }
1054         else if (mv.uMove == RECOGNMOVE.uMove)
1055         {
1056             strncat(buf, "<REC>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1057             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1058             break;
1059         }
1060         else if (mv.uMove == DRAWMOVE.uMove)
1061         {
1062             strncat(buf, "<=>", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1063             ASSERT(ctx->sPlyInfo[v].PV[u+1].uMove == 0);
1064             break;
1065         }
1066         else
1067         {
1068             strncat(buf, MoveToSan(mv, &ctx->sPosition),
1069                     ARRAY_LENGTH(buf) - strlen(buf));
1070             strncat(buf, " ", ARRAY_LENGTH(buf) - strlen(buf) - 1);
1071         }
1072
1073         if (FALSE == MakeMove(ctx, mv)) break;
1074         u++;
1075
1076         if (strlen(buf) > (SMALL_STRING_LEN_CHAR - 10)) break;
1077     }
1078
1079     //
1080     // Unmake the moves
1081     //
1082     u--;
1083     while(ctx->uPly > v)
1084     {
1085         UnmakeMove(ctx, ctx->sPlyInfo[v].PV[u]);
1086         u--;
1087     }
1088     ASSERT(ctx->uPly == v);
1089     ASSERT(PositionsAreEquivalent(&board, &ctx->sPosition));
1090     return(buf);
1091 }
1092
1093
1094 void
1095 UtilPanic(ULONG uPanicCode,
1096           POSITION *pos,
1097           void *arg1, void *arg2, void *arg3,
1098           char *szFile, ULONG uLine)
1099 {
1100     Bug("Typhoon PANIC 0x%x (%p, %p, %p, %p)\n"
1101         "Location: %s at line %u\n\n",
1102         uPanicCode, pos, arg1, arg2, arg3, szFile, uLine);
1103     Banner();
1104     Bug("----------------------------------------------------------------\n");
1105     switch(uPanicCode) {
1106         case CANNOT_INITIALIZE_SPLIT:
1107         case GOT_ILLEGAL_MOVE_WHILE_PONDERING:
1108         case CANNOT_OFFICIALLY_MAKE_MOVE:
1109             DumpPosition(pos);
1110             DumpMove((ULONG)arg1);
1111             break;
1112         case INITIALIZATION_FAILURE:
1113             Bug("%s\n", (char *)arg1);
1114             break;
1115         default:
1116             break;
1117     }
1118     fflush(stdout);
1119     fflush(g_pfLogfile);
1120     BREAKPOINT;
1121     exit(-1);
1122 }
1123
1124 void
1125 UtilPrintPV(SEARCHER_THREAD_CONTEXT *ctx,
1126             SCORE iAlpha,
1127             SCORE iBeta,
1128             SCORE iScore,
1129             MOVE mv)
1130 /**
1131
1132 Routine description:
1133
1134     Print a PV out to stdout and the log.
1135
1136 Parameters:
1137
1138     SEARCHER_THREAD_CONTEXT *ctx,
1139     SCORE iAlpha,
1140     SCORE iBeta,
1141     SCORE iScore,
1142     MOVE mv
1143
1144 Return value:
1145
1146     void
1147
1148 **/
1149 {
1150     double dNow = SystemTimeStamp();
1151
1152     ASSERT(ctx->uThreadNumber == 0);
1153     ASSERT(IS_VALID_SCORE(iAlpha));
1154     ASSERT(IS_VALID_SCORE(iBeta));
1155     ASSERT(iAlpha < iBeta);
1156     ASSERT(IS_VALID_SCORE(iScore));
1157
1158     dNow -= g_MoveTimer.dStartTime;
1159
1160     //
1161     // Set the last PV in the context if we have a root PV or a root
1162     // fail high.
1163     //
1164     if ((iAlpha < iScore) && (iScore < iBeta))
1165     {
1166         strncpy(ctx->szLastPV, WalkPV(ctx), SMALL_STRING_LEN_CHAR);
1167     }
1168     else if (iScore > iBeta)
1169     {
1170         strncpy(ctx->szLastPV, MoveToSan(mv, &(ctx->sPosition)),
1171                 SMALL_STRING_LEN_CHAR);
1172     }
1173
1174     if ((TRUE == g_Options.fThinking) && (TRUE == g_Options.fShouldPost))
1175     {
1176         //
1177         // Maybe output the PV.  Note: xboard gets confused by PV
1178         // lines that don't match its requirements exactly; if we are
1179         // running under xboard, match its expected format.  Otherwise
1180         // be more helpful / verbose.
1181         //
1182         if ((dNow > 0.35) || ((dNow > 0.15) && (g_Options.fVerbosePosting)))
1183         {
1184             if (TRUE == g_Options.fRunningUnderXboard)
1185             {
1186                 if ((iAlpha < iScore) && (iScore < iBeta))
1187                 {
1188                     Trace("%2u %6d %5u %-12"
1189                           COMPILER_LONGLONG_UNSIGNED_FORMAT" %s\n",
1190                           g_uIterateDepth,
1191                           iScore,
1192                           (ULONG)(dNow * 100),
1193                           ctx->sCounters.tree.u64TotalNodeCount,
1194                           ctx->szLastPV);
1195                 }
1196                 else if (iScore <= iAlpha)
1197                 {
1198                     Trace("%2u %6d %5u %-12"
1199                           COMPILER_LONGLONG_UNSIGNED_FORMAT" FL --\n",
1200                           g_uIterateDepth,
1201                           iScore,
1202                           (ULONG)(dNow * 100),
1203                           ctx->sCounters.tree.u64TotalNodeCount);
1204                 }
1205                 else
1206                 {
1207                     ASSERT(iScore >= iBeta);
1208                     Trace("%2u %6d %5u %-12"
1209                           COMPILER_LONGLONG_UNSIGNED_FORMAT" %s ++\n",
1210                           g_uIterateDepth,
1211                           iScore,
1212                           (ULONG)(dNow * 100),
1213                           ctx->sCounters.tree.u64TotalNodeCount,
1214                           ctx->szLastPV);
1215                 }
1216             }
1217             else // !running under xboard
1218             {
1219                 if ((iAlpha < iScore) && (iScore < iBeta))
1220                 {
1221                     Trace("%2u  %5s  %-9s  %-11"
1222                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  %s\n",
1223                           g_uIterateDepth,
1224                           ScoreToString(iScore),
1225                           TimeToString(dNow),
1226                           ctx->sCounters.tree.u64TotalNodeCount,
1227                           ctx->szLastPV);
1228                 }
1229                 else if (iScore <= iAlpha)
1230                 {
1231                     Trace("%2u- %5s  %-9s  %-11"
1232                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  FL --\n",
1233                           g_uIterateDepth,
1234                           ScoreToString(iScore),
1235                           TimeToString(dNow),
1236                           ctx->sCounters.tree.u64TotalNodeCount);
1237                 }
1238                 else
1239                 {
1240                     ASSERT(iScore >= iBeta);
1241                     Trace("%2u+ %5s  %-9s  %-11"
1242                           COMPILER_LONGLONG_UNSIGNED_FORMAT"  %s ++\n",
1243                           g_uIterateDepth,
1244                           ScoreToString(iScore),
1245                           TimeToString(dNow),
1246                           ctx->sCounters.tree.u64TotalNodeCount,
1247                           ctx->szLastPV);
1248                 }
1249             }
1250         }
1251     }
1252 }