void FlatUCBMod::expand(Node* node, int UCTPlayer) { if (getUntriedChildren(node).size() > 0) { Node* randomNode = getRandomNode(getUntriedChildren(node)); rollout(randomNode, randomNode->currentState, randomNode->playerPlaying); } else { if (node->currentState.gameFinished()) { rollout(node, node->currentState, node->playerPlaying); } else { //createAllChildren(node); Node* randomNode = getRandomNode(node->childrenPtrs); rollout(randomNode, randomNode->currentState, randomNode->playerPlaying); } } }
void FlatUCBMod::doUCT(int UCTPlayer, GameState gameState, std::vector<Move> moveHistory) { // Create inital root node and its children. Node* rootNode = requestNewNode(); rootNode->isRoot = true; rootNode->visited = 0; rootNode->currentState = gameState; rootNode->playerPlaying = UCTPlayer; if (moveHistory.size() > 2) { Move lastMove = moveHistory.back(); int size = moveHistory.size(); if (lastMove.player == UCTPlayer && lastMove.absoluteCardId == REMODEL && lastMove.type == ACTION) // Time to trash a card from remodel. { rootNode->opt.type = ACTION; rootNode->opt.absoluteCardId = REMODEL; } else if (lastMove.player == UCTPlayer && moveHistory[size - 2].absoluteCardId == REMODEL && lastMove.type == TRASH) // Time to gain a card from remodel. { rootNode->flags = REMODELFLAG; rootNode->opt.type = TRASH; rootNode->opt.absoluteCardId = lastMove.absoluteCardId; } else if (lastMove.player == UCTPlayer && lastMove.absoluteCardId == THIEF && lastMove.type == ACTION) { rootNode->opt.type = ACTION; rootNode->opt.absoluteCardId = THIEF; } else if (lastMove.player != UCTPlayer && moveHistory[size - 2].absoluteCardId == THIEF && lastMove.type == THIEFFLIP) { rootNode->flags = THIEFDRAW; rootNode->opt.type = THIEFFLIP; rootNode->opt.absoluteCardId = lastMove.absoluteCardId; rootNode->opt.absoluteExtraCardId = lastMove.absoluteExtraCardId; } else if (lastMove.player == UCTPlayer && lastMove.type == ACTION && lastMove.absoluteCardId == MONEYLENDER) rootNode->currentState.playerStates[rootNode->playerPlaying].spentMoney -= 3; } createAllChildren(rootNode); if (rootNode->childrenPtrs.size() == 1) { std::vector<Node*> temp; temp.push_back(rootNode->childrenPtrs.at(0)); temp.at(0)->visited = 99; addToReturnVector(temp); return; } int sims = 0; for (int i = 0; i < UCBMOD_SIMULATIONS; i++) { Node* toRollout = UCTSelectChild(rootNode); rollout(toRollout, toRollout->currentState, UCTPlayer); if (UCBMOD_PRINTSIMULATIONS) printTree(gameState.turnCounter, UCTPlayer, rootNode, moveHistory.size(), i); sims = i; } std::cout << "Sims: " << sims << std::endl; if (UCBMOD_PRINTTREE) printTree(gameState.turnCounter, UCTPlayer, rootNode, moveHistory.size(), -1); // "Return" addToReturnVector(rootNode->childrenPtrs); }
void Player::PlayerUCT::walk_tree(Board & board, Node * node, int depth){ int toplay = board.toplay(); if(!node->children.empty() && node->outcome < 0){ //choose a child and recurse Node * child; do{ int remain = board.movesremain(); child = choose_move(node, toplay, remain); if(child->outcome < 0){ movelist.addtree(child->move, toplay); if(!board.move(child->move, (player->minimax == 0), (player->locality || player->weightedrandom) )){ logerr("move failed: " + child->move.to_s() + "\n" + board.to_s(false)); assert(false && "move failed"); } child->exp.addvloss(); //balanced out after rollouts walk_tree(board, child, depth+1); child->exp.addv(movelist.getexp(toplay)); if(!player->do_backup(node, child, toplay) && //not solved player->ravefactor > min_rave && //using rave node->children.num() > 1 && //not a macro move 50*remain*(player->ravefactor + player->decrrave*remain) > node->exp.num()) //rave is still significant update_rave(node, toplay); return; } }while(!player->do_backup(node, child, toplay)); return; } if(player->profile && stage == 0){ stage = 1; timestamps[1] = Time(); } int won = (player->minimax ? node->outcome : board.won()); //if it's not already decided if(won < 0){ //create children if valid if(node->exp.num() >= player->visitexpand+1 && create_children(board, node, toplay)){ walk_tree(board, node, depth); return; } if(player->profile){ stage = 2; timestamps[2] = Time(); } //do random game on this node for(int i = 0; i < player->rollouts; i++){ Board copy = board; rollout(copy, node->move, depth); } }else{ movelist.finishrollout(won); //got to a terminal state, it's worth recording } treelen.add(depth); movelist.subvlosses(1); if(player->profile){ timestamps[3] = Time(); if(stage == 1) timestamps[2] = timestamps[3]; stage = 3; } return; }