Beispiel #1
0
    const Node* explore(const State& startState, TerminationChecker& terminationChecker) {
        ++iterationCounter;
        clearOpenList();
        openList.reorder(fComparator);

        Planner::incrementGeneratedNodeCount();
        Node*& startNode = nodes[startState];

        if (startNode == nullptr) {
            startNode = nodePool->construct(Node{nullptr, startState, Action(), 0, domain.heuristic(startState), true});
        } else {
            startNode->g = 0;
            startNode->action = Action();
            startNode->predecessors.clear();
            startNode->parent = nullptr;
        }

        startNode->iteration = iterationCounter;
        addToOpenList(*startNode);

        while (!terminationChecker.reachedTermination() && openList.isNotEmpty()) {
            Node* const currentNode = popOpenList();

            if (domain.isGoal(currentNode->state)) {
                return currentNode;
            }

            terminationChecker.notifyExpansion();
            expandNode(currentNode);
        }

        return openList.top();
    }
void RxDev::showContextMenu_availableNodes(const QPoint&point){

    QMenu contextMenu_availableNodes;
    QModelIndex index(ui->treeView_availableNodes->indexAt(point));
    //menuPoint_availableNodes = point;
    //const QModelIndex index = ui->treeView_availableNodes->selectionModel()->currentIndex();
    QModelIndex seekRoot = index;
    if(index.isValid()){

    while(seekRoot.parent() != QModelIndex())
    {
        seekRoot = seekRoot.parent();

    }
    contextMenu_availableNodes.addAction(tr("view/edit Specfile"),this, SLOT(openSpecFile()));
    contextMenu_availableNodes.addAction(tr("expand"),this, SLOT(expandNode()));
    contextMenu_availableNodes.addAction(tr("collapse"),this, SLOT(collapseNode()));
    contextMenu_availableNodes.addSeparator();
    contextMenu_availableNodes.addAction(tr("expand all"),this, SLOT(expandAll()));
    contextMenu_availableNodes.addAction(tr("collapse all"),this, SLOT(collapseAll()));



    contextMenu_availableNodes.exec(ui->treeView_availableNodes->viewport()->mapToGlobal(point));
    }
}
Beispiel #3
0
//returns true if there were no prob creating a path
//error only occur if there's something wrong with the parameter
//can (and will) return true even if there is no way to the destination
bool PathPlanner::Planning(int start[2], int goal[2]) {
	if(!inBounds(start) || !inBounds(goal)) return false;

	std::vector<Path> pathList;
	Path init(0,computeHeuristic(start[0],start[1],goal[0],goal[1]));
	init.nodes.push_back(&nodeMap[start[0]][start[1]]);
	nodeMap[start[0]][start[1]].state = FRONTIER;
	pathList.push_back(init);

	Path newpath;
	Path toexpand;
	Node* lastnode;

	while(pathList.size() != 0 ) {
		std::sort(pathList.begin(),pathList.end());
		toexpand = pathList.back();
		pathList.pop_back();

		if(toexpand.nodes.back() == &nodeMap[goal[0]][goal[1]]) {
			path = toexpand;
			return true;
		}

		lastnode = toexpand.nodes.back();

		if( lastnode->state != EXPLORED) {

			//bottom
			expandNode(toexpand,&pathList,0,1,3,goal);

			//right
			expandNode(toexpand,&pathList,1,0,3,goal);

			// left
			expandNode(toexpand,&pathList,-1,0,3,goal);

			//top
			expandNode(toexpand,&pathList,0,-1,3,goal);

			//top-left
			expandNode(toexpand,&pathList,-1,-1,4,goal);

			//top-right
			expandNode(toexpand,&pathList,1,-1,4,goal);

			//bottom-left
			expandNode(toexpand,&pathList,-1,1,4,goal);

			//bottom-right
			expandNode(toexpand,&pathList,1,1,4,goal);

			toexpand.nodes.back()->state = EXPLORED;
		}

	}
	return false;
}
Beispiel #4
0
    Node* explore(const State& startState, TerminationChecker& terminationChecker) {
        ++iterationCounter;
        clearOpenList();
        openList.reorder(fComparator);

        Planner::incrementGeneratedNodeCount();
        Node*& startNode = nodes[startState];

        if (startNode == nullptr) {
            startNode = nodePool->construct(Node{nullptr, startState, Action(), 0, domain.heuristic(startState), true});
        } else {
            startNode->g = 0;
            startNode->action = Action();
            startNode->predecessors.clear();
            startNode->parent = nullptr;
        }

        startNode->iteration = iterationCounter;
        addToOpenList(*startNode);

        Node* currentNode = startNode;

        checkSafeNode(currentNode);

        while (!terminationChecker.reachedTermination() && !domain.isGoal(currentNode->state)) {
            //            if (domain.safetyPredicate(currentNode->state)) { // try to find nodes which lead to safety
            //                currentNode = popOpenList();
            //                terminationChecker.notifyExpansion();
            //                expandNode(currentNode);
            //            }
            //
            //            if (currentNode == startNode) { // if we can't just do LSS-LRTA*
            //                while (!terminationChecker.reachedTermination() && !domain.isGoal(currentNode->state)) {
            //                    currentNode = popOpenList();
            //                    terminationChecker.notifyExpansion();
            //                    expandNode(currentNode);
            //                }
            //            }
            Node* const currentNode = popOpenList();
            if (domain.isGoal(currentNode->state)) {
                return currentNode;
            }

            terminationChecker.notifyExpansion();
            expandNode(currentNode);
        }

        return openList.top();
    }
void Astar::execute() {
  do {
    std::set<Node>::iterator it = std::min_element(openList.begin(), openList.end(), Node::CompareCostWithHeuristic());
    Node currentNode = *it;
    openList.erase(it);
    if (isGoalNode(currentNode)) {
      pathFound = true;
      lastNode = currentNode;
      return;
    } else {
      currentNode.setPaint(CLOSED);
      closedList.insert(currentNode);
    }
    expandNode(currentNode);
  } while (not openList.empty());
  pathFound = false;
}
Beispiel #6
0
std::vector<SearchNode*>* AStar::searchPath(SearchNode* start, SearchNode* goal){

  queue.clear();

  currentIteration++;

  currentGoal = goal;
  //put start in the queue
  start->computeHeuristic(currentGoal);
  start->g=0;
  start->f=start->h;
  start->expanded = false;
  start->iteration = currentIteration;
  queue.push(start->f, start);
  //while queue front != goal
  while(queue.empty()==false){
    SearchNode* n = queue.pop();
    if(n->iteration == currentIteration && n->expanded){
      continue;
    } else {
      if(n==currentGoal){
//        std::cerr<<"PATH FOUND"<<std::endl;

        std::vector<SearchNode*>* result = new std::vector<SearchNode*>();
        SearchNode* s = n;
        while(s!=NULL){
        	result->push_back(s);
        	s = s->getPredecessor();
        }
        return result;

      } else {
        expandNode(n);
      }
    }
  }

  std::cerr<<"search finished w/o result"<<std::endl;

  return NULL;
}
Beispiel #7
0
bool Pathfinder::pathfind(std::vector<PathfindingAction>& path)
{
#if 0
	pout << "Actor " << actor->getObjId();

	if (targetitem) {
		pout << " pathfinding to item: ";
		targetitem->dumpInfo();
	} else {
		pout << " pathfinding to (" << targetx << "," << targety << "," << targetz << ")" << std::endl;
	}
#endif

#ifdef DEBUG
	if (actor->getObjId() == visualdebug_actor) {
		RenderSurface* screen = GUIApp::get_instance()->getScreen();
		screen->BeginPainting();
		if (targetitem)
			drawbox(targetitem);
		else
			drawdot(targetx, targety, targetz, 2, 0xFF0000FF);
		screen->EndPainting();
	}
#endif


	path.clear();

	PathNode* startnode = new PathNode();
	startnode->state = start;
	startnode->cost = 0;
	startnode->parent = 0;
	startnode->depth = 0;
	startnode->stepsfromparent = 0;
	nodelist.push_back(startnode);
	nodes.push(startnode);

	unsigned int expandednodes = 0;
	const unsigned int NODELIMIT_MIN = 30;	//! constant
	const unsigned int NODELIMIT_MAX = 200;	//! constant
	bool found = false;
	Uint32 starttime = SDL_GetTicks();

	while (expandednodes < NODELIMIT_MAX && !nodes.empty() && !found) {
		PathNode* node = nodes.top(); nodes.pop();

#if 0
		pout << "Trying node: (" << node->state.x << "," << node->state.y
			 << "," << node->state.z << ") target=(" << targetx << ","
			 << targety << "," << targetz << ")" << std::endl;
#endif

		if (checkTarget(node)) {
			// done!

			// find path length
			PathNode* n = node;
			unsigned int length = 0;
			while (n->parent) {
				n = n->parent;
				length++;
			}
#if 0
			pout << "Pathfinder: path found (length = " << length << ")"
				 << std::endl;
#endif

			unsigned int i = length;
			if (length > 0) length++; // add space for final 'stand' action
			path.resize(length);

			// now backtrack through the nodes to assemble the final animation
			while (node->parent) {
				PathfindingAction action;
				action.action = node->state.lastanim;
				action.direction = node->state.direction;
				action.steps = node->stepsfromparent;
				path[--i] = action;
#if 0
				pout << "anim = " << node->state.lastanim << ", dir = "
					 << node->state.direction << ", steps = "
					 << node->stepsfromparent << std::endl;
#endif

				//TODO: check how turns work
				//TODO: append final 'stand' animation

				node = node->parent;
			}

			if (length) {
				if (node->state.combat)
					path[length-1].action = Animation::combatStand;
				else
					path[length-1].action = Animation::stand;
				path[length-1].direction = path[length-2].direction;
			}

			expandtime = SDL_GetTicks() - starttime;
			return true;
		}

		expandNode(node);
		expandednodes++;

		if(expandednodes >= NODELIMIT_MIN && ((expandednodes) % 5) == 0)
		{
			Uint32 elapsed_ms = SDL_GetTicks() - starttime;
			if(elapsed_ms > 350) break;
		}
	}

	expandtime = SDL_GetTicks() - starttime;

#if 0
	static sint32 pfcalls = 0;
	static sint32 pftotaltime = 0;
	pfcalls++;
	pftotaltime += expandtime;
	pout << "maxout average = " << (pftotaltime / pfcalls) << "ms." << std::endl;
#endif

	return false;
}
Beispiel #8
0
int AStarPath::pathFind() {
    if(!checkUnitBorders(destX/8, destY/8) && distance <=20) {
    	int newDestX = destX/8 + (rand()%3-1),
    		newDestY = destY/8 + (rand()%3-1);
    	bool help = true;
    	for(int i=0; i<distance; i++) {
    		newDestX += (rand()%3-1),
    		newDestY += (rand()%3-1);
			if(checkUnitBorders(newDestX, newDestY)) {
				this->destX = newDestX*8;
				this->destY = newDestY*8;
				help = false;
			}
    	}
    	std::cout << help << std::endl;
    	if(help) return 0;
    }

    // Creating a map object we search our path in. You move an unit from
    // a start coordinate tuple, given in pixels to a destination tuple,
    // also given in pixels. The map is designed as 64x64 pixel tiles, but
    // that's too unaccurate for a pathfinding algorithm. So I choiced 8x8
    // pixels, to be good enough.
    // As maps are currently sized at 110x110 tiles, which is not possible
    // to change. We need an graph with 880x880 nodes.
    // Because most nodes of your graph won't even be touched, these won't
    // be initialized at start.
    //map.resize(880);

    // The only two points which will be needed in each pathfinding call
    // are the start and destination nodes, so we are initializing them
    map[this->startX/8][this->startY/8] = new Node(this->startX/8,this->startY/8,0,0);
    map[this->destX/8][this->destY/8] = new Node(this->destX/8,this->destY/8,0,0);

    // The open list is a list of each object we are going to look at.
    // At the beginning, only the start node is in this list.
    open_list.push_back(map[this->startX/8][this->startY/8]);

    // Main loop for the algorithm, when this terminates, you have
    // either a found path or there is none existing.
    bool found = false;
    while(!found) {
        // If open_list is totally empty, we removed each object which is in
        // it, therefore, there is no path to destination because we looked
        // at every node.
        if(open_list.empty() || closed_list.size() >= 3000) {
            found = true;
            return 0;
        }

        // We are looking for the shortest path, so the neighbor nodes with lowest
        // distance, equals to highest priority, will get checked fist.
        // TODO: This can be optimized by remembering the point we're at and only looking for direct neighbours.
        int indexMin = 0;
        for(int i=open_list.size()-1; i>=0; i--) {
            if(open_list[indexMin]->getPriority() >= open_list[i]->getPriority()) {
                indexMin = i;
            }
        }
        //std::cout << "Current: " << open_list[indexMin]->getX() << "/" << open_list[indexMin]->getY() << std::endl;
        //std::cout << "Destination: " << this->destX << "/" << this->destY << std::endl;
        //std::cout << "openListSize: " << open_list.size() << std::endl;
        //std::cout << "closedListSize: " << closed_list.size() << std::endl;
        //std::cout << "empty? " << open_list.empty() << std::endl;

        // The current node will be set to the node which was found as the
        // one with highest priority.
        Node* currentNode = open_list[indexMin];

        // As we are looking at this node now, we will erase it from open list.
        open_list.erase(open_list.begin()+indexMin);

        // Euclid distance to destination
        // If distance arg is set, unit will only move until a range, so we
        // need to calculate range to destination to get a value to compare to.
        float toDest = getDistance(currentNode->getX()*8, currentNode->getY()*8, destX, destY);

        // If currentNode is the destination point, we're done with the algorithm.
        if(currentNode == map[destX/8][destY/8] || toDest <= distance) {
            found = true;

            Node* n = currentNode;
            bool help = true;

            // We are going back though each node we walked though while finding the path
            // using the getPredecessor() method, which provides a pointer to the previous
            // node in the path. This way, we go back from destination to the start while
            // writing the fastest path in a final_list queue.
            while(help) {
                final_list.push(n);
                n = map[n->getX()][n->getY()];
                n = n->getPredecessor();
                if(n == map[startX/8][startY/8]) {
                    final_list.push(n);
                    help = false;
                } else if(n == NULL) {
                    help = false;
                }
            }
            return 1;
        }

        // We are expanding the current node. This means, we are searching
        // for neighbour nodes which we should look at and add them to
        // the open list.
        expandNode(currentNode);

        // As we went though all things we can do with this current node,
        // we can add it to the closed list. This one won't get touched
        // any more. It's like a blacklist of nodes.
        closed_list.push_back(currentNode);
    }
    return 0; // This should never happen
}
Beispiel #9
0
// a non-recursive and hopefully somewhat parallel algorithm based on alpha beta
float exploreTree(Node *node, int depth)
{
    exploreSubTreeCount = 0;

    // the frontier / current list of nodes that need to be explored / nodes at the current level
    // TODO: many of these lists are probably redundant - get rid of some later
    Node *currentPVNode   = NULL;       Node *nextPVNode   = NULL;
    Node *currentCutNodes = NULL;       Node *nextCutNodes = NULL;
    Node *currentAllNodes = NULL;       Node *nextAllNodes = NULL;
    int nCutNodes = 0, nAllNodes = 0;
    int nNextCutNodes = 0, nNextAllNodes = 0;

    // full frontier
    Node **fullCurrentFrontier = NULL;
    Node **fullNextFrontier    = NULL;
    int nCurr, nNext;

    // 1. PV based initial tree generation
    node->nodeType = PV_NODE;   // the root is always a PV node
    currentPVNode = node;
    fullCurrentFrontier = &node;
    nCurr = 1;

    bool isMaxLevel = true;
    for (int i = 0; i < depth - 1; i++)
    {
        // explore the frontier nodes

        // figure out total no. of childs that need to be explored for all frontier nodes
        nNext = 0;
        for (int j=0; j<nCurr; j++)
        {
            int childsToExplore = 0;
            switch (fullCurrentFrontier[j]->nodeType)
            {
                case PV_NODE:
                case ALL_NODE:
                    childsToExplore = fullCurrentFrontier[j]->nChildren;
                    break;
                case CUT_NODE:
                    childsToExplore = 1;
                    break;
            }

            nNext += childsToExplore;
        }
        
        // allocate memory for the next frontier
        fullNextFrontier = (Node**) malloc (nNext * sizeof(Node *));
        
        int index = 0;
        // fill in the next frontier
        for (int j=0; j<nCurr; j++)
        {
            switch (fullCurrentFrontier[j]->nodeType)
            {
                case PV_NODE:
                    for (int k = 0; k < fullCurrentFrontier[j]->nChildren; k++)
                    {
                        Node *curNode = &(fullCurrentFrontier[j]->children[k]);
                        if (index == 0) // first child of PV node is PV node
                            curNode->nodeType = PV_NODE;
                        else            // others are CUT nodes
                            curNode->nodeType = CUT_NODE;
                        fullNextFrontier[index++] = curNode;
                    }
                    fullCurrentFrontier[j]->nChildsExplored = fullCurrentFrontier[j]->nChildren;

                    break;
                case ALL_NODE:
                    for (int k = 0; k < fullCurrentFrontier[j]->nChildren; k++)
                    {
                        Node *curNode = &(fullCurrentFrontier[j]->children[k]);
                        curNode->nodeType = CUT_NODE;   // child of ALL node is cut node
                        fullNextFrontier[index++] = curNode;
                    }
                    fullCurrentFrontier[j]->nChildsExplored = fullCurrentFrontier[j]->nChildren;
                    break;
                case CUT_NODE:
                    {
                        fullCurrentFrontier[j]->nChildsExplored = 1;
                        fullCurrentFrontier[j]->children[0].nodeType = ALL_NODE;
                        fullNextFrontier[index++] = &(fullCurrentFrontier[j]->children[0]);
                    }
            }

            // Ankan - not known yet, but initialize with first child
            fullCurrentFrontier[j]->best = &(fullCurrentFrontier[j]->children[0]);
            fullCurrentFrontier[j]->bestChild = 0;
        }

        assert(index == nNext);

        // go to next depth, set current = next
        if (i!=0)
            free (fullCurrentFrontier);

        nCurr = nNext;
        fullCurrentFrontier = fullNextFrontier;

        isMaxLevel = !isMaxLevel;
    }
    

    // when generating the last level evaluate all ALL nodes at the level just above the CUT node leaves
    // for depth 5 search, we need to do a MAX reduction (see modern gpu's segmented reduction example when implementing parallel version)

    fullNextFrontier = (Node**) malloc (nCurr * sizeof(Node *));
    bool *expectedMore = (bool*) malloc (nCurr * sizeof(bool));
    float *currentNodeVals = (float *) malloc(nCurr * sizeof(float));

    for (int i=0;i<nCurr;i++)
    {
        Node *curNode = fullCurrentFrontier[i];
        curNode->nodeVal = isMaxLevel ? -INF : INF;
        if(curNode->nodeType == PV_NODE || curNode->nodeType == ALL_NODE)
        {
            for (int k = 0; k < curNode->nChildren; k++)
            {
                if (isMaxLevel)
                {
                    if (curNode->children[k].nodeVal > curNode->nodeVal)
                    {
                        curNode->nodeVal = curNode->children[k].nodeVal;
                        curNode->best = &curNode->children[k];
                        curNode->bestChild = k;
                    }
                }
                else
                {
                    if (curNode->children[k].nodeVal < curNode->nodeVal)
                    {
                        curNode->nodeVal = curNode->children[k].nodeVal;
                        curNode->best = &curNode->children[k];
                        curNode->bestChild = k;
                    }
                }
            }
            fullNextFrontier[i] = curNode;
            currentNodeVals[i] = curNode->nodeVal;
            curNode->nChildsExplored = curNode->nChildren;
            expectedMore[i] = isMaxLevel ? false : true;
        }
        else
        {
            curNode->best = &curNode->children[0];
            curNode->bestChild = 0;

            curNode->nChildsExplored = 1;
            curNode->children[0].nodeType = ALL_NODE;
            fullNextFrontier[i] = &curNode->children[0];
            currentNodeVals[i] = fullNextFrontier[i]->nodeVal;
            expectedMore[i] = isMaxLevel ? true : false;
        }

        fullNextFrontier[i]->numChildrenAtFrontier = 1;
        fullNextFrontier[i]->frontierOffset = i;
    }

    free (fullCurrentFrontier);
    fullCurrentFrontier = fullNextFrontier;


    float *minScan = (float *) malloc (sizeof(float) * nCurr);
    float *maxScan = (float *) malloc (sizeof(float) * nCurr);
    bool *ignored = (bool *)malloc(sizeof(bool) * nCurr);
    memset(ignored, 0, sizeof(bool) * nCurr);

    float curMin, curMax;
    curMin = curMax = currentNodeVals[0];  // init. with value of PV node

    int nRejected = 0;
    int nExpnded = 0;

    // propogate frontier offsets from leafs up the tree
    int count;
    int start = propogateFrontierOffsets(node, &count);
    assert(start == 0 && count == nCurr);

    int iterations = 0;

    do
    {
        iterations++;

        nRejected = 0;
        nExpnded = 0;

        // ignore all nodes to the left of bestNow
        for (int i = 0; i < nCurr; i++)
        {
            ignored[i] = true;

            // Unnecessary and expensive. TODO: figure out better way
            bool found = false;
            Node *bestNow = node;
            while (bestNow->children)
            {
                bestNow = bestNow->best;
                if (bestNow == fullCurrentFrontier[i])
                {
                    found = true;
                }
            }

            if (found)
            {
                curMin = curMax = bestNow->nodeVal;
                break;
            }
        }

        for (int i = 1; i < nCurr; i++)
        {
            // all nodes that are explored here must be ALL nodes
            assert(fullCurrentFrontier[i]->nodeType = ALL_NODE ||
                   fullCurrentFrontier[i]->nChildsExplored == fullCurrentFrontier[i]->nChildren);

            if (ignored[i])
                continue;

            minScan[i] = curMin;
            maxScan[i] = curMax;

            // this node was expected to be less than the PV node value
            if (expectedMore[i] == false)
            {
                if (currentNodeVals[i] <= curMin)
                {
                    // reject this branch (i.e, no need to evaluate any more siblings)
                    nRejected++;
                    ignored[i] = true;
                }
                if (currentNodeVals[i] > curMax)
                {
                    curMax = currentNodeVals[i];
                    // need to evaluate more siblings of this node
                    expandNode(fullCurrentFrontier, currentNodeVals, i, curMax, NULL, ignored);
                    nExpnded++;
                }
            }
            else //if (expectedMore[i])
            {
                if (currentNodeVals[i] >= curMax)
                {
                    // reject this branch (i.e, no need to evaluate any more siblings of this node)
                    nRejected++;
                    ignored[i] = true;
                }
                if (currentNodeVals[i] < curMin)
                {
                    curMin = currentNodeVals[i];
                    // need to evaluate more siblings of this node
                    expandNode(fullCurrentFrontier, currentNodeVals, i, curMin, NULL, ignored);
                    nExpnded++;
                }
            }
        }

    } while (nExpnded);

    printf("\nFrontier Nodes: %d, main loop iterations: %d, explore subtree count: %d", nCurr, iterations, exploreSubTreeCount);
    printf("\nExplore Tree found value: %f\n", node->nodeVal);



    free (fullCurrentFrontier);
    return node->nodeVal;
}
Beispiel #10
0
// starts exploring a node as if it's a CUT node with cutVal as the value to check against
// returns either cutVal if a  better value couldn't be found,  or value of the best found node otherwise
// works only on CUT and ALL nodes, no node is marked as PV node by this function
float exploreSubTree(Node *node, float cutVal)
{
    exploreSubTreeCount++;

    // isMaxLevel is true if node's *parent* is a MAX level
    bool isMaxLevel = !node->isMaxNode;
    if (node->children == NULL)
    {
        // leaf node
        return isMaxLevel ? max(cutVal, node->nodeVal) 
                          : min(cutVal, node->nodeVal);
    }

    // full frontier
    Node **fullCurrentFrontier = NULL;
    Node **fullNextFrontier = NULL;

    // only for the last level
    float *currentNodeVals;

    int nCurr, nNext;

    // treat passed-in node as CUT node
    node->nodeType = CUT_NODE;
    fullCurrentFrontier = &node;
    nCurr = 1;

    bool currentIsMaxLevel = !isMaxLevel;
    int subDepth = 0;
    while (1)
    {
        bool secondLastLevel = false;
        secondLastLevel = (fullCurrentFrontier[0]->children[0].children == NULL);

        // explore the frontier nodes

        // figure out total no. of childs that need to be explored for all frontier nodes
        nNext = 0;
        for (int j=0; j<nCurr; j++)
        {
            switch (fullCurrentFrontier[j]->nodeType)
            {
                case ALL_NODE:
                    // if it's the second last level, we will explore all ALL nodes and find the best immediately
                    nNext += secondLastLevel ? 1 : fullCurrentFrontier[j]->nChildren;
                    break;
                case CUT_NODE:
                    nNext++;
                    break;
            }
        }
        
        // no more child nodes, we are at leaves..
        if (nNext == 0)
            break;

        // allocate memory for the next frontier
        fullNextFrontier = (Node**) malloc (nNext * sizeof(Node *));

        if (secondLastLevel) {
            assert(nCurr == nNext);
            currentNodeVals = (float *)malloc(nNext * sizeof(float));
        }
        
        int index = 0;
        // fill in the next frontier
        for (int j=0; j<nCurr; j++)
        {
            switch (fullCurrentFrontier[j]->nodeType)
            {
                case ALL_NODE:
                    if (secondLastLevel)
                    {
                        Node * curNode = fullCurrentFrontier[j];
                        curNode->nodeVal = curNode->isMaxNode ? -INF : INF;
                        for (int k = 0; k < curNode->nChildren; k++)
                        {
                            if (curNode->isMaxNode)
                            {
                                if (curNode->children[k].nodeVal > curNode->nodeVal)
                                {
                                    curNode->nodeVal = curNode->children[k].nodeVal;
                                    curNode->best = &curNode->children[k];
                                    curNode->bestChild = k;
                                }
                            }
                            else
                            {
                                if (curNode->children[k].nodeVal < curNode->nodeVal)
                                {
                                    curNode->nodeVal = curNode->children[k].nodeVal;
                                    curNode->best = &curNode->children[k];
                                    curNode->bestChild = k;
                                }
                            }
                        }
                        if (secondLastLevel)
                            currentNodeVals[index] = curNode->nodeVal;
                        fullNextFrontier[index++] = curNode;
                        curNode->nChildsExplored = curNode->nChildren;
                    }
                    else
                    {
                        for (int k = 0; k < fullCurrentFrontier[j]->nChildren; k++)
                        {
                            Node *curNode = &(fullCurrentFrontier[j]->children[k]);
                            curNode->nodeType = CUT_NODE;   // child of ALL node is cut node
                            fullNextFrontier[index++] = curNode;
                        }
                        fullCurrentFrontier[j]->nChildsExplored = fullCurrentFrontier[j]->nChildren;
                        fullCurrentFrontier[j]->best = &(fullCurrentFrontier[j]->children[0]);
                    }
                    break;
                case CUT_NODE:
                    {
                        fullCurrentFrontier[j]->nChildsExplored = 1;
                        fullCurrentFrontier[j]->best = &(fullCurrentFrontier[j]->children[0]);
                        fullCurrentFrontier[j]->children[0].nodeType = ALL_NODE;
                        fullNextFrontier[index] = &(fullCurrentFrontier[j]->children[0]);
                        if (secondLastLevel)
                        {
                            currentNodeVals[index] = fullNextFrontier[index]->nodeVal;
                            fullCurrentFrontier[j]->nodeVal = currentNodeVals[index];
                        }
                        index++;
                    }
            }

            if (secondLastLevel)
            {
                fullNextFrontier[j]->numChildrenAtFrontier = 1;
                fullNextFrontier[j]->frontierOffset = j;
            }
        }

        // go to next depth, set current = next
        if (subDepth != 0)
            free (fullCurrentFrontier);

        nCurr = nNext;
        fullCurrentFrontier = fullNextFrontier;

        subDepth++;

        currentIsMaxLevel = !currentIsMaxLevel;

        if (secondLastLevel)
            break;
    }

    int count;
    int start = propogateFrontierOffsets(node, &count);
    assert(start == 0 && count == nCurr);
    
    float *minScan = (float *)malloc(sizeof(float) * nCurr);
    float *maxScan = (float *)malloc(sizeof(float) * nCurr);
    bool *ignored = (bool *)malloc(sizeof(bool) * nCurr);
    memset(ignored, 0, sizeof(bool) * nCurr);

    float curMin, curMax;
    curMin = curMax = cutVal;  // init. with cut val

    float computedVal = isMaxLevel ? -INF : INF;

    int nRejected;
    int nExpnded;

    do
    {
        nRejected = 0;
        nExpnded = 0;

        curMin = curMax = cutVal;

        for (int i = 0; i < nCurr; i++)
        {
            // all nodes that are explored here must be ALL nodes
            assert(fullCurrentFrontier[i]->nodeType = ALL_NODE ||
                fullCurrentFrontier[i]->nChildsExplored == fullCurrentFrontier[i]->nChildren);

            if (ignored[i])
                continue;

            minScan[i] = curMin;
            maxScan[i] = curMax;

            // this node was expected to be less than the PV node value
            if (isMaxLevel)
            {
                if (currentNodeVals[i] <= curMin)
                {
                    // reject this branch (i.e, no need to evaluate any more siblings)
                    nRejected++;
                    ignored[i] = true;
                }
                if (currentNodeVals[i] > curMax)
                {
                    curMax = currentNodeVals[i];
                    // need to evaluate more siblings of this node
                    if (expandNode(fullCurrentFrontier, currentNodeVals, i, curMax, node, ignored))
                        nExpnded++;
                    computedVal = currentNodeVals[i];
                }
            }
            else //if (!isMaxLevel)
            {
                if (currentNodeVals[i] >= curMax)
                {
                    // reject this branch (i.e, no need to evaluate any more siblings of this node)
                    nRejected++;
                    ignored[i] = true;
                }
                if (currentNodeVals[i] < curMin)
                {
                    curMin = currentNodeVals[i];
                    // need to evaluate more siblings of this node
                    if(expandNode(fullCurrentFrontier, currentNodeVals, i, curMin, node, ignored))
                        nExpnded++;
                    computedVal = currentNodeVals[i];
                }
            }
        }

        // the loop is done when nothing gets expanded anymore
    } while (nExpnded);

    return isMaxLevel ? max(cutVal, computedVal)
                      : min(cutVal, computedVal);
}