Advertisement
atomheartother

DailyProgrammer Maze

Jan 11th, 2017
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.58 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5.  
  6. #define BAD_CHAR 'x'
  7.  
  8. struct s_node;
  9.  
  10. // Represents a link from a node to another
  11. typedef struct  s_link
  12. {
  13.   struct s_node *dest;
  14.   struct s_link *next;
  15.   unsigned      moves;
  16. }               t_link;
  17.  
  18. // Represents a node
  19. typedef struct  s_node
  20. {
  21.   t_link        *links;
  22.   struct s_node *next;
  23.   unsigned      x;
  24.   unsigned      y;
  25.   char          id;
  26.   char          busy;
  27.   char          shortest;
  28. }               t_node;
  29.  
  30. typedef struct s_tile
  31. {
  32.   struct s_tile *next;
  33.   unsigned      x;
  34.   unsigned      y;
  35.   char          val;
  36. }               t_tile;
  37.  
  38. char g_display;
  39.  
  40. int    add_node(t_node **start, unsigned x,
  41.                 unsigned y, char id, char begin)
  42. {
  43.   t_node        *node = malloc(sizeof(t_node));
  44.   if (!node)
  45.     return 1;
  46.   node->x = x;
  47.   node->y = y;
  48.   node->id = id;
  49.   node->busy = 0;
  50.   node->shortest = 0;
  51.   node->links = NULL;
  52.   if (!*start)
  53.     {
  54.       node->next = NULL;
  55.       *start = node;
  56.     }
  57.   else if (begin)
  58.     {
  59.       node->next = *start;
  60.       *start = node;
  61.     }
  62.   else
  63.     {
  64.       node->next = (*start)->next;
  65.       (*start)->next = node;
  66.     }
  67.   return 0;
  68. }
  69.  
  70. void    delete_links(t_link *link)
  71. {
  72.   t_link        *temp;
  73.  
  74.   while (link)
  75.     {
  76.       temp = link->next;
  77.       free(link);
  78.       link = temp;
  79.     }
  80. }
  81.  
  82. void    delete_nodes(t_node *list)
  83. {
  84.   t_node        *temp;
  85.   while (list)
  86.     {
  87.       temp = list->next;
  88.       delete_links(list->links);
  89.       free(list);
  90.       list = temp;
  91.     }
  92. }
  93.  
  94. // Counts lines
  95. // Since we're reading every char individually, we also take this opportunity to find nodes
  96. unsigned        count_lines(const char * const str, t_node **start)
  97. {
  98.   FILE *f = fopen(str, "r");
  99.   if (!f)
  100.     return 0;
  101.   unsigned y = 0, x = 0;
  102.   while (!feof(f))
  103.     {
  104.       char c = fgetc(f);
  105.       if (c == -1)
  106.         break ;
  107.       else if (c == '\n')
  108.         {
  109.           x = 0;
  110.           y++;
  111.         }
  112.       else
  113.         {
  114.           if (c == '0')
  115.             {
  116.               if (add_node(start, x, y, c, 1))
  117.                 return 0;
  118.             }
  119.           else if (c != '.' && c != '#')
  120.             if (add_node(start, x, y, c, 0))
  121.               return 0;
  122.           x++;
  123.         }
  124.     }
  125.   fclose(f);
  126.   return y;
  127. }
  128.  
  129. void    delete_map(char **map)
  130. {
  131.   unsigned ii = 0;
  132.   while (map[ii])
  133.     free(map[ii++]);
  134. }
  135.  
  136. void    check_res(unsigned *res, unsigned val)
  137. {
  138.   if (val && (!*res || *res > val))
  139.     *res = val;
  140. }
  141.  
  142. t_tile*    create_tile(char **map, unsigned x, unsigned y)
  143. {
  144.   t_tile *list = malloc(sizeof(t_tile));
  145.  
  146.   list->x = x;
  147.   list->y = y;
  148.   list->val = map[y][x];
  149.   map[y][x] = BAD_CHAR;
  150.   list->next = NULL;
  151.   return list;
  152. }
  153.  
  154. void    append_to_list(t_tile **newlist, t_tile *new)
  155. {
  156.   if (*newlist)
  157.     new->next = (*newlist);
  158.   *newlist = new;
  159. }
  160.  
  161. unsigned        check_depth(char **map, t_tile *current, t_tile **newlist,
  162.                             t_tile *oldlist, t_node *node)
  163. {
  164.   // Done with this depth
  165.   if (!current)
  166.     return 0;
  167.  
  168.   unsigned res = 0;
  169.  
  170.   // Found match
  171.   if (current->val != '.' && current->val != node->id)
  172.     res = 1;
  173.  
  174.   // Only '.' and nodes get added
  175.   if (current->val != '#' && current->val != BAD_CHAR)
  176.     {
  177.       // Add tiles to new list
  178.       if (map[current->y][current->x + 1] != '#' && map[current->y][current->x + 1] != BAD_CHAR)
  179.         append_to_list(newlist, create_tile(map, current->x + 1, current->y));
  180.       if (map[current->y][current->x - 1] != '#' && map[current->y][current->x - 1] != BAD_CHAR)
  181.         append_to_list(newlist, create_tile(map, current->x - 1, current->y));
  182.       if (map[current->y + 1][current->x] != '#' && map[current->y + 1][current->x] != BAD_CHAR)
  183.         append_to_list(newlist, create_tile(map, current->x, current->y + 1));
  184.       if (map[current->y - 1][current->x] != '#' && map[current->y - 1][current->x] != BAD_CHAR)
  185.         append_to_list(newlist, create_tile(map, current->x, current->y - 1));
  186.     }
  187.   return res + check_depth(map, current->next, newlist, oldlist, node);
  188. }
  189.  
  190. void    delete_tiles(char **map, t_tile *list)
  191. {
  192.   t_tile *temp;
  193.   while (list)
  194.     {
  195.       map[list->y][list->x] = list->val;
  196.       temp = list->next;
  197.       free(list);
  198.       list = temp;
  199.     }
  200. }
  201.  
  202. void    join_lists(t_tile **l1, t_tile *l2)
  203. {
  204.   t_tile *temp = l2;
  205.   if (!temp)
  206.     return ;
  207.   while (temp->next)
  208.     temp = temp->next;
  209.   temp->next = *l1;
  210.   *l1 = l2;
  211. }
  212.  
  213. char            end_condition(t_link *links, t_node *nodes)
  214. {
  215.   unsigned ncount = 0;
  216.   while (nodes)
  217.     {
  218.       ncount++;
  219.       nodes = nodes->next;
  220.     }
  221.   unsigned lcount = 0;
  222.   while (links)
  223.     {
  224.       lcount++;
  225.       links = links->next;
  226.     }
  227.   return lcount == ncount - 1;
  228. }
  229.  
  230. unsigned        get_map_len(char* * map)
  231. {
  232.   unsigned len = 0;
  233.   unsigned i = 0;
  234.   while (map[i])
  235.     len += strlen(map[i++]);
  236.   return len;
  237. }
  238.  
  239. void    show_map(char **map)
  240. {
  241.   const unsigned len = get_map_len(map);
  242.   char pmap[len + 1];
  243.   pmap[0] = 0;
  244.   unsigned i = 0;
  245.   while (map[i])
  246.     {
  247.       strcat(pmap, map[i]);
  248.       i++;
  249.     }
  250.   write(1, pmap, len);
  251.   usleep(1000);
  252. }
  253.  
  254. void        bfs_link(char **map, t_node *node, t_node *start)
  255. {
  256.   // This contains the current values
  257.   t_tile        *list = create_tile(map, node->x, node->y);
  258.   // This contains the next values
  259.   t_tile *newlist = NULL;
  260.   // This contains the previous values
  261.   t_tile *oldlist = NULL;
  262.  
  263.   unsigned      dist = 0;
  264.  
  265.   while (42)
  266.     {
  267.       unsigned matches = check_depth(map, list, &newlist, oldlist, node);
  268.       t_tile *l = list;
  269.       // Browse the current list to find matches
  270.       if (matches)
  271.         {
  272.           while (matches && l)
  273.             {
  274.               // we found a value that matches
  275.               if (l->val != '.')
  276.                 {
  277.                   // Look for the node n we matched
  278.                   t_node *n = start;
  279.                   while (n)
  280.                     {
  281.                       if (n->id == l->val)
  282.                         {
  283.                           // Fill link information
  284.                           t_link *t = malloc(sizeof(t_link));
  285.                           t->dest = n;
  286.                           t->moves = dist;
  287.                           t->next = node->links;
  288.                           node->links = t;
  289.                           break ;
  290.                         }
  291.                       n = n->next;
  292.                     }
  293.                   matches--;
  294.                 }
  295.               l = l->next;
  296.             }
  297.           if (end_condition(node->links, start))
  298.             break ;
  299.         }
  300.       join_lists(&oldlist, list); // oldlist = list + oldlist
  301.       list = newlist;
  302.       newlist = NULL;
  303.       dist++;
  304.       if (list == NULL)
  305.         fprintf(stderr, "Could not find all nodes starting from %c!\n", node->id);
  306.       if (g_display)
  307.         show_map(map);
  308.     }
  309.   delete_tiles(map, oldlist);
  310.   delete_tiles(map, list);
  311.   delete_tiles(map, newlist);
  312. }
  313.  
  314. // Start from each node and find the path to every other node
  315. void    fill_links(char **map, t_node *start)
  316. {
  317.   t_node        *node = start;
  318.   while (node)
  319.     {
  320.       bfs_link(map, node, start);
  321.       node = node->next;
  322.     }
  323. }
  324.  
  325. int     fill_map(char **map, const char * const str,
  326.                  unsigned lines)
  327. {
  328.   FILE *f = fopen(str, "r");
  329.   if (!f)
  330.     return 1;
  331.   unsigned i = 0;
  332.   size_t line_width = 0;
  333.   while (i < lines)
  334.     {
  335.       // Saves allocs, assuming the map is a rectangle
  336.       if (!line_width)
  337.         map[i] = NULL;
  338.       else
  339.         map[i] = malloc(line_width);
  340.       if (getline(&map[i++], &line_width, f) == -1)
  341.         {
  342.           map[i] = NULL;
  343.           delete_map(map);
  344.           fclose(f);
  345.           return 1;
  346.         }
  347.     }
  348.   map[i] = NULL;
  349.   fclose(f);
  350.   return 0;
  351. }
  352.  
  353. void    show_node(t_node *node)
  354. {
  355.   printf("%c (%u, %u)\n", node->id, node->x, node->y);
  356.   t_link        *link = node->links;
  357.   while (link)
  358.     {
  359.       printf("\t->%c: %u\n", link->dest->id, link->moves);
  360.       link = link->next;
  361.     }
  362. }
  363.  
  364. // Go recursively into each link and find the shortest path. ez.
  365. unsigned    solve(t_node *start, unsigned moves)
  366. {
  367.   if (!start || start->busy)
  368.     return 0;
  369.   start->busy = 1;
  370.   t_link *l = start->links;
  371.   unsigned      temp = 0, res = 0;
  372.   while (l)
  373.     {
  374.       if ((temp = solve(l->dest, l->moves)) && (!res || res > temp))
  375.         {
  376.           res = temp;
  377.           start->shortest = l->dest->id;
  378.         }
  379.       l = l->next;
  380.     }
  381.   start->busy = 0;
  382.   return moves + res;
  383. }
  384.  
  385. void    get_option(char *str)
  386. {
  387.   if (!strcmp("--display", str))
  388.     g_display = 1;
  389. }
  390.  
  391. int     main(int ac, char * const av[])
  392. {
  393.   g_display = 0;
  394.   if (ac < 2)
  395.     {
  396.       fprintf(stderr, "usage: ./%s [--display] <map file>\n", av[0]);
  397.       return 1;
  398.     }
  399.   unsigned idx = ac == 2 ? 1 : 2;
  400.   if (idx == 2)
  401.     get_option(av[1]);
  402.   // We count lines first so we can allocate the right number of pointers
  403.   // We also take this opportunity to get node positions
  404.   t_node *start = NULL;
  405.   unsigned lines = count_lines(av[idx], &start);
  406.   if (!lines)
  407.     {
  408.       fprintf(stderr, "Something went wrong while opening %s\n", av[idx]);
  409.       return 1;
  410.     }
  411.   // Allocate map then fill it
  412.   char **map = malloc(sizeof(char*) * (lines + 1));
  413.   if (!map)
  414.     return 1;
  415.   if (!fill_map(map, av[idx], lines))
  416.     {
  417.       fill_links(map, start);
  418.       printf("Shortest path: %u\n", solve(start, 0));
  419.       delete_map(map);
  420.     }
  421.   else
  422.     fprintf(stderr, "Could not fill map\n");
  423.   delete_nodes(start);
  424.   free(map);
  425.   return 0;
  426. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement