void TestIterativeValue(int depth) { // setup book and cache CCache acache(2); cache = &acache; const int nEmpty = 22; CBook* oldBook = book; book = NULL; InitializeCache(); SetBookHeights(nEmpty); mpcs = CMPCStats::GetMPCStats('J','A',5); // testing const COsGame osGame = LoadTestGames().at(0); const CQPosition testPosition = PositionFromEmpties(osGame, nEmpty); std::vector<CMoveValue> mvs = createMoves(testPosition); Pos2 pos2; pos2.Initialize(testPosition.BitBoard(), testPosition.BlackMove()); u4 nValued=0; std::vector<CMoveValue> mvsEvaluated; ValueMulti(pos2, depth, -kInfinity, kInfinity, 4, 1, mvs, false, false, mvsEvaluated, nValued); // cout << " nValued = " << nValued << "\n"; // cout << " mvsEvaluated = \n"; // for (int i=0; i<mvsEvaluated.size(); i++) { // CMoveValue mv = mvsEvaluated.at(i); // cout << "new CMoveValue(" << mv.move << "," << mv.value << "),\n"; // } // cout << "\n"; // tear down book and cache book = oldBook; cache = NULL; }
void AnalyzePosition(CPlayerComputer* computer, CQPosition& pos) { CMVK mvk; std::cout << pos.NEmpty(); computer->Clear(); u4 fNeed=CSearchInfo::kNeedMove+CSearchInfo::kNeedValue+CSearchInfo::kNeedMPCStats; CSearchInfo si = computer->DefaultSearchInfo(pos.BlackMove(), fNeed, INFINITE_TIME, 0); computer->GetChosen(si, pos, mvk, true); printf("\n"); std::cerr << "."; }
std::vector<CMoveValue> createMoves(CQPosition testPosition) { std::vector<CMoveValue> mvs; CMoves moves; testPosition.CalcMoves(moves); CMove move; while (moves.GetNext(move)) { mvs.push_back(CMoveValue(move, (short)0)); } return mvs; }
//! Helper routine to make sure that the given position is stored as an unsolved leaf node in the book static void TestULeafPos(const CBook& book, const CQPosition& pos, CValue value, const CHeightInfoX& hix) { const CBookData* bd=book.FindData(pos.BitBoard()); TEST(bd!=NULL); TEST(bd->IsLeaf()); TEST(!bd->IsProven()); TEST(bd->IsUleaf()); TEST(bd->Hi()==hix); TEST(bd->Values().vMover==value); TEST(bd->Values().vOpponent==value); TEST(bd->Values().vHeuristic==value); }
// preconditions: computer has no book void CalcMPCStats(CPlayerComputer* computer, int height) { FILE* cpFile; CBitBoard bb; int nbbs[60], i, iPos; const int iPosMin=159; // start at this line, useful if stopping and restarting CQPosition pos; CCalcParams *cpOld=computer->pcp; CHeightInfo hi(height, 0, false); CCalcParamsFixedHeight cp(hi); computer->pcp=&cp; computer->cd.fsPrint=0; // header info std::cout << 3 << " " << height << " " << kStoneValue << "\n"; // clear computer's and params //computer->cd.iPruneMidgame=computer->cd.iPruneEndgame=0; // clear position counts and init for (i=0; i<60; i++) nbbs[i]=0; iPos=0; // read positions from file; analyze if we should std::string fn(fnBaseDir); fn+="captured.pos"; if ((cpFile=fopen(fn.c_str(),"rb"))) { while (bb.Read(cpFile)) { pos.Initialize(bb, true); if (nbbs[bb.NEmpty()]++ < kMaxPositions) if (iPos++>=iPosMin) AnalyzePosition(computer, pos); } fclose(cpFile); } // restore computer's book and params computer->pcp=cpOld; }
static void TestMakeMove() { CQPosition pos; char sBoard[65]; pos.Initialize(); pos.MakeMove(CMove("F5")); assertStringEquals("---------------------------O*------***--------------------------", pos.GetSBoard(sBoard)); assertFalse(pos.BlackMove()); assertEquals(59, pos.NEmpty()); assertEquals(1, pos.NMover()); }
// save values of positions in a file // format: // bitboard (white just moved), value (to black), pass flag (0,1,2), best move (for mover) // precondition: no book (unless you want to add these positions to a book) void CalcPosValues(CPlayerComputer* computer, bool fAppend) { FILE* fpCapture, *fpPV; CQPosition pos; CMVK mvk; CMoves moves; int i, quantities[60], pass, nCalced, iAppend; CBitBoard bb; time_t tStart; if (fAppend) { // figure out what number to start on std::string fn(fnBaseDir); fn+=sPVFile; fpPV=fopen(fn.c_str(), "rb"); int result = fseek(fpPV, 0, SEEK_END); int nFileSize=ftell(fpPV); int nRecordSize=sizeof(bb.mover)+sizeof(bb.empty)+ sizeof(mvk.value)+sizeof(pass)+sizeof(mvk.move); if (nFileSize%nRecordSize) { iAppend=0; std::cerr << "Previous .pv file is corrupt, starting again: file size = " << nFileSize << ", record size = " << nRecordSize << ", file size % record size = " << nFileSize%nRecordSize << "\n"; } else { iAppend=nFileSize/nRecordSize; std::cerr << "Appending to previous file with " << iAppend << " elements\n"; } fclose(fpPV); fpPV=NULL; } else iAppend=0; // clear count for (i=0;i<60; i++) quantities[i]=0; std::string fn(fnBaseDir); fn+=fnCapture; fpCapture=fopen(fn.c_str(), "rb"); if (fpCapture) { std::string fn(fnBaseDir); fn+=sPVFile; fpPV=fopen(fn.c_str(), iAppend?"a+bc":"wbc"); if (fpPV) { for (nCalced=0; bb.Read(fpCapture); ) { if (bb.NEmpty()>60) continue; quantities[bb.NEmpty()]++; // print progress if (nCalced%200 == 0) { fflush(fpPV); if (nCalced%10000 == 0) fprintf(stderr, "\nPosition %dk ",nCalced/1000); else fprintf(stderr, "."); } //printf("%d", bb.NEmpty()); if (nCalced>=iAppend) { pos.Initialize(bb,true); pass=pos.CalcMovesAndPass(moves); // if terminal position, calc value if (pass==2) { mvk.value=-pos.TerminalValue(); mvk.move.Set(-1); } // nonterminal position, get value from computer else { tStart=time(0); CSearchInfo si = computer->DefaultSearchInfo(pos.BlackMove(), CSearchInfo::kNeedMove + CSearchInfo::kNeedValue, INFINITE_TIME, 0); computer->GetChosen(si, pos, mvk, true); if (pass==1) mvk.value=-mvk.value; //printf("NEmpty = %2d; value = %4d; move = ",pos.NEmpty(),mvk.value); //mvk.move.Print(); //printf("; pass = %d; time = %2d\n",pass, time(0)-tStart); } // write to file if (!bb.Write(fpPV) || !fwrite(&mvk.value, sizeof(mvk.value), 1, fpPV) || !fwrite(&pass, sizeof(pass), 1, fpPV) || !fwrite(&mvk.move, sizeof(mvk.move), 1, fpPV)) { std::string fn(fnBaseDir); fn+=sPVFile; std::cerr << "can't write to file " << fn << "\n"; assert(0); _exit(1); } } nCalced++; } fclose(fpPV); } fclose(fpCapture); } // print count int sum=0; for (i=0;i<60; i++) { sum+=quantities[i]; printf("%d:%d\n",i,quantities[i]); } printf("%d total positions\n",sum); }
void TestFindQuestionableNode() { COsGame game; game.Initialize("8"); CQPosition initialPos(game, 0); CQPosition questionablePosition; CBook book; bool drawToMover; // The position is not in book. FindQuestionableNode should return NULL. bool isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(!isQuestionable); // add the initial position to the book. FindQuestionableNode should return the initial position. const CBitBoard initialBitBoard(initialPos.BitBoard()); CMinimalReflection mr(initialBitBoard); CHeightInfoX heightInfoX(2, 4, false, initialBitBoard.NEmpty()); book.StoreLeaf(CMinimalReflection(initialBitBoard), heightInfoX, 0); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(isQuestionable); TEST(questionablePosition==initialPos); // add the initial position to the book with a deviation of the deviation cutoff // Since this is bigger than the threshold for deviations, we won't count it. book.StoreLeaf(CMinimalReflection(initialBitBoard), heightInfoX, deviationCutoff); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(!isQuestionable); // but if it's one less than the deviation cutoff, it's questionable book.StoreLeaf(CMinimalReflection(initialBitBoard), heightInfoX, deviationCutoff-1); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(isQuestionable); TEST(questionablePosition==initialPos); // Also if it's negative... at the deviation cutoff is ok, one more is questionable book.StoreLeaf(CMinimalReflection(initialBitBoard), heightInfoX, -deviationCutoff); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(!isQuestionable); book.StoreLeaf(CMinimalReflection(initialBitBoard), heightInfoX, 1-deviationCutoff); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(isQuestionable); TEST(questionablePosition==initialPos); // This node is a draw, at +3/-3.. so it's ok const CBookData* bookData = book.FindData(initialBitBoard); // casting to remove const is a really bad idea... but no other easy way to test CBookValue& bookValue = (CBookValue&)(bookData->Values()); bookValue.vHeuristic = 0; bookValue.vMover = drawCutoff; bookValue.vOpponent = - drawCutoff; isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(!isQuestionable); TEST(questionablePosition==initialPos); CQPosition nextPos(initialPos); nextPos.MakeMove(CMove("F5")); const CBitBoard f5 = nextPos.BitBoard(); nextPos.MakeMove(CMove("D6")); const CBitBoard f5d6 = nextPos.BitBoard(); nextPos = initialPos; nextPos.MakeMove(CMove("F5")); nextPos.MakeMove(CMove("F6")); const CBitBoard f5f6 = nextPos.BitBoard(); // Now we have a questionable position, but it's not at the initial node // tree is: // f5 d6 : proven draw // f5 f6 : deviation with value drawValue book.StoreRoot(initialBitBoard, heightInfoX, 0, -16400); book.StoreRoot(f5, heightInfoX, 0, -16400); CHeightInfoX hixSolved = CHeightInfoX(f5f6.NEmpty(), 0, false, f5f6.NEmpty()); book.StoreLeaf(f5f6, hixSolved, 0); book.StoreLeaf(f5d6, heightInfoX, drawCutoff); book.NegamaxAll(); isQuestionable = book.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(isQuestionable); TEST(CMinimalReflection(questionablePosition.BitBoard())==CMinimalReflection(f5d6)); // This position has a questionable node, but it's not on the draw tree so it's not returned CBook book2; book2.StoreRoot(initialBitBoard, heightInfoX, -deviationCutoff, -16400); book2.StoreRoot(f5, heightInfoX, deviationCutoff, -16400); book2.StoreLeaf(f5f6, heightInfoX, -deviationCutoff); book2.StoreLeaf(f5d6, heightInfoX, 0); book2.NegamaxAll(); isQuestionable = book2.FindQuestionableNode(questionablePosition, drawToMover, initialPos, drawCutoff, deviationCutoff); TEST(!isQuestionable); }
//! Test that WriteCompressed() followed by ReadCompressed() returns the same book void CBook::TestIO() { { // test book with no position CBook book(NULL, s_out); book.TestMyIO(); } { // test book with a pass position and a subposition from that CBook book(NULL, s_out); CQPosition pos; pos.Initialize("---------------------------**------**------------------O------O*", true); book.StoreRoot(pos.BitBoard(), CHeightInfoX(10, 4, false, pos.NEmpty()), 32, -300); pos.MakeMove(CMove(057)); pos.Pass(); book.StoreLeaf(pos.BitBoard(), CHeightInfoX(10, 4, false, pos.NEmpty()), 32); book.TestMyIO(); } { // test book with only one entry CBook book(NULL, s_out); CQPosition pos; pos.Initialize(); book.StoreLeaf(pos.BitBoard(), CHeightInfoX(10, 4, false, 60), 32); book.TestMyIO(); } { // test book with two entries in a tree CBook book(NULL, s_out); CQPosition pos; pos.Initialize(); book.StoreRoot(pos.BitBoard(), CHeightInfoX(10, 4, false, 60), 32, 16400); pos.MakeMove(CMove(045)); book.StoreLeaf(pos.BitBoard(), CHeightInfoX(10, 4, false, 59), -32); book.TestMyIO(); } }
//! Test CBook::StoreSubposition(). //! While we're at it, test negamaxing as well, so store the parent position //! as a branch node and see if it's assigned the right value. static void TestStoreSubposition() { { // test StoreSubposition() when there is no pass after the move. CBook book; CQPosition pos; pos.Initialize(); const CMoveValue mv(F5, 41); CHeightInfoX hix(2, 4, false, pos.NEmpty()); // store subpos in book book.StoreSubposition(pos, mv, hix); TEST(book.Size()==1); // test that subpos went in correctly CQPosition posSub(pos); posSub.MakeMove(mv.move); CHeightInfoX hixSub(1, 4, false, posSub.NEmpty()-1); TestULeafPos(book, posSub, -mv.value, hixSub); // test that pos is valued correctly when we negamax book.StoreRoot(pos.BitBoard(), hix, mv.value, -100); book.NegamaxAll(); const CBookData* pbd=book.FindData(pos.BitBoard()); TEST(pbd!=NULL); TEST(pbd->Values().vHeuristic==mv.value); } { // test StoreSubposition() when there is a pass after the move. CBook book; CQPosition pos("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO*******-----------------", false); CMoveValue mv(A7, 64*kStoneValue); CHeightInfoX hix(2, 4, false, pos.NEmpty()); // store subpos in book book.StoreSubposition(pos, mv, hix); TEST(book.Size()==1); // test that subpos went in correctly CQPosition posSub(pos); posSub.MakeMoveAndPass(mv.move); CHeightInfoX hixSub(1, 4, false, posSub.NEmpty()-1); TestULeafPos(book, posSub, mv.value, hixSub); // test that pos is valued correctly when we negamax book.StoreRoot(pos.BitBoard(), hix, mv.value, -100); book.NegamaxAll(); const CBookData* pbd=book.FindData(pos.BitBoard()); TEST(pbd!=NULL); TEST(pbd->Values().vHeuristic==mv.value); } { // test StoreSubposition() when there are two passes after the move. // no subposition should be added to the book (we don't store terminal nodes in book.) CBook book; CQPosition pos("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO******-----------------", false); CMoveValue mv; mv.move=H6; mv.value=64*kStoneValue; CHeightInfoX hix(2, 4, false, pos.NEmpty()); // store subpos in book book.StoreSubposition(pos, mv, hix); TEST(book.Size()==0); // test that pos is valued correctly when we negamax book.StoreRoot(pos.BitBoard(), hix, mv.value, -100); book.NegamaxAll(); const CBookData* pbd=book.FindData(pos.BitBoard()); TEST(pbd!=NULL); TEST(pbd->Values().vHeuristic==mv.value); } }