[GO] Breadth-first search / bidirectional search (Python version)

Implemented breadth-first search and bidirectional search of the basic algorithm based on 8 puzzles

Breadth-first search

procedure

  1. Generate a start puzzle
  2. Queue the start puzzle
  3. Get the puzzle from the beginning of the queue
  4. Create a new puzzle when you move the puzzle up / down / left / right
  5. If the panel layout of the puzzle is the goal, it ends
  6. Check if the panel layout of the puzzle has appeared
  7. If it has already appeared, repeat from 5 for the puzzle in the next direction.
  8. Store the puzzle in the queue if it hasn't appeared yet
  9. Repeat steps 5 to 8 for puzzles in each direction
  10. Continue from 3 to 9 until the queue is empty

point

--Record the panel layout that has already appeared --Keep the panel arrangement that you have passed through in the puzzle object

class Queue:
    '''
Queue class for storing puzzle objects
    '''
    def __init__(self, puzzle):
        self.puzzle_list = []

        self.puzzle_list.append(puzzle)
    
    #Add puzzle to the end of the list
    def enqueue(self, puzzle):
        self.puzzle_list.append(puzzle)

    #Get the puzzle from the top of the list
    def dequeue(self):
        return self.puzzle_list.pop(0)

    #Check if the puzzle list is empty
    def is_empty(self):
        return len(self.puzzle_list) == 0


class Puzzle:
    '''
Puzzle class with current panel layout, list of checked panel layouts, puzzle size
    '''
    def __init__(self, panel_list, state_list, size):
        self.panel_list = panel_list

        #A list that holds the state of the panel arrangement that you have passed through
        self.state_list = state_list
        self.state_list.append(panel_list)

        self.size = size

    #Generator that returns the panel layout when 0 on the panel is moved left, right, up and down
    def gene_next_panel(self, puzzle):
        zero_pos = puzzle.panel_list.index(0)

        col = zero_pos // self.size
        raw = zero_pos % self.size

        def __get_next_panel():
            panel_list = puzzle.panel_list[:]
            n = panel_list[next_pos]
            panel_list[next_pos] = 0
            panel_list[zero_pos] = n
            return panel_list

        if self.size > col + 1:
            next_pos = (col + 1) * self.size + raw
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if col - 1 >= 0:
            next_pos = (col - 1) * self.size + raw
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if self.size > raw + 1:
            next_pos = col * self.size + raw + 1
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if raw - 1 >= 0:
            next_pos = col * self.size + raw - 1
            panel_list = __get_next_panel()
            yield tuple(panel_list)

    def result_print(self):

        for s in self.state_list:
            print(s)

def breadth_first(size, goal, panel_list):
    puzzle = Puzzle(panel_list, [], size)
    queue = Queue(puzzle)
    checked_dict = {}

    while queue.is_empty() is False:
        puzzle = queue.dequeue()

        for next_panel in puzzle.gene_next_panel(puzzle):
            next_puzzle = Puzzle(list(next_panel), puzzle.state_list[:], size)

            if next_panel in checked_dict:
                continue

            if list(next_panel) == goal:
                return next_puzzle

            #Record the panel layout that has already appeared
            checked_dict[next_panel] = True
            queue.enqueue(next_puzzle)

if __name__ == '__main__':
    size = 3
    goal = [1, 2, 3, 4, 5, 6, 7, 8, 0]
    panel_list = [5, 4, 2, 6, 7, 0, 8, 1, 3]

    puzzle = breadth_first(size, goal, panel_list)

    puzzle.result_print()

Bidirectional search

procedure

  1. Generate a start puzzle
  2. Queue the start puzzle
  3. Generate a goal puzzle
  4. Queue the goal puzzle
  5. Get the puzzle from the beginning of the queue
  6. Generate a panel layout when moving the puzzle up / down / left / right
  7. Check if the panel layout has appeared
  8. If it has already appeared, check the orientation of the puzzle that held the panel layout in the past and the puzzle being checked.
  9. Goal if the puzzles do not match
  10. Store the puzzle in a confirmation dictionary and queue if it hasn't appeared yet
  11. Perform steps 5 to 8 for the generated panel layout in each direction. 12.5 Continue from 5 to 10 until the queue is empty

point

--Store the puzzle object in the confirmation dictionary --When the same panel layout appears in the past, you can check the passage record of the puzzle object that possessed the panel layout.

class Queue:
    '''
Queue class for storing puzzle objects
    '''
    def __init__(self, puzzle):
        self.puzzle_list = []

        self.puzzle_list.append(puzzle)
    
    #Add puzzle to the end of the list
    def enqueue(self, puzzle):
        self.puzzle_list.append(puzzle)

    #Get the puzzle from the top of the list
    def dequeue(self):
        return self.puzzle_list.pop(0)

    #Check if the puzzle list is empty
    def is_empty(self):
        return len(self.puzzle_list) == 0


