Ejemplo n.º 1
0
    def start(self):
        # initialize the init state and goal state as 2d array
        #init_tile = np.array([[2, 3, 6], [1, 4, 8], [7, 5, 0]])
        init_tile = np.array([[1, 2, 3], [0, 4, 6], [7, 5, 8]])

        init = State(init_tile, 0, 0)

        goal_tile = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])

        goal = State(goal_tile, 0, 0)

        self.tiles = 8

        UIS_solver = UninformedSearchSolver(init, goal)
        UIS_solver.run()

        IS_solver = InformedSearchSolver(init, goal)
        IS_solver.run()
Ejemplo n.º 2
0
    def start(self):
        # initialize the init state and goal state as 2d array
        #init_tile = np.array([[2, 3, 6], [1, 4, 8], [7, 5, 0]])
        init_tile = np.array([[1, 2, 3], [0, 4, 6], [7, 5, 8]])

        # initial state given in prompt for testing
        #init_tile = np.array([[2, 3, 1], [0, 4, 6], [7, 5, 8]])

        init = State(init_tile, 0, 0)

        goal_tile = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])

        goal = State(goal_tile, 0, 0)

        self.tiles = 8

        print("\nBegin uninformed (Breadth-First) search:")
        UIS_solver = UninformedSearchSolver(init, goal)
        # Time the amount of time it takes to complete computation
        uStartTime = time.time()
        UIS_solver.run()
        uEndTime = time.time()
        uCompTime = uEndTime - uStartTime

        # Print time it took to compute
        print("\n")
        print("Took " + uCompTime.__str__() + " seconds to complete.")

        print("\n")
        print("************************************************************")

        print("\nBegin Informed (Best-First) search:")
        IS_solver = InformedSearchSolver(init, goal)
        # Time computational time
        iStartTime = time.time()
        IS_solver.run()
        iEndTime = time.time()
        iCompTime = iEndTime - iStartTime

        # Print time it took to compute
        print("\n")
        print("Took " + iCompTime.__str__() + " seconds to complete.")
