2

I am trying to solve 8 puzzle problem in python given here in this assignment -https://www.cs.princeton.edu/courses/archive/fall12/cos226/assignments/8puzzle.html

My goal state is a little different from what is mentioned in the assignment -

#GOAL STATE
goal_state =  [[0,1,2],[3,4,5],[6,7,8]]

The buggy part, it seems, is the isSolvable function. It is implemented correctly but while testing the board, it considers the goal state to be the one in which relative order is maintained and blank can be anywhere. So it might be the case that a board is solvable but it might not lead to the current defined goal state. So I am unable to think of a method in which I can test for all the possible goal states while running the solver function *

Also, my solver function was wrongly implemented. I was only considering the neighbor which had the minimum manhattan value and when I was hitting a dead end, I was not considering other states. This can be done by using a priority queue. I am not exactly sure as to how to proceed to implement it. I have written a part of it(see below) which is also kind of wrong as I not pushing the parent into the heap. Kindly provide me guidance for that.

Here is my complete code - https://pastebin.com/q7sAKS6a

Updated code with incomplete solver function - https://pastebin.com/n4CcQaks

I have used manhattan values to calculate heuristic values and hamming value to break the tie.

my isSolvable function, manhattan function and solver function:

isSolvable function -

#Conditions for unsolvability -->
#https://www.geeksforgeeks.org/check-instance-8-puzzle-solvable/
    def isSolvable(self):
        self.one_d_array = []

        for i in range(0,len(self.board)):
            for j in range(0,len(self.board)):
                self.one_d_array.append(self.board[i][j])

        inv_count = 0
        for i in range(0,len(self.one_d_array)-1):
            for j in range(i+1, len(self.one_d_array)):
                if (self.one_d_array[i] != 0 and self.one_d_array[j] != 0 and self.one_d_array[i] > self.one_d_array[j]):
                    inv_count = inv_count + 1

        if(inv_count % 2 == 0):
            print("board is solvable")
            return True
        else:
            print("board is not solvable")
            return False

Manhattan function

    def manhattan_value(self,data=None):
        manhattan_distance = 0
        for i in range(0,len(data)):
            for j in range(0,len(data)):
                if(data[i][j] != self.goal_state[i][j] and data[i][j] != 0):
                    #correct position of the element
                    x_goal , y_goal = divmod(data[i][j],3)
                    manhattan_distance = manhattan_distance + abs(i-x_goal) + abs(j-y_goal)

        return manhattan_distance

Updated Solver function

    #implement A* algorithm
    def solver(self):
        moves = 0
        heuristic_value = []
        prev_state = []
        curr_state = self.board
        output = []
        heap_array = []
        store_manhattan_values = []


        if(curr_state == self.goal_state):
            print("goal state reached!")
            print(curr_state)
            print("number of moves required to reach goal state --> {}".format(moves))

        else:
            while(True):
                min_heuristic_value = 99999999999
                min_pos = None
                moves = moves + 1
                output = self.get_neighbours(curr_state)

                for i in range(len(output)):
                    store_manhattan_values.append([self.manhattan_value(output[i]),i])

                #print(store_manhattan_values)
                for i in range(len(store_manhattan_values)):
                    heapq.heappush(heap_array,store_manhattan_values[i])

                #print(heap_array)
                #print(heapq.heappop(heap_array)[1])


                #if(moves > 1):
                #    return
            return

