Move AlphaBetaQId::findBestMove() { auto start_time = std::chrono::steady_clock::now(); tt->aging(); std::list<Move> l = possibleMoves(); if (l.empty()) return NoMove; // game over. i lost if (l.size() == 1) return l.back(); // if only one move possible, return at once unsigned int r = tree_depth+1; // for TT std::list<std::pair<int, Move> > sl; for (const auto& m: l) { sl.push_back(std::pair<int, Move>(value, m)); } // copy possible moves for (tree_depth = 1; tree_depth <r; tree_depth++) { std::cerr << "depth=" << std::setw(2) << tree_depth << "\t"; for (auto &p: sl) { move(p.second); p.first = -evaluateMoveTree(tree_depth-1, -mateValue(), mateValue()); undo(p.second); std::cerr << moveValueString (p.second, p.first) << "\t"; } auto end_time = std::chrono::steady_clock::now(); std::cerr << "(" << std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count() << " s)" << "\r"; // std::endl; sl.sort(std::greater<std::pair<int, Move> >()); } tree_depth--; // restore from last ++, for next run std::cerr << std::endl; auto end_time = std::chrono::steady_clock::now(); std::cerr << "Time elapsed " << std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count() << "us.\n"; return sl.front().second; // best move; }
int AlphaBetaQId::evaluateMoveTreeQuiesce(int depth, int alpha, int beta) { #ifdef USE_POSITION_KEY int a = alpha; // remember argument int w; if (probe(w, alpha, beta, depth)) return w; #endif std::list<Move> l = possibleMoves(); if (l.empty()) { return -mateValue(tree_depth-depth); } // game over, node is terminal. return mate in plies if (l.front().isQuiet()) { return evaluatePosition(); } // no jumps, so quiesence search over. node is (at least) quiet Move best_move = NoMove; for (const auto& m: l) { // play forced moves move(m); int v = -evaluateMoveTreeQuiesce(depth-1, -beta, -alpha); undo(m); if (v >= beta) { store(v, a, beta, NoMove, depth); return v; } if (v > alpha) { alpha = v; best_move = m; } } store(alpha, a, beta, best_move, depth); // allow negative depthes in TT return alpha; }
int AlphaBetaQId::evaluateMoveTree(unsigned int depth, int alpha, int beta) { #ifdef USE_POSITION_KEY int a = alpha; int w; if (probe(w, alpha, beta, depth)) return w; #endif if (!depth) { return evaluateMoveTreeQuiesce(depth, alpha, beta); } // end of search depth. just forward all args to qsearch. std::list<Move> l = possibleMoves(); if (l.empty()) { return -mateValue(tree_depth-depth); } // game over, node is terminal Move best_move = NoMove; for (const auto& m: l) { move(m); int v = -evaluateMoveTree(depth-1, -beta, -alpha); undo(m); if (v >= beta) { store(v, a, beta, NoMove, depth); return v; } if (v > alpha) { alpha = v; best_move = m; } } store(alpha, a, beta, best_move, depth); return alpha; }
///condiciona os movimentos, de acordo com a disponibilidades das casas. Adicionando os possiveis a arvore void possibleMoves(Movimentos tree, int x, int y, char tipo, char nome [10], int turno) { int contador = 0; if (tabuleiro[x][y] == 1) { if (tabuleiro[x + 1][y + 1] == 0) inserirMovimentoPossivel(tree, x + 1, y + 1, tipo, nome, turno); if (tabuleiro[x - 1][y + 1] == 0) inserirMovimentoPossivel(tree, x + 1, y + 1, tipo, nome, turno); while (contador < 5) { //recorre 5 vezes a função possibleMoves(tree, x + 1, y + 1, tipo, nome, turno); possibleMoves(tree, x - 1, y + 1, tipo, nome, turno); contador++; } } if (tabuleiro[x][y] == 2) { if (tabuleiro[x + 1][y - 1] == 0) inserirMovimentoPossivel(tree, x + 1, y + 1, tipo, nome, turno); if (tabuleiro[x - 1][y - 1] == 0) inserirMovimentoPossivel(tree, x + 1, y + 1, tipo, nome, turno); while (contador < 5) {//recorre 5 vezes a função possibleMoves(tree, x - 1, y - 1, tipo, nome, turno); possibleMoves(tree, x + 1, y - 1, tipo, nome, turno); contador++; } } }
Move MCBoard::randomMove() { std::list<Move> l = possibleMoves(); if (!l.empty()) { unsigned int choose = rand() % l.size(); unsigned int c = 0; for (const auto& m: l) { if (c == choose) { return m; } c++; } } return NoMove; }
vector<Point> AIPlayer::getAllPossibleMoves(GameField gameField) { int i, j; vector<Point> possibleMoves(0); for (i = 0; i < gameField.getSize(); i++) { for (j = 0; j < gameField.getSize(); j++) { if (gameField.isEmpty(i, j)) { possibleMoves.push_back(Point(i, j)); cout << i << " " << j << endl; } } } return possibleMoves; }
Move MCBoard::findBestMove() { Move best_move = NoMove; std::list<Move> l = possibleMoves(); int best_value = -mateValue(); for (const auto& m: l) { move(m); std::cerr << m.toString() << std::endl; int r = evaluatePosition(turn); if (r > best_value) { best_value = r; best_move = m; } std::cerr << r << " - " << best_value << std::endl; undo(m); } return best_move; }
Move *Player::doMove(Move *opponentsMove, int msLeft) { /* * TODO: Implement how moves your AI should play here. You should first * process the opponent's opponents move before calculating your own move */ Side opside; if (side == BLACK) { opside = WHITE; } else { opside = BLACK; } board.doMove(opponentsMove, opside); updateWeights(opponentsMove); if(board.hasMoves(side)) { std::vector<Move*> moves = possibleMoves(); int max_index = 0; //index of the move whose square has the highest known heuristic value for (unsigned i = 0; i < moves.size(); i++) { if (getSquareWeight(moves[i]) > getSquareWeight(moves[max_index])) { max_index = i; } } board.doMove(moves[max_index], side); updateWeights(moves[max_index]); return moves[max_index]; } else { return NULL; } }
int Minimax::doMinimax(std::vector<VolcanoBoard>& res, const VolcanoBoard& vb, int depth) { VolcanoBoard currVb, bestVb; std::vector<VolcanoBoard> currList, bestList; depth--; bool touched = false; int bestScore = MAX_SCORE; if (vb.isFirstPlayer()) { bestScore = -bestScore; } int currScore = 0; // get all possible moves. VolcanoMoveGen possibleMoves(vb); while (!possibleMoves.isEnd()) { currVb = *possibleMoves; if (testEndCondition(vb) || depth <= 0) { // game over, get score currScore = getScore(vb); } else { // score by calling doMinimax recursively currVb.changePlayer(); currScore = doMinimax(currList, currVb, depth); } if (!vb.isFirstPlayer()) { currScore = -currScore; } if (vb.isFirstPlayer() && currScore > bestScore) { // if p1, return max scoring move bestScore = currScore; bestVb = currVb; bestList = currList; touched = true; } else if (!vb.isFirstPlayer() && currScore < bestScore) { // if p2, return min scoring move bestScore = currScore; bestVb = currVb; bestList = currList; touched = true; } possibleMoves++; } if (touched) { TODO : curr/bestLists res.push_back(bestVb); } else { // raise error } return bestScore; /* function minimax(node, depth, maximizingPlayer) if depth = 0 or node is a terminal node return the heuristic value of node bestValue := -∞ for each child of node val := minimax(child, depth - 1, FALSE) bestValue := max(bestValue, val) return -bestValue */ }
// graph where s_i = {pos_D, pos_R, cost}, pointer to parents. // possible entries (diamond pushes) are added with wavefront // the shortest path till now is explored further (heap) // hash table to check if node exists bool Sokoban::findPath(){ printMap(map_); std::cout << "Init. finding paths..." << std::endl; // graph to store the tree of possibilities graph paths; // has a solution been found bool solution_found = false; // - make needed maps // heuristic map std::vector< std::vector<char> > heuristic_map = map_; wavefront(heuristic_map, goals_); // printMap(heuristic_map); // std::cout << std::endl; // deadlock map std::vector< std::vector<char> > deadlock_map = map_; deadlocks(deadlock_map); // printMap(deadlock_map); // the next child to consider (lowest cost) node * cheapest_leaf = nullptr; // node to add node nextnode(0, cheapest_leaf, heuristic_map); nextnode.setRobot(pos_t(robot_.x_, robot_.y_)); nextnode.setDiamonds(diamonds_); std::cout << "# of Diamonds: " << diamonds_.size() << std::endl; // add the initial position paths.createChild(nextnode); int lastCost = 0; std::cout << "Exploring paths..." << std::endl; // run this until the path is found or no paths can be taken int iterations = 0; // debug thing while(!solution_found && paths.getNextChild(cheapest_leaf)){ iterations++; // if(lastCost < cheapest_leaf->getCost() + cheapest_leaf->getHeuristic()){ // lastCost = cheapest_leaf->getCost() + cheapest_leaf->getHeuristic(); // std::cout << "current cost: " << lastCost << ", open-/closed-list size: " << paths.getOpenListSize() << " / " << paths.getClosedListSize() << std::endl; // } // check cheapest leaf if it is the solution solution_found = cheapest_leaf->compSolution(map_); if(!solution_found){ // generate the key for the element std::string key = cheapest_leaf->getKey(map_size_.x_); // check that this node has not already been found, if so, remove it bool unique_node = paths.nodeUnique(key); bool valid_node = false; std::vector< pos_t > * diamonds; if(unique_node){ paths.addChild(cheapest_leaf, key); // get diamonds pointer diamonds = cheapest_leaf->getDiamonds(); // check that the node is valid (all diamonds are in valid positions) valid_node = validNode(diamonds, deadlock_map); } else{ paths.deleteChild(cheapest_leaf); } std::vector< std::vector<char> > wf_map; if(unique_node && valid_node){ wf_map = map_; // make wf map for(int d = 0; d < diamonds->size(); d++){ int x = (*diamonds)[d].x_; int y = (*diamonds)[d].y_; wf_map[y][x] = MAP_DIAMOND; } // make wavefront from pos to see the distance to the diamonds std::vector< pos_t > robot_position = {*(cheapest_leaf->getRobotPos())}; wavefront(wf_map, robot_position); // find the diamonds that can be moved std::vector< node > moves; possibleMoves(wf_map, diamonds, moves, cheapest_leaf); // add the moves to the heap (does not take care of states being the same) for(int newChild = 0; newChild < moves.size(); newChild++){ // update heuristics first moves[newChild].updateHeuristic(heuristic_map); // add the child // paths.createChild(moves[newChild]); } paths.createChild(moves); } } else{ // return shortest path node * parent = cheapest_leaf->getParent(); node * child = cheapest_leaf; path_ = ""; while(parent != nullptr){ std::vector< pos_t > p_diamonds; std::vector< pos_t > c_diamonds; std::vector< std::vector<char> > wf_map; p_diamonds = *(parent->getDiamonds()); c_diamonds = *(child->getDiamonds()); // set diamonds to walls to generate wfamp to move with wf_map = map_; for(int d = 0; d < p_diamonds.size(); d++){ int x = (p_diamonds)[d].x_; int y = (p_diamonds)[d].y_; wf_map[y][x] = MAP_DIAMOND; } // robot pos pos_t p_position = *(parent->getRobotPos()); pos_t c_position = *(child->getRobotPos()); std::vector< pos_t > wf_start = {p_position}; wavefront(wf_map, wf_start); // find the diamond that was moved int p_d = 0; int c_d = 0; while(p_diamonds.size() != 1){ bool somethingremoved = false; c_d = 0; while(c_d < c_diamonds.size() && !somethingremoved){ if((p_diamonds)[p_d].y_ == (c_diamonds)[c_d].y_ &&(p_diamonds)[p_d].x_ == (c_diamonds)[c_d].x_){ // remove the diamond p_diamonds.erase(p_diamonds.begin() + p_d); c_diamonds.erase(c_diamonds.begin() + c_d); somethingremoved = true; } c_d++; } p_d++; if(p_d >= p_diamonds.size()){ p_d = 0; } } // adjust the start pos to be t push spot int x = (p_diamonds)[0].x_ - (c_diamonds)[0].x_; int y = (p_diamonds)[0].y_ - (c_diamonds)[0].y_; c_position.x_ += x; c_position.y_ += y; // find sub path std::string subpath = ""; findSubPath(subpath,wf_map, p_position, c_position); // add the final push if(x == 1 && y == 0){ subpath += "W"; } else if(x == -1 && y == 0){ subpath += "E"; } else if(x == 0 && y == 1){ subpath += "N"; } else if(x == 0 && y == -1){ subpath += "S"; } // add the path path_ = subpath + path_; // find new nodes child = parent; parent = child->getParent(); } std::cout << "Cheapest path length: " << cheapest_leaf->getCost() << std::endl; } } if(!paths.getNextChild(cheapest_leaf)){ std::cout << "No more possible paths left to explore.\n"; } std::cout << "# of iterations gone through: " << iterations << "\n"; std::cout << "# of elements in closed list: " << paths.getClosedListSize() << "\n"; std::cout << "# of elements in open list: " << paths.getOpenListSize() << "\n"; return solution_found; }