3 Copyright (c) Scott Gasch
11 Program entry point and setup code.
19 $Id: main.c 355 2008-07-01 15:46:43Z scott $
25 FILE *g_pfLogfile = NULL;
26 GAME_OPTIONS g_Options;
27 CHAR g_szInitialCommand[SMALL_STRING_LEN_CHAR];
28 ULONG g_uInputThreadHandle = (ULONG)-1;
36 Describe the compile/build options and program version.
50 Trace("Typhoon %s (built on %s %s):\n", VERSION, __DATE__, __TIME__);
53 Trace(" " COMPILER_STRING);
54 Trace(" Make profile used: %s\n", PROFILE);
56 Trace(" Multiprocessor enabled; %u searcher thread%s\n",
57 g_Options.uNumProcessors, (g_Options.uNumProcessors > 1) ? "s" : "");
59 Trace(" Single processor version\n");
62 Trace(" DEBUG build\n");
65 Trace(" Testcode compiled in\n");
68 Trace(" Evaluation terms\n");
71 Trace(" Evaluation timing\n");
74 Trace(" Performance counters\n");
76 Trace(" Testing nullmove prediction algorithms\n");
80 Trace(" Search tree dumpfile generation enabled\n");
82 Trace(" Hash sizes: %u Mb (main), %u Mb / thread (pawn), %u Mb / thread (eval)\n",
83 (g_uHashTableSizeEntries * sizeof(HASH_ENTRY)) / MB,
84 PAWN_HASH_TABLE_SIZE * sizeof(PAWN_HASH_ENTRY) / MB,
85 EVAL_HASH_TABLE_SIZE * sizeof(EVAL_HASH_ENTRY) / MB);
86 Trace(" QCheckPlies: %u\n", QPLIES_OF_NON_CAPTURE_CHECKS);
87 Trace(" FutilityBase: %u\n", FUTILITY_BASE_MARGIN);
89 Trace(" Logging Eval DNA.\n");
93 Trace(" IID R-factor: %u ply\n", IID_R_FACTOR / ONE_PLY);
104 Close the main logfile.
116 if (NULL != g_pfLogfile) {
131 Open the main logfile.
143 if (NULL != g_pfLogfile) {
146 if (!strlen(g_Options.szLogfile) ||
147 !strcmp(g_Options.szLogfile, "-")) {
151 // If the logfile we want to write already exists, back it up.
152 if (TRUE == SystemDoesFileExist(g_Options.szLogfile)) {
153 VERIFY(BackupFile(g_Options.szLogfile));
155 ASSERT(FALSE == SystemDoesFileExist(g_Options.szLogfile));
157 g_pfLogfile = fopen(g_Options.szLogfile, "wb+");
158 if (NULL == g_pfLogfile) {
159 UtilPanic(INITIALIZATION_FAILURE,
160 (void *)"Can't open logfile",
161 (void *)&(g_Options.szLogfile),
171 PreGameReset(FLAG fResetBoard)
176 Reset internal state between games.
188 if (TRUE == fResetBoard)
190 SetRootToInitialPosition();
193 ClearDynamicMoveOrdering();
201 _ParseHashOption(char *p,
207 if ((!STRCMPI(p, "none")) || (!STRCMPI(p, "no"))) return(0);
208 if (2 == sscanf(p, "%u%1c", &u, &c))
223 u *= 1024 * 1024 * 1024;
226 Trace("Error (unrecognized size): \"%s\"\n", p);
231 Trace("Error (size too large): \"%s\"\n", p);
241 while(!IS_A_POWER_OF_2(u))
251 InitializeOptions(int argc, char *argv[])
256 Set global options to their initial state. This code also is
257 responsible for parsing the commandline in order to override the
258 default state of global options.
276 memset(&g_Options, 0, sizeof(g_Options));
277 g_szInitialCommand[0] = '\0';
278 g_Options.uMyClock = g_Options.uOpponentsClock = 600;
279 g_Options.fGameIsRated = FALSE;
280 g_Options.fOpponentIsComputer = FALSE;
281 g_Options.uSecPerMove = 0;
282 g_Options.uMaxDepth = MAX_PLY_PER_SEARCH - 1;
283 g_Options.fShouldPonder = TRUE;
284 g_Options.fPondering = g_Options.fThinking = FALSE;
285 g_Options.mvPonder.uMove = 0;
286 g_Options.fShouldPost = TRUE;
287 g_Options.fForceDrawWorthZero = FALSE;
288 g_Options.uMyIncrement = 0;
289 g_Options.uMovesPerTimePeriod = 0;
290 g_Options.szAnalyzeProgressReport[0] = '\0';
291 g_Options.fShouldAnnounceOpening = TRUE;
292 g_Options.eClock = CLOCK_NONE;
293 g_Options.eGameType = GAME_UNKNOWN;
294 g_Options.ePlayMode = FORCE_MODE;
295 g_Options.fNoInputThread = FALSE;
296 g_Options.fVerbosePosting = TRUE;
297 strcpy(g_Options.szEGTBPath, "/egtb/three;/etc/four;/egtb/five");
298 strcpy(g_Options.szLogfile, "typhoon.log");
299 strcpy(g_Options.szBookName, "book.bin");
300 g_Options.uNumHashTableEntries = 0x10000;
301 g_Options.uNumProcessors = 1;
302 g_Options.fStatusLine = TRUE;
303 g_Options.iResignThreshold = 0;
304 g_Options.u64MaxNodeCount = 0ULL;
310 if ((!STRCMPI(argv[i], "--cpus")) && (argc > i))
312 g_Options.uNumProcessors = (ULONG)atoi(argv[i+1]);
313 if ((g_Options.uNumProcessors == 0) ||
314 (g_Options.uNumProcessors > 64))
316 g_Options.uNumProcessors = 2;
322 if ((!STRCMPI(argv[i], "--command")) && (argc > i))
324 strncpy(g_szInitialCommand,
326 SMALL_STRING_LEN_CHAR - 2);
327 strcat(g_szInitialCommand, "\r\n");
330 else if ((!STRCMPI(argv[i], "--hash")) && (argc > i))
332 g_Options.uNumHashTableEntries =
333 _ParseHashOption(argv[i+1],
337 else if ((!STRCMPI(argv[i], "--egtbpath")) && (argc > i))
339 if (!strcmp(argv[i+1], "-")) {
340 g_Options.szEGTBPath[0] = '\0';
342 strncpy(g_Options.szEGTBPath, argv[i+1], SMALL_STRING_LEN_CHAR);
346 else if (!STRCMPI(argv[i], "--book") && argc > i)
348 if (!strcmp(argv[i+1], "-")) {
349 g_Options.szBookName[0] = '\0';
351 strncpy(g_Options.szBookName, argv[i+1], SMALL_STRING_LEN_CHAR);
355 else if (!STRCMPI(argv[i], "--batch"))
357 g_Options.fNoInputThread = TRUE;
359 else if ((!STRCMPI(argv[i], "--dnafile")) && (argc > i))
361 if (!ReadEvalDNA(argv[i+1]))
363 UtilPanic(INITIALIZATION_FAILURE,
364 (void *)"Bad DNA file",
365 (void *)&(argv[i+1]),
372 else if ((!STRCMPI(argv[i], "--logfile")) && (argc > i))
374 strncpy(g_Options.szLogfile, argv[i+1],
375 SMALL_STRING_LEN_CHAR);
378 else if (!STRCMPI(argv[i], "--help")) {
379 Trace("Usage: %s [--batch] [--command arg] [--logfile arg] [--egtbpath arg]\n"
380 " [--dnafile arg] [--cpus arg] [--hash arg]\n\n"
381 " --batch : operate the engine without an input thread\n"
382 " --book : specify the opening book to use or '-' for none\n"
383 " --command : specify initial command(s) (requires arg)\n"
384 " --cpus : indicate the number of cpus to use (1..64)\n"
385 " --hash : indicate desired hash size (e.g. 16m, 1g)\n"
386 " --egtbpath : supplies the egtb path or '-' for none\n"
387 " --logfile : indicate desired output logfile name or '-' for none\n"
388 " --dnafile : indicate desired eval profile input (requres arg)\n\n"
389 "Example: %s --hash 256m --cpus 2\n"
390 " %s --logfile test.out --batch --command \"test\" --dnafile test.in\n", argv[0], argv[0], argv[0]);
395 Trace("Error (unknown argument): \"%s\"; try --help\n", argv[i]);
399 // TODO: parse other commandline options and override above
430 MainProgramInitialization(int argc, char *argv[])
435 Perform main program initialization. This includes stuff like:
436 precomputing some data structures, resetting the global options,
437 parsing the commandline to override said options, and calling out
438 to other modules to tell them to initialize themselves.
451 srand((unsigned int)time(0));
452 InitializeOptions(argc, argv);
453 InitializeTreeDump();
455 InitializeSigSystem();
456 InitializeInteriorNodeRecognizers();
457 InitializeSearchDepthArray();
458 InitializeWhiteSquaresTable();
459 InitializeVectorDeltaTable();
460 InitializeSwapTable();
461 InitializeDistanceTable();
462 InitializeOpeningBook();
463 InitializeDynamicMoveOrdering();
464 InitializeHashSystem();
465 InitializePositionHashSystem();
467 InitializeParallelSearch();
469 VERIFY(PreGameReset(TRUE));
470 (void)BeginLogging();
476 MainProgramCleanup(void)
481 Perform main program cleanup. Tear down the stuff we set up in
482 MainProgramInitialization.
494 CleanupOpeningBook();
496 CleanupDynamicMoveOrdering();
498 CleanupParallelSearch();
500 CleanupPositionHashSystem();
511 RunStartupProgramTest(void)
516 If we built this version with -DTEST then this code is the start
517 of the self-test that runs at program startup time.
532 Trace("Testing CPP macros...\n");
533 for (u = 0; u < 1000000; u++)
537 x = x & ~(0x80000000);
538 y = y & ~(0x80000000);
540 if (MAX(x, y) != MAXU(x, y))
542 UtilPanic(TESTCASE_FAILURE,
543 NULL, "max maxu", NULL, NULL, __FILE__, __LINE__);
546 if (MAXU(x, y) != MAXU(y, x))
548 UtilPanic(TESTCASE_FAILURE,
549 NULL, "maxu assoc", NULL, NULL, __FILE__, __LINE__);
552 if (MIN(x, y) != MINU(x, y))
554 UtilPanic(TESTCASE_FAILURE,
555 NULL, "min minu", NULL, NULL, __FILE__, __LINE__);
558 if (MINU(x, y) != MINU(y, x))
560 UtilPanic(TESTCASE_FAILURE,
561 NULL, "minu assoc", NULL, NULL, __FILE__, __LINE__);
564 if (abs(x - y) != ABS_DIFF(x, y))
566 UtilPanic(TESTCASE_FAILURE,
567 NULL, "abs_diff", NULL, NULL, __FILE__, __LINE__);
570 if (ABS_DIFF(x, y) != ABS_DIFF(y, x))
572 UtilPanic(TESTCASE_FAILURE,
573 NULL, "abs_diff assoc", NULL, NULL, __FILE__, __LINE__);
587 TestLegalMoveGenerator();
589 TestLiftPlaceSlidePiece();
592 TestMakeUnmakeMove();
601 void DeclareTerminalStates(GAME_RESULT result) {
602 switch(result.eResult) {
603 case RESULT_IN_PROGRESS:
605 case RESULT_BLACK_WON:
606 Trace("0-1 {%s}\n", result.szDescription);
607 SetGameResultAndDescription(result);
609 g_Options.ePlayMode = FORCE_MODE;
611 case RESULT_WHITE_WON:
612 Trace("1-0 {%s}\n", result.szDescription);
613 SetGameResultAndDescription(result);
615 g_Options.ePlayMode = FORCE_MODE;
618 Trace("1/2-1/2 {%s}\n", result.szDescription);
619 Trace("tellics draw\n");
620 SetGameResultAndDescription(result);
622 g_Options.ePlayMode = FORCE_MODE;
624 case RESULT_ABANDONED:
627 SetGameResultAndDescription(result);
629 g_Options.ePlayMode = FORCE_MODE;
636 void MainProgramLoop() {
642 while (!g_fExitProgram) {
644 // Prepare to search or ponder
645 memcpy(&pos, GetRootPosition(), sizeof(POSITION));
646 fThink = fPonder = FALSE;
647 result.eResult = RESULT_IN_PROGRESS;
648 result.szDescription[0] = '\0';
650 // What should we do?
651 switch(g_Options.ePlayMode) {
653 fThink = (pos.uToMove == WHITE);
654 fPonder = (pos.uToMove == BLACK);
657 fThink = (pos.uToMove == BLACK);
658 fPonder = (pos.uToMove == WHITE);
662 fThink = fPonder = FALSE;
667 result = Think(&pos);
668 if ((NumberOfPendingInputEvents() != 0) &&
669 (FALSE == g_fExitProgram))
672 ParseUserInput(FALSE);
674 DeclareTerminalStates(result);
675 } else if (fPonder) {
676 if (g_Options.fShouldPonder) {
677 result = Ponder(&pos);
679 if (FALSE == g_fExitProgram)
682 ParseUserInput(FALSE);
684 DeclareTerminalStates(result);
687 ParseUserInput(FALSE);
694 main(int argc, char *argv[])
699 Chess engine entry point and main loop.
712 // Initial setup work...
713 Trace("Setting up, please wait...\n");
714 if (FALSE == SystemDependentInitialization())
716 Trace("main: Operating system dependent init code failed, "
720 if (FALSE == MainProgramInitialization(argc, argv))
722 Trace("main: Main program init code failed, aborting.\n");
727 (void)RunStartupProgramTest();
729 if (TRUE == g_Options.fNoInputThread)
731 InitInputSystemInBatchMode();
735 g_uInputThreadHandle = InitInputSystemWithDedicatedThread();
738 // Enter the main work loop code...
741 // If we get here g_fExitProgram is set -- clean up.
742 Trace("MAIN THREAD: thread terminating.\n");
743 if (FALSE == MainProgramCleanup())
745 Trace("main: Main program cleanup code failed, aborting.\n");