Recursive brute force maze solver Java

后端 未结 1 553
天涯浪人
天涯浪人 2021-01-26 13:13

In an attempt to write a brute force maze solving C program, I\'ve written this java program first to test an idea. I\'m very new to C and intend to convert it after getting th

相关标签:
1条回答
  • 2021-01-26 13:53

    This wasn't originally intended to be an answer but it sort of evolved into one. Honestly, I think starting in Java and moving to C is a bad idea because the two languages are really nothing alike, and you won't be doing yourself any favors because you will run into serious issues porting it if you rely on any features java has that C doesn't (i.e. most of them)

    That said, I'll sketch out some algorithmic C stuff.

    Support Structures

    typedef
    struct Node
    {
        int x, y;
        // x and y are array indices
    }
    Node;
    
    typedef
    struct Path
    {
        int maxlen, head;
        Node * path;
        // maxlen is size of path, head is the index of the current node
        // path is the pointer to the node array
    }
    Path;
    
    int    node_compare(Node * n1, Node * n2); // returns true if nodes are equal, else false
    
    void   path_setup(Path * p, Node * n); // allocates Path.path and sets first node
    void   path_embiggen(Path * p);        // use realloc to make path bigger in case it fills up
    int    path_toosmall(Path * p);        // returns true if the path needs to be reallocated to add more nodes
    Node * path_head(Path * p);            // returns the head node of the path
    void   path_push(Path * p, Node * n);  // pushes a new head node onto the path
    void   path_pop(Path * p);             // pops a node from path
    

    You might to change your maze format into an adjacency list sort of thing. You could store each node as a mask detailing which nodes you can travel to from the node.

    Maze Format

    const int // these constants indicate which directions of travel are possible from a node
    N = (1 << 0),       // travel NORTH from node is possible
    S = (1 << 1),       // travel SOUTH from node is possible
    E = (1 << 2),       // travel EAST  from node is possible
    W = (1 << 3),       // travel WEST  from node is possible
    NUM_DIRECTIONS = 4; // number of directions (might not be 4.  no reason it has to be)
    
    const int
    START  = (1 << 4),  // starting  node
    FINISH = (1 << 5);  // finishing node
    
    const int
    MAZE_X = 4,         // maze dimensions
    MAZE_Y = 4;
    
    int maze[MAZE_X][MAZE_Y] = 
    {
        {E,        S|E|W,    S|E|W,    S|W       },
        {S|FINISH, N|S,      N|START,  N|S       },
        {N|S,      N|E,      S|E|W,    N|S|W     },
        {N|E,      E|W,      N|W,      N         }
    };
    
    Node start  = {1, 2}; // position of start node
    Node finish = {1, 0}; // position of end node
    

    My maze is different from yours: the two formats don't quite map to each other 1:1. For example, your format allows finer movement, but mine allows one-way paths.

    Note that your format explicitly positions walls. With my format, walls are conceptually located anywhere where a path is not possible. The maze I created has 3 horizontal walls and 5 vertical ones (and is also enclosed, i.e. there is a continuous wall surrounding the whole maze)

    For your brute force traversal, I would use a depth first search. You can map flags to directions in a number of ways, like maybe the following. Since you are looping over each one anyway, access times are irrelevant so an array and not some sort of faster associative container will be sufficient.

    Data Format to Offset Mappings

    // map directions to array offsets
    // format is [flag], [x offset], [y offset]
    int mappings[][] =
    {
        {N, -1,  0},
        {S,  1,  0},
        {E,  0,  1},
        {W,  0, -1}
    }
    

    Finally, your search. You could implement it iteratively or recursively. My example uses recursion.

    Search Algorithm Pseudocode

    int search_for_path(int ** maze, char ** visited, Path * path)
    {
        Node * head = path_head(path);
        Node temp;
        int i;
    
        if (node_compare(head, &finish)) return 1; // found finish
        if (visited[head->x][head->y])   return 0; // don't traverse again, that's pointless
    
        visited[head->x][head->y] = 1;
        if (path_toosmall(path)) path_embiggen(path);
    
        for (i = 0; i < NUM_DIRECTIONS; ++i)
        {
            if (maze[head->x][head->y] & mappings[i][0]) // path in this direction
            {
                temp = {head->x + mappings[i][1], head->y + mappings[i][2]};
                path_push(path, &temp);
                if (search_for_path(maze, visited, path)) return 1; // something found end
                path_pop(path);
            }
        }
        return 0; // unable to find path from any unvisited neighbor
    }
    

    To call this function, you should set everything up like this:

    Calling The Solver

    // we already have the maze
    // int maze[MAZE_X][MAZE_Y] = {...};
    
    // make a visited list, set to all 0 (unvisited)
    int visited[MAZE_X][MAZE_Y] = 
    {
        {0,0,0,0},
        {0,0,0,0},
        {0,0,0,0},
        {0,0,0,0}
    };
    
    // setup the path
    Path p;
    path_setup(&p, &start);
    
    if (search_for_path(maze, visited, &path))
    {
        // succeeded, path contains the list of nodes containing coordinates from start to end
    }
    else
    {
        // maze was impossible
    }
    

    It's worth noting that because I wrote this all in the edit box, I haven't tested any of it. It probably won't work on the first try and might take a little fiddling. For example, unless start and finish are declared globally, there will be a few issues. It would be better to pass the target node to the search function instead of using a global variable.

    0 讨论(0)
提交回复
热议问题