Add solution to second part of day 5
authorLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Tue, 5 Dec 2023 10:44:39 +0000 (11:44 +0100)
committerLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Wed, 6 Dec 2023 10:17:28 +0000 (11:17 +0100)
This solution may be vastly improved by implementing composition of
maps. Then every map may be reduced to a single map from seed to
location. This composition should then also give the location ranges
from seed ranges and the lowest location start of range is the result.

5/5b.c [new file with mode: 0644]

diff --git a/5/5b.c b/5/5b.c
new file mode 100644 (file)
index 0000000..6eec9f5
--- /dev/null
+++ b/5/5b.c
@@ -0,0 +1,255 @@
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "libft.h"
+
+#define MAP_TYPES 7
+
+typedef unsigned int t_myint;
+
+struct s_seed_range
+{
+       t_myint start;
+       t_myint range;
+};
+typedef struct s_seed_range    t_seed_range;
+
+struct s_seeds
+{
+       size_t                  size;
+       t_seed_range    *seeds;
+};
+typedef struct s_seeds t_seeds;
+
+struct s_transform
+{
+       t_myint dest_start;
+       t_myint src_start;
+       t_myint range;
+};
+typedef struct s_transform     t_transform;
+
+struct s_map
+{
+       t_transform     *trans;
+       size_t          size;
+       size_t          capacity;
+};
+typedef struct s_map   t_map;
+
+struct s_almanac
+{
+       t_map   maps[MAP_TYPES];
+};
+typedef struct s_almanac       t_almanac;
+
+size_t count_char(const char *str, char c)
+{
+       size_t  counter;
+
+       counter = 0;
+       while (*str)
+       {
+               if (*str == c)
+                       ++counter;
+               ++str;
+       }
+       return (counter);
+}
+
+void   parse_seeds(const char *line, t_seeds *seeds)
+{
+       size_t  i;
+
+       seeds->size = count_char(line, ' ') / 2;
+       seeds->seeds = ft_calloc(seeds->size, sizeof(*(seeds->seeds)));
+       while (*line != ':')
+               ++line;
+       ++line;
+       i = 0;
+       while (i < seeds->size)
+       {
+               seeds->seeds[i].start = ft_atoi(++line);
+               while (ft_isdigit(*line))
+                       ++line;
+               seeds->seeds[i].range = ft_atoi(++line);
+               while (ft_isdigit(*line))
+                       ++line;
+               ++i;
+       }
+       return ;
+}
+
+t_transform    parse_transform(const char *str)
+{
+       t_transform     trans;
+
+       trans.dest_start = ft_atoi(str);
+       while (ft_isdigit(*str))
+               ++str;
+       trans.src_start = ft_atoi(++str);
+       while (ft_isdigit(*str))
+               ++str;
+       trans.range = ft_atoi(++str);
+       return (trans);
+}
+
+int    enlarge_map(t_map *map)
+{
+       t_transform     *tmp;
+
+       tmp = map->trans;
+       map->trans = ft_calloc(map->capacity * 2, sizeof(*map->trans));
+       if (!map->trans)
+       {
+               map->trans = tmp;
+               return (1);
+       }
+       map->capacity *= 2;
+       ft_memcpy(map->trans, tmp, map->size * sizeof(*map->trans));
+       free(tmp);
+       return (0);
+}
+
+void   add_transform(t_map *map, t_transform trans)
+{
+       if (map->size == map->capacity)
+               enlarge_map(map);
+       map->trans[map->size] = trans;
+       ++(map->size);
+       return ;
+}
+
+void   init_almanac(t_almanac *almanac)
+{
+       size_t  i;
+
+       i = 0;
+       while (i < MAP_TYPES)
+       {
+               almanac->maps[i].size = 0;
+               almanac->maps[i].capacity = 4;
+               almanac->maps[i].trans = ft_calloc(almanac->maps[i].capacity, sizeof(*almanac->maps[i].trans));
+               ++i;
+       }
+       return ;
+}
+
+int    parse(const char *file_name, t_almanac *almanac, t_seeds *seeds)
+{
+       int             fd;
+       char    *line;
+       size_t  i;
+
+       fd = open(file_name, O_RDONLY);
+       if (fd < 0)
+               return (2);
+       line = get_next_line(fd);
+       parse_seeds(line, seeds);
+       free(get_next_line(fd));
+       i = 0;
+       while (i < MAP_TYPES)
+       {
+               free(line);
+               free(get_next_line(fd));
+               line = get_next_line(fd);
+               while (line)
+               {
+                       if (*line == '\n')
+                               break;
+                       add_transform(&almanac->maps[i], parse_transform(line));
+                       free(line);
+                       line = get_next_line(fd);
+               }
+               ++i;
+       }
+       close(fd);
+       return (0);
+}
+
+t_myint        apply_map(t_myint input, const t_map map)
+{
+       size_t  i;
+       t_myint offset;
+
+       i = 0;
+       while (i < map.size)
+       {
+               if (map.trans[i].src_start <= input && input <= map.trans[i].src_start + map.trans[i].range - 1)
+               {
+                       offset = input - map.trans[i].src_start;
+                       return (map.trans[i].dest_start + offset);
+               }
+               ++i;
+       }
+       return (input);
+}
+
+t_myint        find_location(t_myint seed, const t_almanac almanac)
+{
+       t_myint tmp;
+       size_t  i;
+
+       i = 0;
+       while (i < MAP_TYPES)
+       {
+               seed = apply_map(seed, almanac.maps[i]);
+               ++i;
+       }
+       return (seed);
+}
+
+void   free_almanac(t_almanac *almanac)
+{
+       size_t  i;
+
+       i = 0;
+       while (i < MAP_TYPES)
+       {
+               free(almanac->maps[i].trans);
+               ++i;
+       }
+       return ;
+}
+
+void   free_seeds(t_seeds *seeds)
+{
+       free(seeds->seeds);
+       return ;
+}
+
+int    main(int argc, char **argv)
+{
+       t_seeds         seeds;
+       t_almanac       almanac;
+       t_myint         min;
+       size_t          i;
+       size_t          j;
+       t_myint         tmp;
+
+       if (argc != 2)
+               return (1);
+       init_almanac(&almanac);
+       if (parse(argv[1], &almanac, &seeds))
+               return (2);
+       min = -1;
+       i = 0;
+       while (i < seeds.size)
+       {
+               ft_printf("Current progress:\t%u / %u\n", i, seeds.size);
+               j = 0;
+               while (j < seeds.seeds[i].range)
+               {
+                       tmp = find_location(seeds.seeds[i].start + j, almanac); 
+                       if (tmp < min)
+                               min = tmp;
+                       ++j;
+               }
+               ++i;
+       }
+       free_almanac(&almanac);
+       free_seeds(&seeds);
+       ft_printf("The closest location is %u.\n", min);
+       return (0);
+}