TEST(HeuristicTest, PrioritizeWinningSooner) { auto gb = GameBoard{" /OX /OX "}; // {0,0} prevents a loss that would happen in 1 move // {1,0} immediately wins EXPECT_GT(gb.getHeuristic(Move{1,0}), gb.getHeuristic(Move{0,0})); }
TEST(HeuristicTest, BetterMinimizingMovesHaveSmallerValues) { auto gb = GameBoard{" / X / "}; // Because this is the second move, it's OPlayer's turn, and // X is the maximizing player. Hence the better move has the // smaller value. EXPECT_LT(gb.getHeuristic(Move{0,0}), gb.getHeuristic(Move{1,0})); }
//see https://en.wikipedia.org/wiki/A*_search_algorithm std::vector<sf::Vector2f> Pathfinder::findPath(const sf::Vector2i& startPos, const sf::Vector2i& goalPos){ if (startPos.x >= 0 && startPos.y >= 0 && goalPos.x >= 0 && goalPos.y >= 0 && startPos.x < m_mapWidth && startPos.y < m_mapHeight && goalPos.x < m_mapWidth && goalPos.y < m_mapHeight) { int size = m_mapWidth * m_mapHeight; int startIndex = startPos.x + (startPos.y * m_mapWidth); int goalIndex = goalPos.x + (goalPos.y * m_mapWidth); Node* start = m_nodes[startIndex]; Node* goal = m_nodes[goalIndex]; if (start != 0 && goal != 0){ //reset nodes for (int i = 0; i < size; i++){ if (m_nodes[i] != 0) m_nodes[i]->reset(); } //pair is fcost,index. storing node pointers causes invalid heap priority_queue<std::pair<int, int>, vector<std::pair<int, int>>, NodeSearchCostComparer> openset; start->setGCost(0); start->setFCost(getHeuristic(start, goal)); start->setOpen(true); openset.push(std::pair<int,int>(start->fCost(), startIndex)); while (openset.size() != 0) { Node* current = m_nodes[openset.top().second]; openset.pop(); if (current == goal) return createPath(startIndex, goalIndex); current->setOpen(false); //remove from open current->setClose(true); //set as closed // if (neighbour != current->getPrevious()){ for (int i = 0; i < 8; i++) { //loop through neighbours int neighbourIndex = getNeighbourIndex(current, i); Node* neighbour = (neighbourIndex == -1) ? 0 : m_nodes[neighbourIndex]; if (neighbour == 0 || neighbour->close() || neighbour == current->getPrevious() || neighbour->walkable() == false) continue; int tenativeGCost = current->gCost() + getCost(m_neighbourOffsets[i]); if (tenativeGCost <= neighbour->gCost()){ neighbour->setPrevious(current); neighbour->setGCost(tenativeGCost); neighbour->setFCost(neighbour->gCost() + getHeuristic(neighbour, goal)); } if (neighbour->open() == false){ //not explored neighbour->setOpen(true); neighbour->setColour(sf::Color(0, 128, 128, 255)); openset.push(std::pair<int,int>(neighbour->fCost(), neighbourIndex)); } } } if (openset.size() == 0) cout << "Couldn't find path." << endl; } } return std::vector<sf::Vector2f>(); }
TEST(HeuristicTest, BestFirstMoveXInCenter) { auto gb = GameBoard{" / / "}; EXPECT_LT(gb.getHeuristic(Move{0,0}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{1,0}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{2,0}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{0,1}), gb.getHeuristic(Move{1,1})); EXPECT_EQ(gb.getHeuristic(Move{1,1}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{2,1}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{0,2}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{1,2}), gb.getHeuristic(Move{1,1})); EXPECT_LT(gb.getHeuristic(Move{2,2}), gb.getHeuristic(Move{1,1})); }
int main(int argc, char **argv){ start = (State *) malloc(sizeof(State)); start->from = -1; goal = (State *) malloc(sizeof(State)); char defaultMaze[] = "maze1.txt"; char * mazeFilename = read_string(argc, argv, "-m", defaultMaze); loadMaze(mazeFilename); AS_Node * startNode = newASNode(getHeuristic(start), 0); startNode->state = start; AS_Config config; AS_initConfig(&config); config.areSameStates = &areSameState; config.isGoalState = &isGoalState; config.expandNode = &expandNode; config.queueInitialCapacity = 20000; config.closedSetChunkSize = 20000; config.startNode = startNode; AS_NodePointer * path = AS_search(&config); printMaze(); if(path){ printf("Solution found.\n"); assignPathToMaze(path); printMaze(); AS_freePath(path); }else{ printf("Solution not found\n."); } return 0; }
void createNode(AS_Node * node, State * oldState, int swapIndexA, int swapIndexB){ State * state = (State *) malloc(sizeof(int)*dimension*dimension); memcpy(state, oldState, sizeof(int)*dimension*dimension); state[swapIndexA] = oldState[swapIndexB]; state[swapIndexB] = oldState[swapIndexA]; ASNode_init(node, getHeuristic(state)); node->state = state; }
TEST(HeuristicTest, SymmetricBoardStatesAreEquivalent) { auto gb = GameBoard{" / X / "}; // Corners EXPECT_EQ(gb.getHeuristic(Move{0,0}), gb.getHeuristic(Move{2,2})); EXPECT_EQ(gb.getHeuristic(Move{2,0}), gb.getHeuristic(Move{2,2})); EXPECT_EQ(gb.getHeuristic(Move{0,2}), gb.getHeuristic(Move{2,2})); // Sides EXPECT_EQ(gb.getHeuristic(Move{1,2}), gb.getHeuristic(Move{1,0})); EXPECT_EQ(gb.getHeuristic(Move{2,1}), gb.getHeuristic(Move{1,0})); EXPECT_EQ(gb.getHeuristic(Move{0,1}), gb.getHeuristic(Move{1,0})); }
TEST(HeuristicTest, MoveRankingTransitivity) { auto gb = GameBoard{" /OX / "}; // Best moves are {0,0}, {2,0}, {1,0}, and {2,1} in that order EXPECT_LT(gb.getHeuristic(Move{2,0}), gb.getHeuristic(Move{0,0})); EXPECT_LT(gb.getHeuristic(Move{1,0}), gb.getHeuristic(Move{2,0})); EXPECT_LT(gb.getHeuristic(Move{2,1}), gb.getHeuristic(Move{1,0})); // Check transitivity EXPECT_LT(gb.getHeuristic(Move{1,0}), gb.getHeuristic(Move{0,0})); EXPECT_LT(gb.getHeuristic(Move{2,1}), gb.getHeuristic(Move{0,0})); EXPECT_LT(gb.getHeuristic(Move{2,1}), gb.getHeuristic(Move{2,0})); }
int heuristicForState(GameState* gs, int player, int other) { if (isDraw(gs)) return 0; int term_stat = getWinner(gs); if (term_stat == player) return 1000; if (term_stat) return -1000; return getHeuristic(gs, player, other); }
int main(int argc, char **argv){ dimension = read_int(argc, argv, "-d", 3); unsigned int seed = read_int(argc, argv, "-r", time(NULL) ); srand (seed); start = (State *) malloc(sizeof(State) * dimension * dimension); do{ int l = dimension * dimension; for(int i = 0; i<l; i++){ start[i] = 0; } //Create a random state for(int i = 1; i<l; i++){ int index = rand() % l; while(start[index] != 0) index = rand() % l; start[index] = i; } }while(!stateHasSolution(start)); AS_Node * startNode = newASNode(getHeuristic(start)); startNode->state = start; AS_Config config; AS_initConfig(&config); config.areSameStates = &areSameState; config.isGoalState = &isGoalState; config.expandNode = &expandNode; config.queueInitialCapacity = 20000; config.closedSetChunkSize = 20000; config.startNode = startNode; printf("Initial state:\n"); printState(start); AS_NodePointer * path = AS_search(&config); if(path){ printf("Solution found.\n"); //printPath(path); AS_freePath(path); }else{ printf("Solution not found\n."); } return 0; }
void createNode(AS_Node * node, AS_Node * oldNode, int x, int y){ State * state = (State *) malloc(sizeof(State)); State * oldState = (State *) oldNode->state; state->x = x; state->y = y; state->from = oldState->y*maze.sizeX + oldState->x; state->points = (bool *) malloc(sizeof(bool) * maze.pointsLength); memcpy(state->points, oldState->points, sizeof(bool) * maze.pointsLength); if(MAZE_AT(x,y) == M_POINT){ int pointIndex = y*maze.sizeX + x; for(int i = 0; i<maze.pointsLength; i++){ if(maze.points[i] == pointIndex){ state->points[i] = true; break; } } } ASNode_init(node, getHeuristic(state), oldNode->cost + 1); node->state = state; }
minmax_t Minimax::minimax(Node * node, unsigned int depth, bool isMax) { if (depth == 0 || node->isLeaf()) { node->setHeuristic(getHeuristic(node->getMove())); minmax_t ret; ret.node = node; ret.heuristc = node->getHeuristic(); return ret; } if (isMax) { uint8_t best = INT8_MAX; for (int i = 0; i < node->getLength(); ++i) { minmax_t val = minimax(node->getNodeAt(i), depth - 1, true); best = std::min(best, val.heuristc); } minmax_t ret; ret.node = node; ret.heuristc = best; return ret; } else { uint8_t best = INT8_MIN; for (int i = 0; i < node->getLength(); ++i) { minmax_t val = minimax(node->getNodeAt(i), depth - 1, false); best = std::max(best, val.heuristc); } minmax_t ret; ret.node = node; ret.heuristc = best; return ret; } }
void Player::calculateStep(const Position& target) { // Abbruchbedienung (Spieler-Position erreicht) if (current != 0 && current->position == position) return; // Nachbarn des aktuellen Knoten beziehen std::list<Node> neighbors = map.getNeighbors(current->position); for (std::list<Node>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { Node& neighbor = *it; // wenn Kosten größer 0 und noch nicht finalized if (neighbor.costs > 0 && finalized.find(neighbor.position) == finalized.end()) { // in todo Liste nach Nachbarn suchen nodeMap::iterator todoIt = todo.find(neighbor.position); // wenn noch nicht in todo Liste oder aktuelle Kosten kleiner als Kosten in todo Liste if (todoIt == todo.end() || todoIt->second.costs > neighbor.costs + current->costs) { // wenn in todo Liste, Nachbarn aus todo Liste löschen if (todoIt != todo.end()) todo.erase(todoIt); // Nachfolger auf aktuellen Knoten setzen neighbor.next = current; // Kosten um bisherige Kosten erhöhen neighbor.costs += current->costs; // in todo Liste einfügen todo.insert(mapElement(neighbor.position, neighbor)); } } } current = &(todo.begin()->second); int currentHeuristic = getHeuristic(current->position, position); // in todo Liste nach billigstem Knoten suchen for (nodeMap::iterator it = todo.begin(); it != todo.end(); ++it) { Node& node = it->second; // Heuristik berechnen int heuristic = getHeuristic(node.position, position); // Gesamtkosten vergleichen if (node.costs + heuristic < current->costs + currentHeuristic) { currentHeuristic = heuristic; current = &node; } } // Knoten in die finalized List einfügen finalized.insert(mapElement(current->position, *current)); current = &finalized.at(current->position); // Knoten aus der todo Liste löschen todo.erase(current->position); calculateStep(target); }
int GridMap::getHeuristic(int startNodeID, int targetNodeID) const { return getHeuristic(toNodeCoord(startNodeID), toNodeCoord(targetNodeID)); }
int HeuristicLimitedSearchMin(SearchBoard *board,Player player,int HMaxZero,const int Level, int Alpha, int Beta, int n, clock_t AcumulatedTime) { bool FoundOnHash; int HashLevel; int HashHeuristic; clock_t Defasagem = AcumulatedTime - clock(); //printf("\nfuncionou ate aqui min\n"); if(n>nivelmax) nivelmax = n; int HMaxLimit = HMaxZero - Level; int HMinLimit = -HMaxZero - Level; numchamadas++; SearchList Greedy; PossibleMovesListMin(board, player,&Greedy); SearchList NextLevel = NewEmptyListMin(); SearchMove M;// = DequeueList(&Greedy); SearchBoard NewBoard; enum piece backup; int LastHeuristic = getHeuristic(board,player); //if(IsEmpty(&Greedy)) //{printf("\n<<<<<<<<<<<<<<<<<<<<<<BUGOU MUITO BIZARRO>>>>>>>>>>>>>>>>>>>>>\n");printBoard(board->board);} while((!IsEmpty(&Greedy))/*&&(-M.hmax-n>HMinLimit)*/) { if(clock()-Tzero>TimeMax) { printf("\nacabou o tempo: %d\n",clock()-Tzero); TimeInterruptionLastSearch = true; return -1000; } numjogadas++; M = DequeueList(&Greedy); NewBoard = *board; if(mkCmpMove(&NewBoard,player,M.Move)!=invalid) { FoundOnHash = false; /*if(getHashValue(&NewBoard, (Player)ChangePlayer(player), &HashHeuristic, &HashLevel)) { if(HashLevel>1+Level-n) { M.h_max = HashHeuristic; FoundOnHash = true; printf("\n%d", HashLevel); } }*/ //if((n<=NIVEL_MAX)&&(-M.h_max-n>HMaxLimit||-M.h_max!=LastHeuristic)) if(!FoundOnHash&&/*n<=NIVEL_MAX&&*/(n<Level||(M.h_max!=LastHeuristic)&&(n<Level+2))) { M.h_max = HeuristicLimitedSearchMax(&NewBoard, (Player)ChangePlayer(player), HMaxZero, Level, Alpha, Beta, n+1, Defasagem+clock()); if(TimeInterruptionLastSearch) return -1000; //addToHash(&NewBoard, (Player)ChangePlayer(player), M.h_max, 1+Level-n); //if(n==Ntest) printf("\nmin%d:%d",n,M.h_max); } //else printf("\n%d\n",n); //undoMov(board->board,M.Move,backup); EnqueueList(&NextLevel,M); // AlphaBeta condition // Alpha is the value of the best alternative for MAX along the path to board // Beta is the value of the best alternative for MIN along the path to board if(M.h_max<Alpha) { EmptyList(&Greedy); EmptyList(&NextLevel); return M.h_max; } if(M.h_max<Beta) Beta = M.h_max; } //M = DequeueList(&Greedy); } move Mov1,Mov2; int resp1 = REAL_MAX, resp2 = REAL_MAX; OrdenateList(&Greedy); OrdenateList(&NextLevel); if(IsEmpty(&Greedy )&&IsEmpty(&NextLevel)) { //printf("BIZU!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",n); return REAL_MAX-n; } if(!IsEmpty(&Greedy )) resp1 = DequeueList(&Greedy).h_max; if(!IsEmpty(&NextLevel)) resp2 = DequeueList(&NextLevel).h_max; //while(!IsEmpty(&Greedy)) printf("\n%d:%d",n,DequeueList(&Greedy).h_max); //while(!IsEmpty(&NextLevel)) printf("\n%d:%d",n,DequeueList(&NextLevel).h_max); //printf("\n%d:final: %d",n,(resp1<resp2?resp1:resp2)); //if(resp1==resp2&&resp1==REAL_MAX&&IsEmpty(&Greedy )&&IsEmpty(&NextLevel)) return REAL_MAX-10;//printf("MIN%dBUGOU BIZARRO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",n); EmptyList(&Greedy); EmptyList(&NextLevel); //if(n==Ntest) printf("\nMIN%d:%d",n,(resp1<resp2?resp1:resp2)); return (resp1<resp2?resp1:resp2); }
TEST(HeuristicTest, GreaterThan) { auto gb = GameBoard{" /OX / "}; // Best moves are {0,0}, {2,0}, {1,0}, and {2,1} in that order EXPECT_GT(gb.getHeuristic(Move{0,0}), gb.getHeuristic(Move{2,0})); }
int Player1::alphaBeta (int depth, int alpha, int beta, bool MAXplayer) { int heuristic = 0; bool go = false; int temp; char winner = 'N'; // 'N' for NULL go = isSolved(winner); // get heur info if (depth == 3 || go ) // or node is a terminal node { heuristic = getHeuristic(depth, winner, !(MAXplayer)); return heuristic;// value of the terminal game tree node } if (MAXplayer) //for each child of node { for (int p = 0; p < 19; p++){ for (int q = 0; q < 19; q++) { if (pOneBoard[p][q] == 'E' && playerDetected(p,q)) { pOneBoard[p][q] = 'P'; // make move on board temp = alphaBeta(depth+1, alpha, beta, !(MAXplayer)); // total recursive calls boardsExamined++; // -- maxmax start- //if (temp > alpha) alpha = temp; //a = max() //pOneBoard[p][q] = 'E'; //unmake move on board // -- maxmax end--- // -- ab code start- if (temp < alpha) alpha = temp; //alpha = max() if (beta <= alpha) { pOneBoard[p][q] = 'E';break; } else pOneBoard[p][q] = 'E'; // -- ab cod end --- }}} return alpha; // α } else //MINplayer //for each child of node { for (int p = 0; p < 19; p++){ for (int q = 0; q < 19; q++) { if (pOneBoard[p][q] == 'E' && playerDetected(p,q)) { pOneBoard[p][q] = 'T'; // make move on board temp = alphaBeta(depth+1, alpha, beta, !(MAXplayer)); // total recursive calls boardsExamined++; // -- maxmax start- //if (temp > beta) beta = temp; // β := max() //pOneBoard[p][q] = 'E'; //unmake move on board // -- maxmax end--- // -- ab code start- if (temp > beta) beta = temp; // β := min() if (beta <= alpha) { pOneBoard[p][q] = 'E'; break; } else pOneBoard[p][q] = 'E'; // -- ab cod end --- }}} return beta; // β } }
move IterativeMinMax(SearchBoard *board, Player player, int time_max) { char name[6]; int TIME_INCREASE = 1; SearchList Greedy = NewEmptyListMax(); SearchList NextLevel; if(player==whites) PossibleMovesListMax(board, player, &NextLevel); else PossibleMovesListMin(board, player, &NextLevel); SearchMove M; SearchBoard NewBoard; enum piece backup; int HMaxLimit = getHeuristic(board, player); int Alpha = REAL_MIN; int Beta = REAL_MAX; int ContadorDoNumerodeJogadasPossiveis=0; Tzero = clock(); clock_t SpentTime = 1;// para nao ter 0 no denominador TimeMax = time_max*CLOCKS_PER_SEC; TimeInterruptionLastSearch = false; clock_t AcumulatedTime; int auxiliar; for(int i=2; clock()-Tzero<time_max && !TimeInterruptionLastSearch /*&& i<=NIVEL_MIN*/; i++) { //NIVEL_MAX = i; Alpha = REAL_MIN; Beta = REAL_MAX; OrdenateList(&NextLevel); AtributeList(&Greedy,&NextLevel); EmptyList(&NextLevel); //M = DequeueList(&Greedy); ContadorDoNumerodeJogadasPossiveis = 0; while(!TimeInterruptionLastSearch&&clock()-Tzero<time_max&&!IsEmpty(&Greedy)) { M = DequeueList(&Greedy); movToStr(M.Move,name); //printf("\n%s:",name); NewBoard = *board; if(mkCmpMove(&NewBoard,player,M.Move)!=invalid) { ContadorDoNumerodeJogadasPossiveis++; movToStr(M.Move,name); printf("\n%d : ",i); printf("%s: %d",name,M.h_max); AcumulatedTime = clock(); if(player==whites) auxiliar = HeuristicLimitedSearchMin(&NewBoard,(Player)ChangePlayer(player),HMaxLimit,i,Alpha,Beta,1,AcumulatedTime); else auxiliar = HeuristicLimitedSearchMax(&NewBoard,(Player)ChangePlayer(player),HMaxLimit,i,Alpha,Beta,1,AcumulatedTime); if(!TimeInterruptionLastSearch) { M.h_max = auxiliar; } printf(" : %d\n",M.h_max); //printf("%d",M.h_max); EnqueueList(&NextLevel,M); } else { //printf("\nfail"); } //M = DequeueList(&Greedy); } if(ContadorDoNumerodeJogadasPossiveis==1) return DequeueList(&NextLevel).Move; //TIME_INCREASE = (time(NULL)-Tzero)/SpentTime; //SpentTime = time(NULL)-Tzero; } ConcatenateList(&Greedy,&NextLevel); OrdenateList(&Greedy); SearchMove resp, aux; resp = DequeueList(&Greedy); NewBoard = *board; mkCmpMove(&NewBoard,player,aux.Move); int contador; srand(time(NULL)); SearchBoard AnotherNewBoard; while(!IsEmpty(&Greedy)) { aux = DequeueList(&Greedy); AnotherNewBoard = *board; mkCmpMove(&AnotherNewBoard,player,aux.Move); if((player==whites&&aux.h_max>resp.h_max)||(player==blacks&&aux.h_max<resp.h_max)) { resp = aux; NewBoard = *board; mkCmpMove(&NewBoard,player,aux.Move); } if(aux.h_max==resp.h_max) { AnotherNewBoard = *board; mkCmpMove(&AnotherNewBoard,player,aux.Move); if((player==whites&&get_heuristics(&AnotherNewBoard,player)>get_heuristics(&NewBoard,player)) ||(player==blacks&&get_heuristics(&AnotherNewBoard,player)<get_heuristics(&NewBoard,player)) ||rand()%50==0) { resp = aux; NewBoard = AnotherNewBoard; } } } return resp.Move; }