Please refer to the PASTEBIN link for complete code and all the references (https://pastebin.com/r7TngdFc).

Updated code with incomplete solver function - https://pastebin.com/n4CcQaks

In the given link for my code (based on my tests and debugging so far) - These functions are working correctly - manhatten_value, hamming_value, append_in_list, get_neighbours

What does these functions do -

isSolvable - tells if the board can be solved or not

manhattan_value - calculates the manhattan value of the board passed to it.

hamming_value - calculates the hamming value of the board passed to it.

append_in_list - helper function for getting neighbours. It swaps values then save the resultant state in an array and then reswaps them to return to original position for further swapping and getting other possible states.

get_neighbours - gets all the possible neighbors which can be formed by swapping places with blank element(0 element).

solver - implements the A* algorithm

I am unable to find my mistake. Kindly guide me in this problem. Thank you in advance for your help!

I am apologizing in advance as I am unable to produce a minimal version of my code for this problem. I can not think of any way to use all the functions and produce a minimal version of the code.

HARSHIT BAJPAI
  • 361
  • 2
  • 17
  • Thanks for the proper forum. I need to wait for 40 minutes though before I post another question. I will do it once the time limit is over. – HARSHIT BAJPAI Sep 14 '19 at 16:50
  • 1
    @SpghttCd Actually, CR is for working code only. This code doesn't work. Please see [on topic](https://codereview.stackexchange.com/help/on-topic) before making migration recommendations. – ggorlen Sep 14 '19 at 17:15
  • @HARSHITBAJPAI This question as it stands appears to be "here is 250 lines of code that don't work--why?" which is [off-topic](https://stackoverflow.com/help/on-topic). Please post a [mcve] and break the problem down to isolate the issue. At the very least, clearly describe which component isn't working and how the code operates. What parts definitely work? What does each module do? What is the input/output you're feeding it exactly and what did you expect? – ggorlen Sep 14 '19 at 17:20
  • 1
    @ggorlen sorry, my misconception, thanks for pointing that out. I always thought review would include finding e.g. hard to track errors. -> recommendation deleted – SpghttCd Sep 14 '19 at 17:38
  • 1
    @SpghttCd No problem! CR does include hard to track errors, but they have to be unknown to the author at post time. – ggorlen Sep 14 '19 at 17:42
  • @ggorlen Thank you for your suggestions. I have added the information about functions that are working(according to me). I am really sorry but I am unable to think of a way to produce a minimal version of the code above. – HARSHIT BAJPAI Sep 14 '19 at 17:49
  • @ggorlen Kindly let me know if there is further explaining required on my part that could be helpful to other readers. – HARSHIT BAJPAI Sep 14 '19 at 17:58
  • This is a helpful update, thanks. – ggorlen Sep 14 '19 at 17:59
  • I have updated the question with a little more understanding of what exactly is the problem. Please let me know if you have any suggestions now @גלעדברקן – HARSHIT BAJPAI Sep 15 '19 at 07:07

1 Answers1

0

(Note, this answer is different than the earlier revision about which many of the comments below were relating to.)

I don't see how the current code implements a queue. It seems like the while loop in the solver picks one new board state each time from a list of possible moves, then considers the next list generated by this new board state.

On the other hand, a priority queue, from what I understand, would have all the (valid) neighbours from the current board state inserted into it and prioritised such that the next chosen board state to be removed from the queue and examined will be the one with highest priority.

(To be completely sure in debugging, I might add a memoisation to detect if the code ends up also revisiting board states -- ah, on second thought, I believe the stipulation in the assignment description that the number of current moves be added to the priority assignment would rule out the same board state being revisited if the priority queue is correctly observed, so memoisation may not be needed.)

גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • Why did you stop after 5 moves? Did you reach the goal state? Consider this board - [[3,1,2],[0,4,5],[6,7,8]] Let me know in many moves does this reach the goal state? Thank you for your help on this – HARSHIT BAJPAI Sep 14 '19 at 18:08
  • If you see the 3rd last and 2nd last line of the code, I was trying to do what you suggested by capping the number of iterations. I could not get to the mistake though. – HARSHIT BAJPAI Sep 14 '19 at 18:10
  • The way I have written the code is that I pass a board and then code itself finds the required moves to get to the goal state. So I don't really have to give moves to the solution. This board - [[3,1,2],[0,4,5],[6,7,8]] is solvable. Yet the code is stuck on an infinite while loop when I pass this. Uncomment line 210 and you will see how code behaves then. – HARSHIT BAJPAI Sep 14 '19 at 18:16
  • I am sorry. Try for this one - [[1,2,3],[4,5,6],[0,7,8]] – HARSHIT BAJPAI Sep 14 '19 at 18:18
  • [[1,2,3],[4,5,6],[0,7,8]] ===> [[1,2,3],[4,5,6],[7,0,8]] ====> [[1,2,3],[4,5,6],[7,8,0]] – HARSHIT BAJPAI Sep 14 '19 at 18:21
  • There might be a board which could require 10-12 moves or even more and I might not be able to manually calculate the sequence. But the isSolvable function tests the condition and returns true if the board is solvable. – HARSHIT BAJPAI Sep 14 '19 at 18:22
  • [[1,2,3],[4,5,6],[0,7,8]] - this is the initial stage which I will give to the code. Code will then tell how many minimum moves are required to reach the goal state. In this case, it should report to two moves needed. – HARSHIT BAJPAI Sep 14 '19 at 18:24
  • Holy shit! You are right! When I was debugging, I was assuming the goal state to be wrong. I just checked for the board - [[3,1,2],[6,4,5],[7,8,0]] . It requires 4 moves and it works fine. I am looking into isSolvable right now. Let me know if you see any obvious mistake in that function – HARSHIT BAJPAI Sep 14 '19 at 18:32
  • That would be incorrect as per specification in the assignment. Also, then the rest of the ordering would become relative to other elements and not an absolute order. – HARSHIT BAJPAI Sep 14 '19 at 19:12
  • I have updated the solver function and question info a little bit. Can you please provide your thoughts for would I code this. I have implemented a little bit but that too is wrong, I think. Let me know how will I proceed for this case? – HARSHIT BAJPAI Sep 15 '19 at 14:56
  • @HARSHITBAJPAI I would Google "priority queue python tutorial," I'm sure there are many examples. In your case, if you have a library for the queue, the idea is simple - either insert into it or get the next item from it. The assignment already tells you what the priority is, and you can use tuples with the first being the priority and the second whatever data is needed to process the item. – גלעד ברקן Sep 15 '19 at 16:32
  • @HARSHITBAJPAI also, rather than `while (True)`, you might have, `while (queue is not empty)`. – גלעד ברקן Sep 15 '19 at 18:00