public override void Think() { // TODO: algorithm is not optimal because when returning from child to parent, child nodes will be listed again (not so big problem, but it something to improve) // timing double currentTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; double mspa = 1000 / aiSpeed; if (!IgnoreSpeed) { if ((currentTime - lastActionTime) < mspa) { return; } } Map.Map map = Position.ParentMap; // if the stack is empty AI may be in dead end // put its current position to the stack and run the DFS again if (blockStack.Count == 0) { blockStack.Push(new VisitedBlock(Position)); } // get current node and his neighbours VisitedBlock currVisitedBlock = blockStack.Peek(); currVisitedBlock.state = BlockState.OPEN; visitedBlocks.Add(currVisitedBlock); MapBlock curr = map.Grid[currVisitedBlock.x, currVisitedBlock.y]; List <MapBlock> neighbours = curr.AccessibleNeighbours(); // choose the next neighbour to go to // those neighbours must not be in CLOSED state and should not contain monster MapBlock nextBlock = null; foreach (MapBlock neighbour in neighbours) { // check if the neighbour wasn't already visited and is not occupied // visited block hash code is calculated only by its coordinates so this can be used VisitedBlock neighbourVb = new VisitedBlock(neighbour); if (!visitedBlocks.Contains(neighbourVb) && !neighbour.Occupied) { // get the last not-visited, unoccupied neighbour // add it to the stack later nextBlock = neighbour; } } // if some neighbours were found, create move action to the last block on the stack if (nextBlock != null) { blockStack.Push(new VisitedBlock(nextBlock)); Direction nextDirection = DirectionMethods.GetDirection(Position, nextBlock); NextAction = new Move() { Actor = this, Direction = nextDirection }; } else { // no possible neighbours were found // this opens up two possibilities // 1. assume current block is a dead end // 2. check if there are monster to fight in neighbour blocks and try to fight them // for now lets just pick the first one // mark current block as closed and pop it from the stack currVisitedBlock.state = BlockState.CLOSED; blockStack.Pop(); // move one step back if (blockStack.Count > 0) { VisitedBlock prevBlock = blockStack.Peek(); nextBlock = map.Grid[prevBlock.x, prevBlock.y]; NextAction = new Move() { Actor = this, Direction = DirectionMethods.GetDirection(Position, nextBlock) }; } } lastActionTime = currentTime; }