Ejemplo n.º 3
0
class UninformedSearchSolver:
    current = State()
    goal = State()
    openlist = []
    closed = []
    depth = 0

    def __init__(self, current, goal):
        self.current = current
        self.goal = goal
        self.openlist.append(current)

    def check_inclusive(self, s):
        isinopen = 0
        isinclosed = 0

        # Var will hold whether state is in open or closed list in position 0 and its index in pos 1
        returnValue = [-1, -1]

        # If s is in the open list
        for i in self.openlist:
            if i.equals(s):
                isinopen = 1
                returnValue[1] = self.openlist.index(i)
                break

        # If s is in the closed list
        for i in self.closed:
            if i.equals(s):
                isinclosed = 1
                returnValue[1] = self.closed.index(i)
                break

        # If child is not in either list
        if isinopen == 0 and isinclosed == 0:
            returnValue[0] = 1
        # If child is already in the open list
        elif isinopen == 1 and isinclosed == 0:
            returnValue[0] = 2
        # If child is already in the closed list
        elif isinopen == 1 and isinclosed == 1:
            returnValue[0] = 3
        return returnValue

    """
     * four types of walks
     * best first search
     *  ↑ ↓ ← → (move up, move down, move left, move right)
     * the blank tile is represent by '0'
    """

    def state_walk(self):
        if len(self.openlist) > 0:
            self.current = self.openlist.pop(
                0)  # Remove leftmost state from open

            # Get location where blank tile is
            walk_state = self.current.tile_seq
            row = 0
            col = 0

            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    if walk_state[i][j] == 0:
                        row = i
                        col = j
                        break

            # Generate children of current
            # Empty lists to hold children when moves are legal
            tempUp = [[None for j in range(len(walk_state))]
                      for i in range(len(walk_state))]
            tempDown = [[None for j in range(len(walk_state))]
                        for i in range(len(walk_state))]
            tempLeft = [[None for j in range(len(walk_state))]
                        for i in range(len(walk_state))]
            tempRight = [[None for j in range(len(walk_state))]
                         for i in range(len(walk_state))]

            # Move up blank space
            if (row - 1) >= 0:
                for i in range(len(walk_state)):
                    for j in range(len(self.current.tile_seq[i])):
                        tempUp[i][j] = self.current.tile_seq[i][j]

                tiletoswitch = tempUp[row - 1][
                    col]  # The value where the blank tile is in the current state
                tempUp[row - 1][col] = self.current.tile_seq[row][
                    col]  # Moving the blank tile up by placing 0 in row-1
                tempUp[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempUp, self.current.depth +
                          1)  # Creating new state from new configuration
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move down blank space
            if (row + 1) < len(walk_state):
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempDown[i][j] = walk_state[i][j]

                tiletoswitch = tempDown[row + 1][
                    col]  # The value where the blank tile is in the current state
                tempDown[row + 1][col] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempDown[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempDown, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move left blank space
            if (col - 1) >= 0:
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempLeft[i][j] = walk_state[i][j]

                tiletoswitch = tempLeft[row][
                    col -
                    1]  # The value where the blank tile is in the current state
                tempLeft[row][col - 1] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempLeft[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempLeft, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move right blank space
            if (col + 1) < len(walk_state):
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempRight[i][j] = walk_state[i][j]

                tiletoswitch = tempRight[row][
                    col +
                    1]  # The value where the blank tile is in the current state
                tempRight[row][col + 1] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempRight[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempRight, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # add current to closed state list
            self.closed.append(self.current)

    # Check the following to make it work properly
    def run(self):
        # output the start state
        print("\nstart state: \n")
        print(self.current.tile_seq)
        print("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")

        path = 0

        while not self.current.equals(self.goal):
            self.state_walk()
            print(np.array(self.current.tile_seq))
            path += 1

        print("\nIt took ", path, " iterations")
        print("The length of the path is: ", self.current.depth)
        # output the goal state
        target = self.goal.tile_seq
        print("\ngoal state:\n")
        print(target)
Ejemplo n.º 4
0
    def state_walk(self):
        if len(self.openlist) > 0:
            self.current = self.openlist.pop(
                0)  # Remove leftmost state from open

            # Get location where blank tile is
            walk_state = self.current.tile_seq
            row = 0
            col = 0

            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    if walk_state[i][j] == 0:
                        row = i
                        col = j
                        break

            # Generate children of current
            # Empty lists to hold children when moves are legal
            tempUp = [[None for j in range(len(walk_state))]
                      for i in range(len(walk_state))]
            tempDown = [[None for j in range(len(walk_state))]
                        for i in range(len(walk_state))]
            tempLeft = [[None for j in range(len(walk_state))]
                        for i in range(len(walk_state))]
            tempRight = [[None for j in range(len(walk_state))]
                         for i in range(len(walk_state))]

            # Move up blank space
            if (row - 1) >= 0:
                for i in range(len(walk_state)):
                    for j in range(len(self.current.tile_seq[i])):
                        tempUp[i][j] = self.current.tile_seq[i][j]

                tiletoswitch = tempUp[row - 1][
                    col]  # The value where the blank tile is in the current state
                tempUp[row - 1][col] = self.current.tile_seq[row][
                    col]  # Moving the blank tile up by placing 0 in row-1
                tempUp[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempUp, self.current.depth +
                          1)  # Creating new state from new configuration
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move down blank space
            if (row + 1) < len(walk_state):
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempDown[i][j] = walk_state[i][j]

                tiletoswitch = tempDown[row + 1][
                    col]  # The value where the blank tile is in the current state
                tempDown[row + 1][col] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempDown[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempDown, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move left blank space
            if (col - 1) >= 0:
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempLeft[i][j] = walk_state[i][j]

                tiletoswitch = tempLeft[row][
                    col -
                    1]  # The value where the blank tile is in the current state
                tempLeft[row][col - 1] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempLeft[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempLeft, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # Move right blank space
            if (col + 1) < len(walk_state):
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        tempRight[i][j] = walk_state[i][j]

                tiletoswitch = tempRight[row][
                    col +
                    1]  # The value where the blank tile is in the current state
                tempRight[row][col + 1] = self.current.tile_seq[row][
                    col]  # Moving blank tile up by placing 0 in row-1
                tempRight[row][
                    col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
                s = State(tempRight, self.current.depth + 1)
                check = self.check_inclusive(s)

                # If child is neither on open or closed list, append it to the open list
                if check[0] == 1:
                    self.openlist.append(s)

            # add current to closed state list
            self.closed.append(self.current)
Ejemplo n.º 5
0
    def state_walk(self):
        self.closed.append(self.current)
        self.openlist.remove(self.current)

        walk_state = self.current.tile_seq
        row = 0
        col = 0

        # Get location where the blank tile is
        for i in range(len(walk_state)):
            for j in range(len(walk_state[i])):
                if walk_state[i][j] == 0:
                    row = i
                    col = j
                    break

        self.depth += 1
        """ add closed state
            if len(self.openlist) > 0:
                self.current = self.openlist.pop(0)  # Remove leftmost state from open
    
                # move to the next heuristic state
                walk_state = self.current.tile_seq
                row = 0
                col = 0
    
                # Get location where the blank tile is
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        if walk_state[i][j] == 0:
                            row = i
                            col = j
                            break
            """
        # Generate children of current based on legal moves
        tempUp = [[None for j in range(len(walk_state))]
                  for i in range(len(walk_state))]
        tempDown = [[None for j in range(len(walk_state))]
                    for i in range(len(walk_state))]
        tempLeft = [[None for j in range(len(walk_state))]
                    for i in range(len(walk_state))]
        tempRight = [[None for j in range(len(walk_state))]
                     for i in range(len(walk_state))]
        ''' The following program is used to do the state space walk '''
        # ↑ move up
        if (row - 1) >= 0:
            for i in range(len(walk_state)):
                for j in range(len(self.current.tile_seq[i])):
                    tempUp[i][j] = self.current.tile_seq[i][j]

            tiletoswitch = tempUp[row - 1][
                col]  # The value where the blank tile is in the current state
            tempUp[row - 1][col] = self.current.tile_seq[row][
                col]  # Moving the blank tile up by placing 0 in row-1
            tempUp[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempUp, self.current.depth +
                      1)  # Creating new state from new configuration
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                    *do the next steps according to flag (check)
                    *if flag = 2 //in the open list
                    *if the child was reached by a shorter path
                    *then give the state on open the shorter path
                    *if flag = 3 //in the closed list
                    *if the child was reached by a shorter path then
                     begin
                    *remove the state from closed;
                    *add the child to open
                    *end;
                """
            # TODO your code end here

        # ↓ move down
        if (row + 1) < len(walk_state):
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempDown[i][j] = walk_state[i][j]

            tiletoswitch = tempDown[row + 1][
                col]  # The value where the blank tile is in the current state
            tempDown[row + 1][col] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempDown[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempDown, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # ← move left
        if (col - 1) >= 0:
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempLeft[i][j] = walk_state[i][j]

            tiletoswitch = tempLeft[row][
                col -
                1]  # The value where the blank tile is in the current state
            tempLeft[row][col - 1] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempLeft[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempLeft, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # → move right
        if (col + 1) < len(walk_state):
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempRight[i][j] = walk_state[i][j]

            tiletoswitch = tempRight[row][
                col +
                1]  # The value where the blank tile is in the current state
            tempRight[row][col + 1] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempRight[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempRight, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
                # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # sort the open list first by h(n) then g(n)

        self.openlist.sort(key=self.sortFun)
        self.current = self.openlist[0]
Ejemplo n.º 6
0
class InformedSearchSolver:
    current = State()
    goal = State()
    openlist = []
    closed = []
    depth = 0

    def __init__(self, current, goal):
        self.current = current
        self.goal = goal
        self.openlist.append(current)

    def sortFun(self, e):
        return e.weight

    """
     * check if the generated state is in open or closed
     * the purpose is to avoid a circle
     * @param s
     * @return
    """

    def check_inclusive(self, s):
        in_open = 0
        in_closed = 0
        ret = [-1, -1]

        for item in self.openlist:
            if item.equals(s):
                in_open = 1
                ret[1] = self.openlist.index(item)
                break

        for item in self.closed:
            if item.equals(s):
                in_closed = 1
                ret[1] = self.closed.index(item)
                break

        if in_open == 0 and in_closed == 0:
            ret[0] = 1  # the child is not in open or closed
        elif in_open == 1 and in_closed == 0:
            ret[0] = 2  # the child is already in open
        elif in_open == 0 and in_closed == 1:
            ret[0] = 3  # the child is already in closed
        return ret

    """
     * four types of walks
     * best first search
     *  ↑ ↓ ← → (move up, move down, move left, move right)
     * the blank tile is represent by '0'
    """

    def state_walk(self):
        self.closed.append(self.current)
        self.openlist.remove(self.current)

        walk_state = self.current.tile_seq
        row = 0
        col = 0

        # Get location where the blank tile is
        for i in range(len(walk_state)):
            for j in range(len(walk_state[i])):
                if walk_state[i][j] == 0:
                    row = i
                    col = j
                    break

        self.depth += 1
        """ add closed state
            if len(self.openlist) > 0:
                self.current = self.openlist.pop(0)  # Remove leftmost state from open
    
                # move to the next heuristic state
                walk_state = self.current.tile_seq
                row = 0
                col = 0
    
                # Get location where the blank tile is
                for i in range(len(walk_state)):
                    for j in range(len(walk_state[i])):
                        if walk_state[i][j] == 0:
                            row = i
                            col = j
                            break
            """
        # Generate children of current based on legal moves
        tempUp = [[None for j in range(len(walk_state))]
                  for i in range(len(walk_state))]
        tempDown = [[None for j in range(len(walk_state))]
                    for i in range(len(walk_state))]
        tempLeft = [[None for j in range(len(walk_state))]
                    for i in range(len(walk_state))]
        tempRight = [[None for j in range(len(walk_state))]
                     for i in range(len(walk_state))]
        ''' The following program is used to do the state space walk '''
        # ↑ move up
        if (row - 1) >= 0:
            for i in range(len(walk_state)):
                for j in range(len(self.current.tile_seq[i])):
                    tempUp[i][j] = self.current.tile_seq[i][j]

            tiletoswitch = tempUp[row - 1][
                col]  # The value where the blank tile is in the current state
            tempUp[row - 1][col] = self.current.tile_seq[row][
                col]  # Moving the blank tile up by placing 0 in row-1
            tempUp[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempUp, self.current.depth +
                      1)  # Creating new state from new configuration
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                    *do the next steps according to flag (check)
                    *if flag = 2 //in the open list
                    *if the child was reached by a shorter path
                    *then give the state on open the shorter path
                    *if flag = 3 //in the closed list
                    *if the child was reached by a shorter path then
                     begin
                    *remove the state from closed;
                    *add the child to open
                    *end;
                """
            # TODO your code end here

        # ↓ move down
        if (row + 1) < len(walk_state):
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempDown[i][j] = walk_state[i][j]

            tiletoswitch = tempDown[row + 1][
                col]  # The value where the blank tile is in the current state
            tempDown[row + 1][col] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempDown[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempDown, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # ← move left
        if (col - 1) >= 0:
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempLeft[i][j] = walk_state[i][j]

            tiletoswitch = tempLeft[row][
                col -
                1]  # The value where the blank tile is in the current state
            tempLeft[row][col - 1] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempLeft[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempLeft, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
            # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # → move right
        if (col + 1) < len(walk_state):
            for i in range(len(walk_state)):
                for j in range(len(walk_state[i])):
                    tempRight[i][j] = walk_state[i][j]

            tiletoswitch = tempRight[row][
                col +
                1]  # The value where the blank tile is in the current state
            tempRight[row][col + 1] = self.current.tile_seq[row][
                col]  # Moving blank tile up by placing 0 in row-1
            tempRight[row][
                col] = tiletoswitch  # Replacing spot where the blank tile was with the value right above
            s = State(tempRight, self.current.depth + 1)
            check = self.check_inclusive(s)

            # If child not in open or closed
            if (check[0] == 1):
                # Assign child heuristic value
                self.heuristic_test(s)
                self.openlist.append(s)
                # If child in open
            elif (check[0] == 2):
                if s.depth < self.openlist[check[1]].depth:
                    self.openlist[check[1]].depth = s.depth
            # If child in closed
            elif (check[0] == 3):
                if s.depth < self.closed[check[1]].depth:
                    self.openlist.append(self.closed.pop(check[1]))
            """
                 *if flag = 2 //in the open list
                 *if the child was reached by a shorter path
                 *then give the state on open the shorter path
                 *if flag = 3 //in the closed list
                 *if the child was reached by a shorter path then
                 *begin
                 *remove the state from closed;
                 *add the child to open
                 *end;
                """
            # TODO your code end here

        # sort the open list first by h(n) then g(n)

        self.openlist.sort(key=self.sortFun)
        self.current = self.openlist[0]

    """
     * Solve the game using heuristic search strategies
     
     * There are three types of heuristic rules:
     * (1) Tiles out of place
     * (2) Sum of distances out of place
     * (3) 2 x the number of direct tile reversals
     
     * evaluation function
     * f(n) = g(n) + h(n)
     * g(n) = depth of path length to start state
     * h(n) = (1) + (2) + (3)
    """

    def heuristic_test(self, current):
        curr_seq = current.tile_seq
        goal_seq = self.goal.tile_seq

        # (1) Tiles out of place
        h1 = 0
        """
         *loop over the curr_seq
         *check the every entry in curr_seq with goal_seq
         
         If a tile is not in it's goal place, sum it to the heuristic estimate.
        """

        for i in range(len(curr_seq)):
            for j in range(len(curr_seq[i])):
                if curr_seq[i][j] != goal_seq[i][j]:
                    h1 += 1

        # (2) Sum of distances out of place
        h2 = 0
        """
         *loop over the goal_seq and curr_seq in nested way
         *locate the entry which has the same value in 
         *curr_seq and goal_seq then calculate the offset
         *through the absolute value of two differences
         *of curr_row-goal_row and curr_col-goal_col
         *absoulte value can be calculated by abs(...)
        """

        for i in range(len(curr_seq)):
            for j in range(len(curr_seq[i])):
                """
                 If a tile is out of place, iterate through the
                 goal state and find where it's supposed to be,
                 then calculate the absolute value of the difference
                 between them and add it to the heuristic score
                """
                if curr_seq[i][j] != goal_seq[i][j]:
                    for k in range(len(goal_seq)):
                        for l in range(len(goal_seq[k])):
                            if curr_seq[i][j] == goal_seq[k][l]:
                                h2 += (abs(i - k) + abs(j - l))

        # (3) 2 x the number of direct tile reversals
        h3 = 0

        for i in range(len(curr_seq)):  # Loop row
            for j in range(len(curr_seq[i])):  # loop col
                # Check boundary of row
                if (i + 1) < len(curr_seq):
                    # Check element is not 0
                    if curr_seq[i + 1][j] != 0 and curr_seq[i][j] != 0:
                        if curr_seq[i + 1][j] == goal_seq[i][j] and curr_seq[
                                i][j] == goal_seq[i + 1][j]:
                            h3 += 1

                # Check boundary of col
                if (j + 1) < len(curr_seq[i]):
                    # Check element is not 0
                    if curr_seq[i][j + 1] != 0 and curr_seq[i][j] != 0:
                        if curr_seq[i][j + 1] == goal_seq[i][j] and curr_seq[
                                i][j] == goal_seq[i][j + 1]:
                            h3 += 1

        h3 *= 2

        # set the heuristic value for current state
        current.weight = current.depth + h1 + h2 + h3

    # You can choose to print all the states on the search path, or just the start and goal state
    def run(self):
        # output the start state
        print("\nstart state: \n")
        print(self.current.tile_seq)
        print("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")

        path = 0

        while not self.current.equals(self.goal):
            self.state_walk()
            print(np.array(self.current.tile_seq))
            path += 1

        print("\nIt took ", path, " iterations")
        print("The length of the path is: ", self.current.depth)
        # output the goal state
        target = self.goal.tile_seq
        print("\ngoal state: \n")
        print(target)
Ejemplo n.º 7
0
    def state_walk(self):
        # add closed state
        self.closed.append(self.current)
        self.openlist.remove(self.current)
        # move to the next heuristic state
        walk_state = self.current.tile_seq
        row = 0
        col = 0

        for i in range(len(walk_state)):
            for j in range(len(walk_state[i])):
                if walk_state[i, j] == 0:
                    row = i
                    col = j
                    break

        self.depth += 1
        ''' The following program is used to do the state space walk '''
        # ↑ move up
        if (row - 1) >= 0:
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row-1, col)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row - 1, col]
            tempArray[row - 1, col] = tempHolder
            #print("temp up \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            #print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                #print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            #print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # ↓ move down
        if (row + 1) < len(walk_state):
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↓ is correspond to (row, col) and (row+1, col)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row + 1, col]
            tempArray[row + 1, col] = tempHolder
            #print("temp down \n", tempArray)
            """
                         *call check_inclusive(temp state)
                         *define a new temp state via temp array
                        """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # ← move left
        if (col - 1) >= 0:
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row, col-1)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row, col - 1]
            tempArray[row, col - 1] = tempHolder
            #print("temp left \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # → move right
        if (col + 1) < len(walk_state):
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row, col+1)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row, col + 1]
            tempArray[row, col + 1] = tempHolder
            #print("temp right \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # sort the open list first by h(n) then g(n)
        self.openlist.sort(key=self.sortFun)
        self.current = self.openlist[0]
Ejemplo n.º 8
0
class InformedSearchSolver:
    current = State()
    goal = State()
    openlist = []
    closed = []
    depth = 0

    def __init__(self, current, goal):
        self.current = current
        self.goal = goal
        self.openlist.append(current)

    def sortFun(self, e):
        return e.weight

    """
     * check if the generated state is in open or closed
     * the purpose is to avoid a circle
     * @param s
     * @return
    """

    def check_inclusive(self, s):
        in_open = 0
        in_closed = 0
        ret = [-1, -1]

        for item in self.openlist:
            if item.equals(s):
                in_open = 1
                ret[1] = self.openlist.index(item)
                break

        for item in self.closed:
            if item.equals(s):
                in_closed = 1
                ret[1] = self.closed.index(item)
                break

        if in_open == 0 and in_closed == 0:
            ret[0] = 1  # the child is not in open or closed
        elif in_open == 1 and in_closed == 0:
            ret[0] = 2  # the child is already in open
        elif in_open == 0 and in_closed == 1:
            ret[0] = 3  # the child is already in closed
        return ret

    """
     * four types of walks
     * best first search
     *  ↑ ↓ ← → (move up, move down, move left, move right)
     * the blank tile is represent by '0'
    """

    def state_walk(self):
        # add closed state
        self.closed.append(self.current)
        self.openlist.remove(self.current)
        # move to the next heuristic state
        walk_state = self.current.tile_seq
        row = 0
        col = 0

        for i in range(len(walk_state)):
            for j in range(len(walk_state[i])):
                if walk_state[i, j] == 0:
                    row = i
                    col = j
                    break

        self.depth += 1
        ''' The following program is used to do the state space walk '''
        # ↑ move up
        if (row - 1) >= 0:
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row-1, col)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row - 1, col]
            tempArray[row - 1, col] = tempHolder
            #print("temp up \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            #print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                #print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            #print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # ↓ move down
        if (row + 1) < len(walk_state):
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↓ is correspond to (row, col) and (row+1, col)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row + 1, col]
            tempArray[row + 1, col] = tempHolder
            #print("temp down \n", tempArray)
            """
                         *call check_inclusive(temp state)
                         *define a new temp state via temp array
                        """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # ← move left
        if (col - 1) >= 0:
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row, col-1)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row, col - 1]
            tempArray[row, col - 1] = tempHolder
            #print("temp left \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # → move right
        if (col + 1) < len(walk_state):
            # TODO your code start here
            """
            *get the 2d array of current 
            *define a temp 2d array and loop over current.tile_seq
            *pass the value from current.tile_seq to temp array 
            """
            tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
            for i in range(len(self.current.tile_seq)):
                for j in range(len(self.current.tile_seq[i])):
                    tempArray[i, j] = self.current.tile_seq[i, j]
            """
             *↑ is correspond to (row, col) and (row, col+1)
             *exchange these two tiles of temp
            """
            tempHolder = tempArray[row, col]
            tempArray[row, col] = tempArray[row, col + 1]
            tempArray[row, col + 1] = tempHolder
            #print("temp right \n", tempArray)
            """
             *call check_inclusive(temp state)
             *define a new temp state via temp array
            """
            tempState = State()
            tempState.tile_seq = tempArray
            tempState.depth = self.depth
            flag = self.check_inclusive(tempState)
            # print("TempState \n",  tempState.tile_seq)
            """
             *do the next steps according to flag
             *if flag = 1 //not in open and closed
             *begin
             *assign the child a heuristic value via heuristic_test(temp state);
             *add the child to open
             *end;
             """
            if flag[0] == 1:
                self.heuristic_test(tempState)
                self.openlist.append(tempState)
                # print("open list \n", self.openlist)
            """
             *if flag = 2 //in the open list
             *if the child was reached by a shorter path
             *then give the state on open the shorter path
             """
            if flag[0] == 2:
                if self.openlist[flag[1]].depth > tempState.depth:
                    self.openlist[flag[1]].depth = tempState.depth
            # print("depth", tempState.depth)
            """
             *if flag = 3 //in the closed list
             *if the child was reached by a shorter path then
             *begin
             *remove the state from closed;
             *add the child to open
             *end;
            """
            if flag[0] == 3:
                if self.closed[flag[1]].depth > tempState.depth:
                    self.closed.remove(self.closed[flag[1]])
                    self.openlist.append(tempState)
            # TODO your code end here

        # sort the open list first by h(n) then g(n)
        self.openlist.sort(key=self.sortFun)
        self.current = self.openlist[0]

    """
     * Solve the game using heuristic search strategies

     * There are three types of heuristic rules:
     * (1) Tiles out of place
     * (2) Sum of distances out of place
     * (3) 2 x the number of direct tile reversals

     * evaluation function
     * f(n) = g(n) + h(n)
     * g(n) = depth of path length to start state
     * h(n) = (1) + (2) + (3)
    """

    def heuristic_test(self, current):
        curr_seq = current.tile_seq
        goal_seq = self.goal.tile_seq

        # (1) Tiles out of place
        h1 = 0
        # TODO your code start here
        """
         *loop over the curr_seq
         *check the every entry in curr_seq with goal_seq
        """
        for i in range(len(curr_seq)):
            for j in range(len(curr_seq[i])):
                if curr_seq[i, j] != goal_seq[i, j]:
                    h1 += 1
        # TODO your code end here

        # (2) Sum of distances out of place
        h2 = 0
        # TODO your code start here
        """
         *loop over the goal_seq and curr_seq in nested way
         *locate the entry which has the same value in 
         *curr_seq and goal_seq then calculate the offset
         *through the absolute value of two differences
         *of curr_row-goal_row and curr_col-goal_col
         *absoulte value can be calculated by abs(...)
        """
        # TODO your code end here

        # (3) 2 x the number of direct tile reversals
        h3 = 0
        # TODO your code start here
        """
         *loop over the curr_seq
         *use a Γ(gamma)shap slider to walk throught curr_seq and goal_seq
         *rule out the entry with value 0
         *set the boundry restriction
         *don't forget to time 2 at last
         *for example 
         *goal_seq  1 2 3   curr_seq  2 1 3 the Γ shape starts 
         *       4 5 6          4 5 6
         *       7 8 0          7 8 0
         *with 1 2 in goal_seq and 2 1 in curr_seq thus the 
         *    4             4
         *reversal is 1 2 and 2 1
        """
        # TODO your code end here

        h3 *= 2

        # set the heuristic value for current state
        current.weight = current.depth + h1 + h2 + h3

    # You can choose to print all the states on the search path, or just the start and goal state
    def run(self):
        # output the start state
        print("start state !!!!!")
        print(self.current.tile_seq)

        path = 0

        while not self.current.equals(self.goal):
            self.state_walk()
            print("decision \n", self.current.tile_seq)
            path += 1

        print("It took ", path, " iterations")
        print("The length of the path is: ", self.current.depth)
        # output the goal state
        target = self.goal.tile_seq
        print(target)
        print("goal state !!!!!")