class Puzzle:
    '''
Puzzle class with current panel layout, list of checked panel layouts, puzzle size
    '''
    def __init__(self, panel_list, state_list, size, direction):
        self.panel_list = panel_list
        self.state_list = state_list
        self.state_list.append(panel_list)
        self.size = size
        self.direction = direction

    def gene_next_panel(self, puzzle):
        zero_pos = puzzle.panel_list.index(0)

        col = zero_pos // self.size
        raw = zero_pos % self.size

        def __get_next_panel():
            panel_list = puzzle.panel_list[:]
            n = panel_list[next_pos]
            panel_list[next_pos] = 0
            panel_list[zero_pos] = n
            return panel_list

        if self.size > col + 1:
            next_pos = (col + 1) * self.size + raw
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if col - 1 >= 0:
            next_pos = (col - 1) * self.size + raw
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if self.size > raw + 1:
            next_pos = col * self.size + raw + 1
            panel_list = __get_next_panel()
            yield tuple(panel_list)

        if raw - 1 >= 0:
            next_pos = col * self.size + raw - 1
            panel_list = __get_next_panel()
            yield tuple(panel_list)

    def result_print(self):

        for s in self.state_list:
            print(s)

    def back_result_print(self):

        for s in self.state_list[::-1]:
            print(s)

def bidirectional_search(size, goal, panel_list):
    start_puzzle = Puzzle(panel_list, [], size, 'S')
    queue = Queue(start_puzzle)
    goal_puzzle = Puzzle(goal, [], size, 'G')
    queue.enqueue(goal_puzzle)

    checked_dict = {}
    checked_dict[tuple(panel_list)] = start_puzzle
    checked_dict[tuple(goal)] = goal_puzzle

    while queue.is_empty() is False:
        puzzle = queue.dequeue()

        for next_panel in puzzle.gene_next_panel(puzzle):

            if next_panel in checked_dict:
                checked_puzzle = checked_dict[next_panel]

                if checked_puzzle.direction != puzzle.direction:
                    return puzzle, checked_puzzle

            else:
                new_puzzle = Puzzle(list(next_panel), puzzle.state_list[:], size, puzzle.direction)
                #Store the puzzle in the confirmation dictionary
                checked_dict[next_panel] = new_puzzle
                queue.enqueue(new_puzzle)

if __name__ == '__main__':
    size = 3
    goal = [1, 2, 3, 4, 5, 6, 7, 8, 0]
    panel_list = [5, 4, 2, 6, 7, 0, 8, 1, 3]

    front_puzzle, back_puzzle = bidirectional_search(size, goal, panel_list)

    front_puzzle.result_print()
    back_puzzle.back_result_print()

reference

-Algorithms with Python / Breadth-first search and iterative deepening

Recommended Posts

Breadth-first search / bidirectional search (Python version)
[Python] BFS (breadth-first search) ABC168D
[Python] Depth-first search and breadth-first search
[Python] BFS (breadth-first search) ABC007C
Algorithm in Python (breadth-first search, bfs)
Breadth-first search (BPF) Maybe understood (python)
Master linear search! ~ Python implementation version ~
PYTHON2.7 64bit version
Sequential search with Python
[Python] Search (itertools) ABC167C
Binary search in Python
[Python] Search (NumPy) ABC165C
Binary search (python2.7) memo
[Python] Binary search ABC155D
python bit full search
Linear search in Python
Binary search with python
Binary search with Python3
Search Twitter using Python
Python version switching (pyenv)
Binary search in Python (binary search)
Check version with python
I implemented breadth-first search in python (queue, drawing self-made)
Implement Depth-First Search (DFS) and Breadth-First Search (BFS) in python
Solving with Ruby and Python AtCoder ABC151 D Breadth-first search
Search for strings in Python
Petit stray Python version output
Search algorithm using word2vec [python]
Homebrew Python --Youtube Search Program
[Python] DFS (Depth-first Search) ATC001A
Change python version using pyenv
Version upgrade of python Anaconda
Binary search in Python / C ++
Algorithm in Python (binary search)
Full bit search with Python
[Python] DFS (Depth-first Search) ABC157D
Python version does not switch
Check OpenSSL version of python 2.6
Introduction to Python (Python version APG4b)
How to change Python version
Find the diameter of the graph by breadth-first search (Python memory)
Search engine work with python
Search twitter tweets with python
Specify python version with virtualenv
Streamline web search with python
tesseract-OCR for Python [Japanese version]
Error resolution python version check
[Python] Tuple version of prefecture pull-down
Virtual Environment Version Control Summary Python
Anaconda and Python version correspondence table
Install xgboost (python version) on Windows
Learn search with Python # 2bit search, permutation search
pyenv-change the python version of virtualenv
Self-organizing map in Python NumPy version
Ideone> Python version: 3.5 (as of August 29, 2017)
How to get the Python version
Algorithm in Python (depth-first search, dfs)
[Code] Module and Python version output
Change the Python version of Homebrew
Write a depth-first search in Python
[2021 version] Python installation Windows 10 (64bit) edition