Esempio n. 1
0
void Berry::makeTurn () {
    std::vector<MoveInfo> res = genMoves();
    if (res.size() != 0) {
        MoveInfo *best = &res[0];
        for (uint i=1; i<res.size(); i++)
            if (res[i].score() > best->score())
                best = &res[i];
        pin.doMove(*best);
    } else {
        pin.doPass();
    }
}
Esempio n. 2
0
void
MoveInfoTable::decode(ByteStream& strm)
{
	MoveInfo	m;
	unsigned	index	= 0;

	m_table.clear();

	while (strm.remaining())
	{
		unsigned skip = m.decode(strm);
		m_table.resize((index += skip) + 1);
		m_table[index].add(m);
	}
}
Esempio n. 3
0
void MonsterAI::makeMove() {
  vector<pair<MoveInfo, int>> moves;
  for (int i : All(behaviours)) {
    MoveInfo move = behaviours[i]->getMove();
    move.value *= weights[i];
    moves.emplace_back(move, weights[i]);
    if (pickItems) {
      for (auto elem : Item::stackItems(creature->getPickUpOptions())) {
        Item* item = elem.second[0];
        if (!item->getShopkeeper() && creature->canPickUp(elem.second)) {
          MoveInfo pickupMove { behaviours[i]->itemValue(item) * weights[i], [=]() {
            creature->globalMessage(creature->getTheName() + " picks up " + elem.first, "");
            creature->pickUp(elem.second);
          }};
          moves.emplace_back(pickupMove, weights[i]);
        }
      }
    }
  }
  /*vector<Item*> inventory = creature->getEquipment().getItems([this](Item* item) { return !creature->getEquipment().isEquiped(item);});
  for (Item* item : inventory) {
    bool useless = true;
    for (PBehaviour& behaviour : behaviours)
      if (behaviour->itemValue(item) > 0)
        useless = false;
    if (useless)
      moves.push_back({ 0.01, [=]() {
        creature->globalMessage(creature->getTheName() + " drops " + item->getAName(), "");
        creature->drop({item});
      }});
  }*/
  MoveInfo winner {0, nullptr};
  for (int i : All(moves)) {
    MoveInfo& move = moves[i].first;
    if (move.value > winner.value)
      winner = move;
    if (i < moves.size() - 1 && move.value > moves[i + 1].second)
      break;
  }
  CHECK(winner.value > 0);
  winner.move();
}
Esempio n. 4
0
void
Search::notifyPV(const MoveInfo& info, int multiPVIndex) {
    if (info.depth <= 0)
        return;
    bool uBound = info.score() <= info.alpha;
    bool lBound = info.score() >= info.beta;
    int score = info.move.score();
    if (verbose) {
        std::stringstream ss;
        ss << std::setw(6) << std::left << TextIO::moveToString(pos, info.move, false)
           << ' ' << std::setw(6) << std::right << score
           << ' ' << std::setw(6) << nodes
           << ' ' << std::setw(6) << qNodes;
        if (uBound)
            ss << " <=";
        else if (lBound)
            ss << " >=";
        else {
            std::string PV = TextIO::moveToString(pos, info.move, false) + " ";
            UndoInfo ui;
            pos.makeMove(info.move, ui);
            PV += tt.extractPV(pos);
            pos.unMakeMove(info.move, ui);
            ss << ' ' << PV;
        }
        std::cout << ss.str() << std::endl;
    }
    if (!listener)
        return;
    bool isMate = false;
    if (score > MATE0 / 2) {
        isMate = true;
        score = (MATE0 - score) / 2;
    } else if (score < -MATE0 / 2) {
        isMate = true;
        score = -((MATE0 + score - 1) / 2);
    }
    U64 tNow = currentTimeMillis();
    int time = (int) (tNow - tStart);
    S64 totNodes = getTotalNodes();
    int nps = (time > 0) ? (int)(totNodes / (time / 1000.0)) : 0;
    listener->notifyPV(info.depth/plyScale, score, time, totNodes, nps, isMate,
                       uBound, lBound, info.pv, multiPVIndex);
}
Esempio n. 5
0
void
Decoder::decodeVariation(ByteStream& data)
{
	unsigned	pieceNum	= 0;	// satisfies the compiler
	Move		move;

	while (true)
	{
		Byte b;

		while ((b = m_strm.get()) > token::End_Marker)
		{
			if (move)
				m_position.doMove(move, pieceNum);

			pieceNum = decodeMove(b, move);

			MoveNode* node = new MoveNode(move);
			m_currentNode->setNext(node);
			m_currentNode = node;
		}

		switch (b)
		{
			case token::End_Marker:
				{
					MoveNode* node = new MoveNode;
					m_currentNode->setNext(node);

					switch (m_strm.get())
					{
						case token::Comment:
							node->setCommentFlag(data.get());
							break;

						case token::End_Marker: break;
						default: return; //IO_RAISE(Game, Corrupted, "unexpected token");
					}
				}
				return;

			case token::Start_Marker:
				{
					MoveNode* current = m_currentNode;

					m_position.push();
					m_position.board().undoMove(move);
					current->addVariation(m_currentNode = new MoveNode);
					decodeVariation(data);
					m_currentNode = current;
					m_position.pop();
				}
				break;

			case token::Nag:
				static_assert(Annotation::Max_Nags >= 7, "Scidb needs at least seven entries");
				{
					nag::ID nag = nag::ID(m_strm.get());

					if (nag == 0)
						move.setLegalMove(false);
					else
						m_currentNode->addAnnotation(nag);
				}
				break;

			case token::Mark:
				if (data.peek() & 0x80)
				{
					MoveInfo info;
					info.decode(data);
					m_currentNode->addMoveInfo(info);
				}
				else
				{
					Mark mark;
					mark.decode(data);
					m_currentNode->addMark(mark);
				}
				break;

			case token::Comment:
				m_currentNode->setCommentFlag(data.get());
				break;
		}
	}
}
Esempio n. 6
0
Move
Search::iterativeDeepening(const MoveGen::MoveList& scMovesIn,
                           int maxDepth, U64 initialMaxNodes,
                           bool verbose, int maxPV) {
    tStart = currentTimeMillis();
    totalNodes = 0;
    if (scMovesIn.size <= 0)
        return Move(); // No moves to search

    std::vector<MoveInfo> scMoves;
    {
        // If strength is < 10%, only include a subset of the root moves.
        // At least one move is always included though.
        std::vector<bool> includedMoves(scMovesIn.size);
        U64 rndL = pos.zobristHash() ^ randomSeed;
        includedMoves[(int)(rndL % scMovesIn.size)] = true;
        double pIncl = (strength < 100) ? strength * strength * 1e-4 : 1.0;
        for (int mi = 0; mi < scMovesIn.size; mi++) {
            rndL = 6364136223846793005ULL * rndL + 1442695040888963407ULL;
            double rnd = ((rndL & 0x7fffffffffffffffULL) % 1000000000) / 1e9;
            if (!includedMoves[mi] && (rnd < pIncl))
                includedMoves[mi] = true;
        }
        for (int mi = 0; mi < scMovesIn.size; mi++) {
            if (includedMoves[mi]) {
                const Move& m = scMovesIn[mi];
                scMoves.push_back(MoveInfo(m, 0));
            }
        }
    }

    logFile.open("/home/petero/treelog.dmp", pd, threadNo);
    const U64 rootNodeIdx = logFile.logPosition(pos, 0, 0, 0);

    kt.clear();
    pd.npsInfo.reset();
//    pd.wq.resetStat();
    const bool smp = pd.numHelperThreads() > 0;
    maxNodes = initialMaxNodes;
    nodesToGo = 0;
    Position origPos(pos);
    bool firstIteration = true;
    Move bestMove = scMoves[0].move; // bestMove is != scMoves[0].move when there is an unresolved fail high
    this->verbose = verbose;
    if ((maxDepth < 0) || (maxDepth > MAX_SEARCH_DEPTH))
        maxDepth = MAX_SEARCH_DEPTH;
    maxPV = std::min(maxPV, (int)scMoves.size());
    for (size_t i = 0; i < COUNT_OF(searchTreeInfo); i++)
        searchTreeInfo[i].allowNullMove = true;
    ht.reScale();
    try {
    for (int depthS = plyScale; ; depthS += plyScale, firstIteration = false) {
        initNodeStats();
        if (listener) listener->notifyDepth(depthS/plyScale);
        int aspirationDelta = 0;
        int alpha = 0;
        UndoInfo ui;
        bool needMoreTime = false;
        for (int mi = 0; mi < (int)scMoves.size(); mi++) {
            if (mi < maxPV)
                aspirationDelta = (std::abs(scMoves[mi].score()) <= MATE0 / 2) ? aspirationWindow : 1000;
            if (firstIteration)
                alpha = -MATE0;
            else if (mi < maxPV)
                alpha = std::max(scMoves[mi].score() - aspirationDelta, -MATE0);
            else
                alpha = scMoves[maxPV-1].score();

            searchNeedMoreTime = (mi > 0);
            Move& m = scMoves[mi].move;
            pd.topMove = m;
            if (currentTimeMillis() - tStart >= 1000)
                if (listener) listener->notifyCurrMove(m, mi + 1);
            nodes = qNodes = 0;
            posHashList[posHashListSize++] = pos.zobristHash();
            bool givesCheck = MoveGen::givesCheck(pos, m);
            int beta;
            if (firstIteration)
                beta = MATE0;
            else if (mi < maxPV)
                beta = std::min(scMoves[mi].score() + aspirationDelta, MATE0);
            else
                beta = alpha + 1;

            int lmrS = 0;
            bool isCapture = (pos.getPiece(m.to()) != Piece::EMPTY);
            bool isPromotion = (m.promoteTo() != Piece::EMPTY);
            if ((depthS >= 3*plyScale) && !isCapture && !isPromotion &&
                !givesCheck && !passedPawnPush(pos, m) && (mi >= rootLMRMoveCount + maxPV)) {
                lmrS = plyScale;
            }
            pos.makeMove(m, ui);
            SearchTreeInfo& sti = searchTreeInfo[0];
            sti.currentMove = m;
            sti.currentMoveNo = mi;
            sti.lmr = lmrS;
            sti.nodeIdx = rootNodeIdx;
            int score = -negaScout(smp, -beta, -alpha, 1, depthS - lmrS - plyScale, -1, givesCheck);
            if ((lmrS > 0) && (score > alpha)) {
                sti.lmr = 0;
                score = -negaScout(smp, -beta, -alpha, 1, depthS - plyScale, -1, givesCheck);
            }
            U64 nodesThisMove = nodes + qNodes;
            posHashListSize--;
            pos.unMakeMove(m, ui);
            storeSearchResult(scMoves, mi, depthS, alpha, beta, score);
            if ((verbose && firstIteration) || (mi < maxPV) || (score > scMoves[maxPV-1].score()))
                notifyPV(scMoves, mi, maxPV);
            int betaRetryDelta = (mi == 0) ? aspirationDelta * 2 : aspirationDelta;
            int alphaRetryDelta = aspirationDelta * 2;
            while ((score >= beta) || ((mi < maxPV) && (score <= alpha))) {
                nodes = qNodes = 0;
                posHashList[posHashListSize++] = pos.zobristHash();
                bool fh = score >= beta;
                if (fh) {
                    if (score > MATE0 / 2)
                        betaRetryDelta = MATE0; // Don't use aspiration window when searching for faster mate
                    beta = std::min(score + betaRetryDelta, MATE0);
                    betaRetryDelta = betaRetryDelta * 3 / 2;
                    if (mi != 0)
                        needMoreTime = true;
                    bestMove = m;
                } else { // score <= alpha
                    if (score < -MATE0 / 2)
                        alphaRetryDelta = MATE0; // Don't use aspiration window when searching for faster mate
                    alpha = std::max(score - alphaRetryDelta, -MATE0);
                    alphaRetryDelta = alphaRetryDelta * 3 / 2;
                    needMoreTime = searchNeedMoreTime = true;
                }
                pos.makeMove(m, ui);
                score = -negaScout(smp, -beta, -alpha, 1, depthS - plyScale, -1, givesCheck);
                nodesThisMove += nodes + qNodes;
                posHashListSize--;
                pos.unMakeMove(m, ui);
                storeSearchResult(scMoves, mi, depthS, alpha, beta, score);
                notifyPV(scMoves, mi, maxPV);
            }
            scMoves[mi].nodes += nodesThisMove;
            if ((mi < maxPV) || (score > scMoves[maxPV-1].move.score())) {
                MoveInfo tmp = scMoves[mi];
                int i = mi;
                while ((i > 0) && (scMoves[i-1].score() < tmp.score())) {
                    scMoves[i] = scMoves[i-1];
                    i--;
                }
                scMoves[i] = tmp;
            }
            bestMove = scMoves[0].move;
            if (!firstIteration) {
                S64 timeLimit = needMoreTime ? maxTimeMillis : minTimeMillis;
                if (timeLimit >= 0) {
                    U64 tNow = currentTimeMillis();
                    if (tNow - tStart >= (U64)timeLimit)
                        break;
                }
            }
        }
        S64 tNow = currentTimeMillis();
        if (verbose) {
            static_assert(nodesByPly.minValue() == nodesByDepth.minValue(), "Incompatible histograms");
            static_assert(nodesByPly.maxValue() == nodesByDepth.maxValue(), "Incompatible histograms");
            for (int i = nodesByPly.minValue(); i < nodesByPly.maxValue(); i++)
                std::cout << std::setw(2) << i
                          << ' ' << std::setw(7) << nodesByPly.get(i)
                          << ' ' << std::setw(7) << nodesByDepth.get(i)
                          << std::endl;
            std::stringstream ss;
            ss.precision(3);
            ss << std::fixed << "Time: " << ((tNow - tStart) * .001);
            ss.precision(2);
            ss << " depth:" << (depthS/(double)plyScale)
               << " nps:" << ((int)(getTotalNodes() / ((tNow - tStart) * .001)));
            std::cout << ss.str() << std::endl;
        }
        if (maxTimeMillis >= 0)
            if (tNow - tStart >= minTimeMillis)
                break;
        if (depthS >= maxDepth * plyScale)
            break;
        if (maxNodes >= 0)
            if (getTotalNodes() >= maxNodes)
                break;
        bool enoughDepth = true;
        for (int i = 0; i < maxPV; i++) {
            int plyToMate = MATE0 - std::abs(scMoves[i].score());
            if (depthS < plyToMate * plyScale)
                enoughDepth = false;
        }
        if (enoughDepth)
            break;
        if (tNow > tStart)
            pd.npsInfo.setBaseNps(getTotalNodesThisThread() * 1000.0 / (tNow - tStart));
        if (firstIteration) {
            std::stable_sort(scMoves.begin()+maxPV, scMoves.end(), MoveInfo::SortByScore());
        } else {
            // Moves that were hard to search should be searched early in the next iteration
            std::stable_sort(scMoves.begin()+maxPV, scMoves.end(), MoveInfo::SortByNodes());
        }
//        std::cout << "fhInfo depth:" << depthS / plyScale << std::endl;
//        pd.fhInfo.print(std::cout);
//        std::cout << "wqStats depth:" << depthS / plyScale << std::endl;
//        pd.wq.printStats(std::cout, pd.numHelperThreads() + 1);
//        log([&](std::ostream& os){pd.npsInfo.print(os, depthS / plyScale);});
    }
    } catch (const StopSearch&) {
        pos = origPos;
    }
    notifyStats();

    logFile.close();
    return bestMove;
}