2

I am using an A* search and a Breadth First search to find a winning game state in an 8 puzzle. The winning state looks like this

123
456
780

and stored as a list like such

[1,2,3,4,5,6,7,8,9,0]

I used a heuristic function to score each node (based on its state), but I believe my method of prioritizing the best scored nodes is slowing my program down a lot. So much so actually that the breadth first search algorithm I made vastly outperforms the A* algorithm (even though most of the the inner workings are identical).

I believe the main thing slowing my A* search down is that I'm using the position in the fringe (the list holding my nodes) to indicate the next node to prioritize.

def aStartSort(node):
    if not fringe:
        fringe.append(node)
    else:
        fl = len(fringe)
        if node.score >= fringe[fl-1].score:
            fringe.append(node)
        else:
            for i in range(fl):
                if node.score < fringe[i].score:
                    fringe.insert(i, node)

So as you can see, every time a node is added to the fringe, it looks for a node that is scored worse than it, and then inserts itself in front of it. This ensures that I get a least a tie for the best scored node when I do fringe.pop(0). But inserting items into the middle of a giant list isn't a very fast action is it? What would be a better alternative?

I also considered not ordering the fringe list, but that seems just as bad or worse (because the entire list would have to be searched each time a node is popped out.

martineau
  • 119,623
  • 25
  • 170
  • 301
user3225440
  • 231
  • 5
  • 14
  • Maybe one way to do it would be to look at the 'path' to the solution your BFS finds, and then look at where your A* is deviating from that 'known best' path. – Tom Dalton Feb 25 '16 at 00:34
  • @TomDalton Well the I don't have a choice on the heuristic I'm using to score the nodes, so I don't really get to change the path of the A*. The heuristic is the amount of tiles that are misplaced (so a max of 8) and the cost is 1 per move. So the full score is decided by f(n) = misplaced tiles + depth. Other than that, the algorithms are pretty much identical. So all I'm left with is looking for a faster way of sorting through the nodes I do pick. – user3225440 Feb 25 '16 at 00:47
  • If the scores are ranging 0-8, then you could keep a `dict` of score:nodes, which would save you doing the scan through the big list looking for the insert point - you just add the new node to the end of the list in the relevant dict key. – Tom Dalton Feb 25 '16 at 12:12

1 Answers1

1

To answer your specific question, assuming your scores are integers, create a dictionary of lists, mapping scores to nodes with that score. That makes inserts O(1), and since you can iterate over the possible score range, retrieval should be fast as well.

aghast
  • 14,785
  • 3
  • 24
  • 56