commit 018821728749aa6ae0e0455a4dd81f8a913f0369
parent 44eac1222be04c60f60ef0309b44f4c3145e12e2
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 23 Mar 2023 20:28:36 +0100
Add day 14
Diffstat:
M | .gitmodules | | | 4 | +--- |
A | 14/info.mk | | | 4 | ++++ |
A | 14/input | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 14/main.c | | | 234 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 14/part1 | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 14/part2 | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 14/test1 | | | 6 | ++++++ |
A | 14/test2 | | | 9 | +++++++++ |
M | Makefile | | | 3 | ++- |
M | common/util.h | | | 2 | ++ |
10 files changed, 562 insertions(+), 4 deletions(-)
diff --git a/.gitmodules b/.gitmodules
@@ -4,11 +4,9 @@
[submodule "lib/libmaxint"]
path = lib/libmaxint
url = git@sinitax.com:snx/libmaxint
-[submodule "lib/libhashmap"]
- path = lib/libhmap
- url = git@sinitax.com:snx/libhashmap
[submodule "lib/liballoc"]
path = lib/liballoc
url = git@sinitax.com:snx/liballoc
[submodule "lib/libhmap"]
+ path = lib/libhmap
url = git@sinitax.com:snx/libhmap
diff --git a/14/info.mk b/14/info.mk
@@ -0,0 +1,4 @@
+14_SRC = 14/main.c common/main.c common/aoc.c common/util.c
+14_SRC += lib/libdvec/build/libdvec.a lib/liballoc/build/liballoc.a
+14_SRC += lib/libhmap/build/libhmap.a lib/libmaxint/build/libmaxint.a
+14_HDR = common/aoc.h common/util.h
diff --git a/14/input b/14/input
@@ -0,0 +1,58 @@
+1 ZQVND => 2 MBZM
+2 KZCVX, 1 SZBQ => 7 HQFB
+1 PFSQF => 9 RSVN
+2 PJXQB => 4 FSNZ
+20 JVDKQ, 2 LSQFK, 8 SDNCK, 1 MQJNV, 13 LBTV, 3 KPBRX => 5 QBPC
+131 ORE => 8 WDQSL
+19 BRGJH, 2 KNVN, 3 CRKW => 9 MQJNV
+16 DNPM, 1 VTVBF, 11 JSGM => 1 BWVJ
+3 KNVN, 1 JQRML => 7 HGQJ
+1 MRQJ, 2 HQFB, 1 MQJNV => 5 VQLP
+1 PLGH => 5 DMGF
+12 DMGF, 3 DNPM, 1 CRKW => 1 CLML
+1 JSGM, 1 RSVN => 5 TMNKH
+1 RFJLG, 3 CFWC => 2 ZJMC
+1 BRGJH => 5 KPBRX
+1 SZBQ, 17 GBVJF => 4 ZHGL
+2 PLGH => 5 CFWC
+4 FCBZS, 2 XQWHB => 8 JSGM
+2 PFSQF => 2 KNVN
+12 CRKW, 9 GBVJF => 1 KRCB
+1 ZHGL => 8 PJMFP
+198 ORE => 2 XQWHB
+2 BWVJ, 7 CFWC, 17 DPMWN => 3 KZCVX
+4 WXBF => 6 JVDKQ
+2 SWMTK, 1 JQRML => 7 QXGZ
+1 JSGM, 1 LFSFJ => 4 LSQFK
+73 KNVN, 65 VQLP, 12 QBPC, 4 XGTL, 10 SWMTK, 51 ZJMC, 4 JMCPR, 1 VNHT => 1 FUEL
+1 BWVJ, 7 MBZM => 5 JXZT
+10 CFWC => 2 DPMWN
+13 LQDLN => 3 LBTV
+1 PFZW, 3 LQDLN => 5 PJXQB
+2 RSVN, 2 PFSQF => 5 CRKW
+1 HGQJ, 3 SMNGJ, 36 JXZT, 10 FHKG, 3 KPBRX, 2 CLML => 3 JMCPR
+126 ORE => 4 FCBZS
+1 DNPM, 13 MBZM => 5 PLGH
+2 XQWHB, 10 FCBZS => 9 LFSFJ
+1 DPMWN => 9 PFZW
+1 ZJMC, 3 TMNKH => 2 SWMTK
+7 TZCK, 1 XQWHB => 5 ZQVND
+4 CFWC, 1 ZLWN, 5 RSVN => 2 WXBF
+1 BRGJH, 2 CLML => 6 LQDLN
+26 BWVJ => 2 GBVJF
+16 PJXQB, 20 SDNCK, 3 HQFB, 7 QXGZ, 2 KNVN, 9 KZCVX => 8 XGTL
+8 PJMFP, 3 BRGJH, 19 MRQJ => 5 SMNGJ
+7 DNPM => 2 SZBQ
+2 JQRML, 14 SDNCK => 8 FHKG
+1 FSNZ, 6 RFJLG, 2 CRKW => 8 SDNCK
+2 CLML, 4 SWMTK, 16 KNVN => 4 JQRML
+8 TZCK, 18 WDQSL => 2 PFSQF
+1 LSQFK => 8 VTVBF
+18 BRGJH, 8 ZHGL, 2 KRCB => 7 VNHT
+3 TZCK => 4 DNPM
+14 PFZW, 1 PFSQF => 7 BRGJH
+21 PLGH, 6 VTVBF, 2 RSVN => 1 ZLWN
+149 ORE => 2 TZCK
+3 JSGM => 1 RFJLG
+4 PFSQF, 4 DMGF => 3 MRQJ
+
diff --git a/14/main.c b/14/main.c
@@ -0,0 +1,234 @@
+#include "allocator.h"
+#include "aoc.h"
+#include "util.h"
+#include "hmap.h"
+#include "dvec.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct ingredient {
+ char name[8];
+ size_t amount;
+};
+
+struct reaction {
+ struct dvec ingredients;
+ struct ingredient result;
+
+};
+
+void
+parse_reactions(struct hmap *reactions)
+{
+ const char *pos, *sep, *lpos, *lend;
+ struct reaction *reaction;
+ struct ingredient ingredient;
+ char line[256];
+ void *slot;
+ int rc;
+
+ lpos = aoc.input;
+ lend = lpos + aoc.input_size;
+ while (readtok(line, sizeof(line), '\n', &lpos, lend)) {
+ if (strspn(line, " \r\n\t\v") == strlen(line))
+ continue;
+
+ reaction = malloc(sizeof(struct reaction));
+ assert(reaction != NULL);
+ dvec_init(&reaction->ingredients, sizeof(struct ingredient),
+ 10, &stdlib_strict_heap_allocator);
+
+ pos = line;
+ while (1) {
+ sep = strchr(pos, ',');
+ if (!sep) sep = strchr(pos, '>');
+
+ rc = sscanf(pos, "%lu %[^,= ]",
+ &ingredient.amount, ingredient.name);
+ assert(rc == 2);
+
+ if (sep) {
+ slot = dvec_add_slot(&reaction->ingredients, NULL);
+ memcpy(slot, &ingredient,
+ sizeof(struct ingredient));
+ } else {
+ memcpy(&reaction->result, &ingredient,
+ sizeof(struct ingredient));
+ }
+
+ if (!sep) break;
+ pos = sep + 2;
+ }
+
+ hmap_add(reactions,
+ (struct hmap_key) {.p = reaction->result.name},
+ (struct hmap_val) {.p = reaction});
+ }
+}
+
+size_t
+add_excess(struct hmap *hmap, struct ingredient *result, struct reaction *reaction)
+{
+ struct hmap_link **link;
+ size_t n, amount, excess;
+
+ amount = result->amount;
+ link = hmap_link_pos(hmap, (struct hmap_key) {.p = reaction->result.name});
+ if (link && *link) {
+ aoc_debug("get excess %s = %u\n", reaction->result.name,
+ (*link)->value.u);
+ if ((*link)->value.u >= amount) {
+ (*link)->value.u -= (unsigned int) amount;
+ return 0;
+ } else {
+ amount -= (*link)->value.u;
+ (*link)->value.u = 0;
+ }
+ }
+
+ n = CEILDIV(amount, reaction->result.amount);
+ excess = n * reaction->result.amount - amount;
+ aoc_debug("set excess %s = %lu\n", reaction->result.name, excess);
+ if (link && *link) {
+ (*link)->value.u = (unsigned int) excess;
+ } else {
+ hmap_add(hmap, (struct hmap_key) {.p = reaction->result.name},
+ (struct hmap_val) {.u = (unsigned int) excess});
+ }
+
+ return n;
+}
+
+size_t
+calculate_ore(struct hmap *reactions, struct hmap *excess,
+ const char *name, size_t amount)
+{
+ struct hmap_link *link;
+ struct reaction *reaction;
+ struct ingredient ingredient;
+ struct ingredient result;
+ struct dvec reactants;
+ struct ingredient *slot, *slot2;
+ size_t ore, n;
+
+ dvec_init(&reactants, sizeof(struct ingredient),
+ 10, &stdlib_strict_heap_allocator);
+
+ slot = dvec_add_slot(&reactants, NULL);
+ ingredient.amount = amount;
+ snprintf(ingredient.name, 8, "%s", name);
+ memcpy(slot, &ingredient, sizeof(struct ingredient));
+
+ ore = 0;
+ while (!dvec_empty(&reactants)) {
+ slot = dvec_back(&reactants);
+ memcpy(&result, slot, sizeof(struct ingredient));
+ dvec_rm_slot(&reactants, slot);
+
+ link = hmap_get(reactions, (struct hmap_key) {.p = result.name});
+ assert(link != NULL);
+ reaction = link->value._p;
+
+ n = add_excess(excess, &result, reaction);
+ if (!n) continue;
+
+ for (DVEC_ITER(&reaction->ingredients, &slot)) {
+ aoc_debug("%lu %s needs %lu %s\n",
+ result.amount, result.name,
+ slot->amount * n, slot->name);
+ if (!strcmp(slot->name, "ORE")) {
+ ore += slot->amount * n;
+ } else {
+ snprintf(ingredient.name, 8, "%s", slot->name);
+ ingredient.amount = slot->amount * n;
+ slot2 = dvec_add_slot(&reactants, NULL);
+ memcpy(slot2, &ingredient, sizeof(struct ingredient));
+ }
+ }
+ }
+
+ dvec_deinit(&reactants);
+
+ return ore;
+}
+
+void
+part1(void)
+{
+ struct hmap_iter iter;
+ struct hmap reactions;
+ struct hmap excess;
+ struct reaction *reaction;
+ size_t ore;
+
+ hmap_init(&reactions, 256, hmap_str_hash, hmap_str_keycmp,
+ &stdlib_strict_heap_allocator);
+ hmap_init(&excess, 256, hmap_str_hash, hmap_str_keycmp,
+ &stdlib_strict_heap_allocator);
+
+ parse_reactions(&reactions);
+
+ ore = calculate_ore(&reactions, &excess, "FUEL", 1);
+
+ aoc.answer = aprintf("%lu", ore);
+ aoc.solution = "1582325";
+
+ for (HMAP_ITER(&reactions, &iter)) {
+ reaction = iter.link->value._p;
+ dvec_deinit(&reaction->ingredients);
+ free(iter.link->value._p);
+ }
+ hmap_deinit(&excess);
+ hmap_deinit(&reactions);
+}
+
+void
+part2(void)
+{
+ const size_t max_ore = 1000000000000UL;
+ struct hmap_iter iter;
+ struct hmap reactions;
+ struct hmap excess;
+ struct reaction *reaction;
+ size_t fuel_min, fuel_max;
+ size_t ore, fuel;
+
+ hmap_init(&reactions, 256, hmap_str_hash, hmap_str_keycmp,
+ &stdlib_strict_heap_allocator);
+ hmap_init(&excess, 256, hmap_str_hash, hmap_str_keycmp,
+ &stdlib_strict_heap_allocator);
+
+ parse_reactions(&reactions);
+
+ fuel_min = 1;
+ fuel_max = max_ore;
+ while (1) {
+ fuel = (fuel_min + fuel_max) / 2;
+ if (fuel == fuel_min) break;
+ ore = calculate_ore(&reactions, &excess, "FUEL", fuel);
+ if (ore > max_ore) {
+ fuel_max = fuel;
+ } else if (ore < max_ore) {
+ fuel_min = fuel;
+ } else {
+ break;
+ }
+ hmap_clear(&excess);
+ }
+
+ aoc.answer = aprintf("%lu", fuel);
+ aoc.solution = "2267486";
+
+ for (HMAP_ITER(&reactions, &iter)) {
+ reaction = iter.link->value._p;
+ dvec_deinit(&reaction->ingredients);
+ free(iter.link->value._p);
+ }
+ hmap_deinit(&excess);
+ hmap_deinit(&reactions);
+}
diff --git a/14/part1 b/14/part1
@@ -0,0 +1,123 @@
+--- Day 14: Space Stoichiometry ---
+
+As you approach the rings of Saturn, your ship's low fuel indicator turns on. There isn't any fuel
+here, but the rings have plenty of raw material. Perhaps your ship's Inter-Stellar Refinery Union
+brand nanofactory can turn these raw materials into fuel.
+
+You ask the nanofactory to produce a list of the reactions it can perform that are relevant to this
+process (your puzzle input). Every reaction turns some quantities of specific input chemicals into
+some quantity of an output chemical. Almost every chemical is produced by exactly one reaction; the
+only exception, ORE, is the raw material input to the entire process and is not produced by a
+reaction.
+
+You just need to know how much ORE you'll need to collect before you can produce one unit of FUEL.
+
+Each reaction gives specific quantities for its inputs and output; reactions cannot be partially
+run, so only whole integer multiples of these quantities can be used. (It's okay to have leftover
+chemicals when you're done, though.) For example, the reaction 1 A, 2 B, 3 C => 2 D means that
+exactly 2 units of chemical D can be produced by consuming exactly 1 A, 2 B and 3 C. You can run
+the full reaction as many times as necessary; for example, you could produce 10 D by consuming 5 A,
+10 B, and 15 C.
+
+Suppose your nanofactory produces the following list of reactions:
+
+10 ORE => 10 A
+1 ORE => 1 B
+7 A, 1 B => 1 C
+7 A, 1 C => 1 D
+7 A, 1 D => 1 E
+7 A, 1 E => 1 FUEL
+
+The first two reactions use only ORE as inputs; they indicate that you can produce as much of
+chemical A as you want (in increments of 10 units, each 10 costing 10 ORE) and as much of chemical B
+as you want (each costing 1 ORE). To produce 1 FUEL, a total of 31 ORE is required: 1 ORE to
+produce 1 B, then 30 more ORE to produce the 7 + 7 + 7 + 7 = 28 A (with 2 extra A wasted) required
+in the reactions to convert the B into C, C into D, D into E, and finally E into FUEL. (30 A is
+produced because its reaction requires that it is created in increments of 10.)
+
+Or, suppose you have the following list of reactions:
+
+9 ORE => 2 A
+8 ORE => 3 B
+7 ORE => 5 C
+3 A, 4 B => 1 AB
+5 B, 7 C => 1 BC
+4 C, 1 A => 1 CA
+2 AB, 3 BC, 4 CA => 1 FUEL
+
+The above list of reactions requires 165 ORE to produce 1 FUEL:
+
+
+ - Consume 45 ORE to produce 10 A.
+
+ - Consume 64 ORE to produce 24 B.
+
+ - Consume 56 ORE to produce 40 C.
+
+ - Consume 6 A, 8 B to produce 2 AB.
+
+ - Consume 15 B, 21 C to produce 3 BC.
+
+ - Consume 16 C, 4 A to produce 4 CA.
+
+ - Consume 2 AB, 3 BC, 4 CA to produce 1 FUEL.
+
+
+Here are some larger examples:
+
+
+ - 13312 ORE for 1 FUEL:
+
+157 ORE => 5 NZVS
+165 ORE => 6 DCFZ
+44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
+12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
+179 ORE => 7 PSHF
+177 ORE => 5 HKGWZ
+7 DCFZ, 7 PSHF => 2 XJWVT
+165 ORE => 2 GPVTF
+3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
+
+
+ - 180697 ORE for 1 FUEL:
+
+2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
+17 NVRVD, 3 JNWZP => 8 VPVL
+53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
+22 VJHF, 37 MNCFX => 5 FWMGM
+139 ORE => 4 NVRVD
+144 ORE => 7 JNWZP
+5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
+5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
+145 ORE => 6 MNCFX
+1 NVRVD => 8 CXFTF
+1 VJHF, 6 MNCFX => 4 RFSQX
+176 ORE => 6 VJHF
+
+
+ - 2210736 ORE for 1 FUEL:
+
+171 ORE => 8 CNZTR
+7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
+114 ORE => 4 BHXH
+14 VRPVC => 6 BMBT
+6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
+6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
+15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
+13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
+5 BMBT => 4 WPTQ
+189 ORE => 9 KTJDG
+1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
+12 VRPVC, 27 CNZTR => 2 XDBXC
+15 KTJDG, 12 BHXH => 5 XCVML
+3 BHXH, 2 VRPVC => 7 MZWV
+121 ORE => 7 VRPVC
+7 XCVML => 6 RJRHP
+5 BHXH, 4 VRPVC => 5 LTCX
+
+
+
+Given the list of reactions in your puzzle input, what is the minimum amount of ORE required to
+produce exactly 1 FUEL?
+
+
diff --git a/14/part2 b/14/part2
@@ -0,0 +1,123 @@
+--- Day 14: Space Stoichiometry ---
+
+As you approach the rings of Saturn, your ship's low fuel indicator turns on. There isn't any fuel
+here, but the rings have plenty of raw material. Perhaps your ship's Inter-Stellar Refinery Union
+brand nanofactory can turn these raw materials into fuel.
+
+You ask the nanofactory to produce a list of the reactions it can perform that are relevant to this
+process (your puzzle input). Every reaction turns some quantities of specific input chemicals into
+some quantity of an output chemical. Almost every chemical is produced by exactly one reaction; the
+only exception, ORE, is the raw material input to the entire process and is not produced by a
+reaction.
+
+You just need to know how much ORE you'll need to collect before you can produce one unit of FUEL.
+
+Each reaction gives specific quantities for its inputs and output; reactions cannot be partially
+run, so only whole integer multiples of these quantities can be used. (It's okay to have leftover
+chemicals when you're done, though.) For example, the reaction 1 A, 2 B, 3 C => 2 D means that
+exactly 2 units of chemical D can be produced by consuming exactly 1 A, 2 B and 3 C. You can run
+the full reaction as many times as necessary; for example, you could produce 10 D by consuming 5 A,
+10 B, and 15 C.
+
+Suppose your nanofactory produces the following list of reactions:
+
+10 ORE => 10 A
+1 ORE => 1 B
+7 A, 1 B => 1 C
+7 A, 1 C => 1 D
+7 A, 1 D => 1 E
+7 A, 1 E => 1 FUEL
+
+The first two reactions use only ORE as inputs; they indicate that you can produce as much of
+chemical A as you want (in increments of 10 units, each 10 costing 10 ORE) and as much of chemical B
+as you want (each costing 1 ORE). To produce 1 FUEL, a total of 31 ORE is required: 1 ORE to
+produce 1 B, then 30 more ORE to produce the 7 + 7 + 7 + 7 = 28 A (with 2 extra A wasted) required
+in the reactions to convert the B into C, C into D, D into E, and finally E into FUEL. (30 A is
+produced because its reaction requires that it is created in increments of 10.)
+
+Or, suppose you have the following list of reactions:
+
+9 ORE => 2 A
+8 ORE => 3 B
+7 ORE => 5 C
+3 A, 4 B => 1 AB
+5 B, 7 C => 1 BC
+4 C, 1 A => 1 CA
+2 AB, 3 BC, 4 CA => 1 FUEL
+
+The above list of reactions requires 165 ORE to produce 1 FUEL:
+
+
+ - Consume 45 ORE to produce 10 A.
+
+ - Consume 64 ORE to produce 24 B.
+
+ - Consume 56 ORE to produce 40 C.
+
+ - Consume 6 A, 8 B to produce 2 AB.
+
+ - Consume 15 B, 21 C to produce 3 BC.
+
+ - Consume 16 C, 4 A to produce 4 CA.
+
+ - Consume 2 AB, 3 BC, 4 CA to produce 1 FUEL.
+
+
+Here are some larger examples:
+
+
+ - 13312 ORE for 1 FUEL:
+
+157 ORE => 5 NZVS
+165 ORE => 6 DCFZ
+44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
+12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
+179 ORE => 7 PSHF
+177 ORE => 5 HKGWZ
+7 DCFZ, 7 PSHF => 2 XJWVT
+165 ORE => 2 GPVTF
+3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
+
+
+ - 180697 ORE for 1 FUEL:
+
+2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
+17 NVRVD, 3 JNWZP => 8 VPVL
+53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
+22 VJHF, 37 MNCFX => 5 FWMGM
+139 ORE => 4 NVRVD
+144 ORE => 7 JNWZP
+5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
+5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
+145 ORE => 6 MNCFX
+1 NVRVD => 8 CXFTF
+1 VJHF, 6 MNCFX => 4 RFSQX
+176 ORE => 6 VJHF
+
+
+ - 2210736 ORE for 1 FUEL:
+
+171 ORE => 8 CNZTR
+7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
+114 ORE => 4 BHXH
+14 VRPVC => 6 BMBT
+6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
+6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
+15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
+13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
+5 BMBT => 4 WPTQ
+189 ORE => 9 KTJDG
+1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
+12 VRPVC, 27 CNZTR => 2 XDBXC
+15 KTJDG, 12 BHXH => 5 XCVML
+3 BHXH, 2 VRPVC => 7 MZWV
+121 ORE => 7 VRPVC
+7 XCVML => 6 RJRHP
+5 BHXH, 4 VRPVC => 5 LTCX
+
+
+
+Given the list of reactions in your puzzle input, what is the minimum amount of ORE required to
+produce exactly 1 FUEL?
+
+
diff --git a/14/test1 b/14/test1
@@ -0,0 +1,6 @@
+10 ORE => 10 A
+1 ORE => 1 B
+7 A, 1 B => 1 C
+7 A, 1 C => 1 D
+7 A, 1 D => 1 E
+7 A, 1 E => 1 FUEL
diff --git a/14/test2 b/14/test2
@@ -0,0 +1,9 @@
+157 ORE => 5 NZVS
+165 ORE => 6 DCFZ
+44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
+12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
+179 ORE => 7 PSHF
+177 ORE => 5 HKGWZ
+7 DCFZ, 7 PSHF => 2 XJWVT
+165 ORE => 2 GPVTF
+3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
diff --git a/Makefile b/Makefile
@@ -1,6 +1,7 @@
CFLAGS = -I lib/libdvec/include -I lib/libhmap/include
CFLAGS += -I lib/libmaxint/include -I lib/liballoc/include
-CFLAGS += -Wunused-variable -Wunused-function -Wformat -Wconversion
+CFLAGS += -Wunused-variable -Wunused-function -Wformat
+CFLAGS += -Wconversion -Wsign-compare
CFLAGS += -I common -g -Werror
ifeq "$(DEBUG)" "1"
diff --git a/common/util.h b/common/util.h
@@ -16,6 +16,8 @@
#define XORSWAP(a, b) ((a) ^= (b) ^= (a))
+#define CEILDIV(a, b) ((a) / (b) + ((a) % (b) ? 1 : 0))
+
__attribute__((noreturn)) void die(const char *fmtstr, ...);
bool readtok(char *buf, size_t buflen,