3 Copyright (c) Scott Gasch
11 Program entry point and setup code.
19 $Id: main.c 351 2008-06-28 04:21:53Z 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)
132 Open the main logfile.
144 if (NULL != g_pfLogfile)
148 ASSERT(g_pfLogfile == NULL);
149 ASSERT(strlen(g_Options.szLogfile));
152 // If the logfile we want to write already exists, back it up.
154 if (TRUE == SystemDoesFileExist(g_Options.szLogfile))
156 VERIFY(BackupFile(g_Options.szLogfile));
158 ASSERT(FALSE == SystemDoesFileExist(g_Options.szLogfile));
160 g_pfLogfile = fopen(g_Options.szLogfile, "wb+");
161 if (NULL == g_pfLogfile)
163 UtilPanic(INITIALIZATION_FAILURE,
164 (void *)"Can't open logfile",
165 (void *)&(g_Options.szLogfile),
175 PreGameReset(FLAG fResetBoard)
180 Reset internal state between games.
192 if (TRUE == fResetBoard)
194 SetRootToInitialPosition();
197 ClearDynamicMoveOrdering();
205 _ParseHashOption(char *p,
211 if ((!STRCMPI(p, "none")) || (!STRCMPI(p, "no"))) return(0);
212 if (2 == sscanf(p, "%u%1c", &u, &c))
227 u *= 1024 * 1024 * 1024;
230 Trace("Error (unrecognized size): \"%s\"\n", p);
235 Trace("Error (size too large): \"%s\"\n", p);
245 while(!IS_A_POWER_OF_2(u))
255 InitializeOptions(int argc, char *argv[])
260 Set global options to their initial state. This code also is
261 responsible for parsing the commandline in order to override the
262 default state of global options.
280 memset(&g_Options, 0, sizeof(g_Options));
281 g_szInitialCommand[0] = '\0';
282 g_Options.uMyClock = g_Options.uOpponentsClock = 600;
283 g_Options.fGameIsRated = FALSE;
284 g_Options.fOpponentIsComputer = FALSE;
285 g_Options.uSecPerMove = 0;
286 g_Options.uMaxDepth = MAX_PLY_PER_SEARCH - 1;
287 g_Options.fShouldPonder = TRUE;
288 g_Options.fPondering = g_Options.fThinking = FALSE;
289 g_Options.mvPonder.uMove = 0;
290 g_Options.fShouldPost = TRUE;
291 g_Options.fForceDrawWorthZero = FALSE;
292 g_Options.uMyIncrement = 0;
293 g_Options.uMovesPerTimePeriod = 0;
294 g_Options.szAnalyzeProgressReport[0] = '\0';
295 g_Options.fShouldAnnounceOpening = TRUE;
296 g_Options.eClock = CLOCK_NONE;
297 g_Options.eGameType = GAME_UNKNOWN;
298 g_Options.ePlayMode = FORCE_MODE;
299 g_Options.fNoInputThread = FALSE;
300 g_Options.fVerbosePosting = TRUE;
301 strcpy(g_Options.szEGTBPath, "/egtb/three;/etc/four;/egtb/five");
302 strcpy(g_Options.szLogfile, "typhoon.log");
303 strcpy(g_Options.szBookName, "book.bin");
304 g_Options.uNumHashTableEntries = 0x10000;
305 g_Options.uNumProcessors = 1;
306 g_Options.fStatusLine = TRUE;
307 g_Options.fShouldResign = FALSE;
308 g_Options.u64MaxNodeCount = 0ULL;
314 if ((!STRCMPI(argv[i], "--cpus")) && (argc > i))
316 g_Options.uNumProcessors = (ULONG)atoi(argv[i+1]);
317 if ((g_Options.uNumProcessors == 0) ||
318 (g_Options.uNumProcessors > 64))
320 g_Options.uNumProcessors = 2;
326 if ((!STRCMPI(argv[i], "--command")) && (argc > i))
328 strncpy(g_szInitialCommand,
330 SMALL_STRING_LEN_CHAR - 2);
331 strcat(g_szInitialCommand, "\r\n");
334 else if ((!STRCMPI(argv[i], "--hash")) && (argc > i))
336 g_Options.uNumHashTableEntries =
337 _ParseHashOption(argv[i+1],
341 else if ((!STRCMPI(argv[i], "--egtbpath")) && (argc > i))
343 g_Options.szEGTBPath[0] = '\0';
344 strncpy(g_Options.szEGTBPath, argv[i+1], SMALL_STRING_LEN_CHAR);
347 else if (!STRCMPI(argv[i], "--batch"))
349 g_Options.fNoInputThread = TRUE;
351 else if ((!STRCMPI(argv[i], "--dnafile")) && (argc > i))
353 if (!ReadEvalDNA(argv[i+1]))
355 UtilPanic(INITIALIZATION_FAILURE,
356 (void *)"Bad DNA file",
357 (void *)&(argv[i+1]),
364 else if ((!STRCMPI(argv[i], "--logfile")) && (argc > i))
366 strncpy(g_Options.szLogfile, argv[i+1],
367 SMALL_STRING_LEN_CHAR);
370 else if (!STRCMPI(argv[i], "--help")) {
371 Trace("Usage: %s [--batch] [--command arg] [--logfile arg] [--egtbpath arg]\n"
372 " [--dnafile arg] [--cpus arg] [--hash arg]\n\n"
373 " --batch : operate the engine without an input thread\n"
374 " --command : specify initial command(s) (requires arg)\n"
375 " --cpus : indicate the number of cpus to use (requires arg, MP build)\n"
376 " --hash : indicate desired hash size (requires arg)\n"
377 " --egtbpath : supplies the egtb path to engine (requires arg)\n"
378 " --logfile : indicate desired output logfile name (requires arg)\n"
379 " --dnafile : indicate desired eval profile input (requres arg)\n\n"
380 "Example: %s --hash 256m --cpus 2\n"
381 " %s --logfile test.out --batch --command \"test\" --dnafile test.in\n", argv[0], argv[0], argv[0]);
386 Trace("Error (unknown argument): \"%s\"; try --help\n", argv[i]);
390 // TODO: parse other commandline options and override above
421 MainProgramInitialization(int argc, char *argv[])
426 Perform main program initialization. This includes stuff like:
427 precomputing some data structures, resetting the global options,
428 parsing the commandline to override said options, and calling out
429 to other modules to tell them to initialize themselves.
442 srand((unsigned int)time(0));
443 InitializeOptions(argc, argv);
444 InitializeTreeDump();
446 InitializeSigSystem();
447 InitializeInteriorNodeRecognizers();
448 InitializeSearchDepthArray();
449 InitializeWhiteSquaresTable();
450 InitializeVectorDeltaTable();
451 InitializeSwapTable();
452 InitializeDistanceTable();
453 InitializeOpeningBook();
454 InitializeDynamicMoveOrdering();
455 InitializeHashSystem();
456 InitializePositionHashSystem();
458 InitializeParallelSearch();
460 VERIFY(PreGameReset(TRUE));
461 return(BeginLogging());
466 MainProgramCleanup(void)
471 Perform main program cleanup. Tear down the stuff we set up in
472 MainProgramInitialization.
484 CleanupOpeningBook();
486 CleanupDynamicMoveOrdering();
488 CleanupParallelSearch();
490 CleanupPositionHashSystem();
501 RunStartupProgramTest(void)
506 If we built this version with -DTEST then this code is the start
507 of the self-test that runs at program startup time.
522 Trace("Testing CPP macros...\n");
523 for (u = 0; u < 1000000; u++)
527 x = x & ~(0x80000000);
528 y = y & ~(0x80000000);
530 if (MAX(x, y) != MAXU(x, y))
532 UtilPanic(TESTCASE_FAILURE,
533 NULL, "max maxu", NULL, NULL, __FILE__, __LINE__);
536 if (MAXU(x, y) != MAXU(y, x))
538 UtilPanic(TESTCASE_FAILURE,
539 NULL, "maxu assoc", NULL, NULL, __FILE__, __LINE__);
542 if (MIN(x, y) != MINU(x, y))
544 UtilPanic(TESTCASE_FAILURE,
545 NULL, "min minu", NULL, NULL, __FILE__, __LINE__);
548 if (MINU(x, y) != MINU(y, x))
550 UtilPanic(TESTCASE_FAILURE,
551 NULL, "minu assoc", NULL, NULL, __FILE__, __LINE__);
554 if (abs(x - y) != ABS_DIFF(x, y))
556 UtilPanic(TESTCASE_FAILURE,
557 NULL, "abs_diff", NULL, NULL, __FILE__, __LINE__);
560 if (ABS_DIFF(x, y) != ABS_DIFF(y, x))
562 UtilPanic(TESTCASE_FAILURE,
563 NULL, "abs_diff assoc", NULL, NULL, __FILE__, __LINE__);
577 TestLegalMoveGenerator();
579 TestLiftPlaceSlidePiece();
582 TestMakeUnmakeMove();
591 void DeclareTerminalStates(GAME_RESULT result) {
592 switch(result.eResult) {
593 case RESULT_IN_PROGRESS:
595 case RESULT_BLACK_WON:
596 Trace("0-1 {%s}\n", result.szDescription);
597 SetGameResultAndDescription(result.eResult, result.szDescription);
599 g_Options.ePlayMode = FORCE_MODE;
601 case RESULT_WHITE_WON:
602 Trace("1-0 {%s}\n", result.szDescription);
603 SetGameResultAndDescription(result.eResult, result.szDescription);
605 g_Options.ePlayMode = FORCE_MODE;
608 Trace("1/2-1/2 {%s}\n", result.szDescription);
609 Trace("tellics draw\n");
610 SetGameResultAndDescription(result.eResult, result.szDescription);
612 g_Options.ePlayMode = FORCE_MODE;
614 case RESULT_ABANDONED:
617 SetGameResultAndDescription(result.eResult, result.szDescription);
619 g_Options.ePlayMode = FORCE_MODE;
626 void MainProgramLoop() {
632 while (!g_fExitProgram) {
634 // Prepare to search or ponder
635 memcpy(&pos, GetRootPosition(), sizeof(POSITION));
636 fThink = fPonder = FALSE;
637 result.eResult = RESULT_IN_PROGRESS;
638 result.szDescription[0] = '\0';
640 // What should we do?
641 switch(g_Options.ePlayMode) {
643 Trace("I play white.\n");
644 fThink = (pos.uToMove == WHITE);
645 fPonder = (pos.uToMove == BLACK);
648 Trace("I play black.\n");
649 fThink = (pos.uToMove == BLACK);
650 fPonder = (pos.uToMove == WHITE);
654 Trace("Force mode\n");
655 fThink = fPonder = FALSE;
661 result = Think(&pos);
662 if ((NumberOfPendingInputEvents() != 0) &&
663 (FALSE == g_fExitProgram))
666 ParseUserInput(FALSE);
668 DeclareTerminalStates(result);
669 } else if (fPonder) {
670 Trace("Ponder...\n");
671 if (g_Options.fShouldPonder) {
672 result = Ponder(&pos);
674 if (FALSE == g_fExitProgram)
677 ParseUserInput(FALSE);
679 DeclareTerminalStates(result);
681 Trace("Force mode, consume input and continue\n");
683 ParseUserInput(FALSE);
690 main(int argc, char *argv[])
695 Chess engine entry point and main loop.
708 // Initial setup work...
709 Trace("Setting up, please wait...\n");
710 if (FALSE == SystemDependentInitialization())
712 Trace("main: Operating system dependent init code failed, "
716 if (FALSE == MainProgramInitialization(argc, argv))
718 Trace("main: Main program init code failed, aborting.\n");
723 (void)RunStartupProgramTest();
725 if (TRUE == g_Options.fNoInputThread)
727 InitInputSystemInBatchMode();
731 g_uInputThreadHandle = InitInputSystemWithDedicatedThread();
734 // Enter the main work loop code...
737 // If we get here g_fExitProgram is set -- clean up.
738 Trace("MAIN THREAD: thread terminating.\n");
739 if (FALSE == MainProgramCleanup())
741 Trace("main: Main program cleanup code failed, aborting.\n");