#include #include #include #include #define arrlen(x) (sizeof(x)/sizeof((x)[0])) enum MATERIAL { ORE, CLAY, BSDN, GEOD, }; struct blueprint { int id; int ore_ore; int clay_ore; int bsdn_ore; int bsdn_clay; int geod_ore; int geod_bsdn; }; void blueprint_ctor(struct blueprint * b, int id, int ore_ore, int clay_ore, int bsdn_ore, int bsdn_clay, int geod_ore, int geod_bsdn) { b->id = id; b->ore_ore = ore_ore; b->clay_ore = clay_ore; b->bsdn_ore = bsdn_ore; b->bsdn_clay = bsdn_clay; b->geod_ore = geod_ore; b->geod_bsdn = geod_bsdn; } struct material { long amount; long robots; long pending; }; void material_ctor(struct material * m, long amount, long robots) { m->amount = amount; m->robots = robots; m->pending = 0; } // Tick a material. // // Amount increases by the number of robots // Number of robots increases by number of pending robots void material_tick(struct material * m) { m->amount += m->robots; m->robots += m->pending; m->pending = 0; } struct inventory { struct material ore; struct material clay; struct material bsdn; struct material geod; }; void inventory_init(struct inventory * i) { material_ctor(&i->ore, 0, 1); material_ctor(&i->clay, 0, 0); material_ctor(&i->bsdn, 0, 0); material_ctor(&i->geod, 0, 0); } void inventory_tick(struct inventory * i) { material_tick(&i->ore); material_tick(&i->clay); material_tick(&i->bsdn); material_tick(&i->geod); } // Try to build a robot out of material #m int inventory_build(struct inventory * i, struct blueprint const * b, enum MATERIAL m) { switch (m) { case ORE: if (i->ore.amount < b->ore_ore) return -1; i->ore.amount -= b->ore_ore; i->ore.pending += 1; break; case CLAY: if (i->ore.amount < b->clay_ore) return -1; i->ore.amount -= b->clay_ore; i->clay.pending += 1; break; case BSDN: if (i->ore.amount < b->bsdn_ore || i->clay.amount < b->bsdn_clay) return -1; i->ore.amount -= b->bsdn_ore; i->clay.amount -= b->bsdn_clay; i->bsdn.pending += 1; break; case GEOD: if (i->ore.amount < b->geod_ore || i->bsdn.amount < b->geod_bsdn) return -1; i->ore.amount -= b->geod_ore; i->bsdn.amount -= b->geod_bsdn; i->geod.pending += 1; break; default: return -1; } return 0; } // Most basic build algorithm. Build as many of the most important things that you // can, and then as many of the next most important, and so on. // // Not optimal. But it helps get the structure of the program working. void inventory_build_basic(struct inventory * i, struct blueprint const * b, int remaining) { int t; for (t = 0; t < remaining; ++t) { while (inventory_build(i, b, GEOD) == 0) ; while (inventory_build(i, b, BSDN) == 0) ; while (inventory_build(i, b, CLAY) == 0) ; while (inventory_build(i, b, ORE) == 0) ; inventory_tick(i); fprintf(stderr, "Blueprint %d tick %d, ore: %ld/%ld, clay %ld/%ld, bsdn %ld/%ld, geod %ld/%ld\n", b->id, t + 1, i->ore.amount, i->ore.robots, i->clay.amount, i->clay.robots, i->bsdn.amount, i->bsdn.robots, i->geod.amount, i->geod.robots); } } int main(int argc, char ** argv) { int rounds = 24; int i; regex_t reblueprint; char buf[BUFSIZ]; while ((i = getopt(argc, argv, "r:")) != -1) { switch (i) { case 'r': rounds = atoi(optarg); break; default: return -1; } } if (regcomp(&reblueprint, "Blueprint ([[:digit:]]+):" " Each ore robot costs ([[:digit:]]+) ore." " Each clay robot costs ([[:digit:]]+) ore." " Each obsidian robot costs ([[:digit:]]+) ore and ([[:digit:]]+) clay." " Each geode robot costs ([[:digit:]]+) ore and ([[:digit:]]+) obsidian.", REG_EXTENDED) != 0) { fprintf(stderr, "Bad regex\n"); return -1; } while (fgets(buf, sizeof(buf), stdin)) { regmatch_t rematch[8]; struct blueprint b; struct inventory i; if (regexec(&reblueprint, buf, arrlen(rematch), rematch, 0) != 0) { fprintf(stderr, "Unexpected blueprint in %s\n", buf); continue; } blueprint_ctor(&b, atoi(buf + rematch[1].rm_so), atoi(buf + rematch[2].rm_so), atoi(buf + rematch[3].rm_so), atoi(buf + rematch[4].rm_so), atoi(buf + rematch[5].rm_so), atoi(buf + rematch[6].rm_so), atoi(buf + rematch[7].rm_so)); inventory_init(&i); inventory_build_basic(&i, &b, rounds); printf("Blueprint %d geodes = %ld\n", b.id, i.geod.amount); } regfree(&reblueprint); return 0; }