Files
adventofcode2022/day19/robot.c

207 lines
5.9 KiB
C
Raw Normal View History

2022-12-22 20:15:21 +01:00
#include <endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 256
#define MAX_BLUEPRINT 128
#define MAX_TIME 24
#define PART_TWO_NUM 3
#define PART_TWO_TIME 32
#define max(a,b) (a >= b ? a : b)
typedef struct blueprint {
int ore_cost;
int clay_cost;
int obsidian_cost[2];
int geode_cost[2];
} BLUEPRINT;
int bestGeode(BLUEPRINT, int[], int[], int, int);
int bestMax = 0;
int main() {
char buf[BUFFER_SIZE], *p, c;
memset(buf, 0, BUFFER_SIZE);
p = buf;
BLUEPRINT blueprints[MAX_BLUEPRINT];
int blueprint_count = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c == '\n') {
sscanf(buf, "Blueprint %*i: Each ore robot costs %i ore. Each clay robot costs %i ore. Each obsidian robot costs %i ore and %i clay. Each geode robot costs %i ore and %i obsidian.", &blueprints[blueprint_count].ore_cost, &blueprints[blueprint_count].clay_cost, &blueprints[blueprint_count].obsidian_cost[0], &blueprints[blueprint_count].obsidian_cost[1], &blueprints[blueprint_count].geode_cost[0], &blueprints[blueprint_count].geode_cost[1]);
blueprint_count++;
memset(buf, 0, BUFFER_SIZE);
p = buf;
}
}
int *quality_levels = (int*)malloc(blueprint_count * sizeof(int));
memset(quality_levels, 0, blueprint_count * sizeof(int));
// Check each blueprint
for (int i = 0; i < blueprint_count; i++) {
bestMax = 0;
int stash[4] = {0,0,0,0};
int robots[4] = {1,0,0,0};
quality_levels[i] = bestGeode(blueprints[i], stash, robots, 0, MAX_TIME);
}
int sum = 0;
for (int i = 0; i < blueprint_count; i++) {
sum += (i+1) * quality_levels[i];
}
printf("%i\n", sum);
free(quality_levels);
unsigned product = 1;
for (int i = 0; i < PART_TWO_NUM; i++) {
bestMax = 0;
int stash[4] = {0,0,0,0};
int robots[4] = {1,0,0,0};
product *= bestGeode(blueprints[i], stash, robots, 0, PART_TWO_TIME);
}
printf("%u\n", product);
}
int bestGeode(BLUEPRINT blueprint, int stash[], int robots[], int sum, int time) {
if (time <= 0) {
return sum;
}
int pompom = 0;
for (int i = 1; i <= time; i+=2) {
pompom += i;
}
if (bestMax > sum + pompom) {
return sum;
}
int max = sum;
int stashCopy[4];
memcpy(stashCopy, stash, 4*sizeof(int));
int robotsCopy[4];
memcpy(robotsCopy, robots, 4*sizeof(int));
// At every step we decide what robot will we build next (if we can)
int mostGeodes = 0;
// Ore robot
int timeCost = 0, timeCost2 = 0;
while (stash[0] + timeCost*robots[0] < blueprint.ore_cost) {
timeCost++;
}
// Build time
timeCost++;
// We don't have the time left to build this
if (time - timeCost >= 0) {
for (int j = 0; j < 4; j++) {
stash[j] = stash[j] + timeCost * robots[j];
}
stash[0] -= blueprint.ore_cost;
robots[0]++;
mostGeodes = bestGeode(blueprint, stash, robots, sum, time - timeCost);
memcpy(stash, stashCopy, 4*sizeof(int));
memcpy(robots, robotsCopy, 4*sizeof(int));
if (mostGeodes > max) {
max = mostGeodes;
}
}
// Clay robot
timeCost = 0;
while (stash[0] + timeCost*robots[0] < blueprint.clay_cost) {
timeCost++;
}
// Build time
timeCost++;
// We don't have the time left to build this
if (time - timeCost >= 0) {
for (int j = 0; j < 4; j++) {
stash[j] = stash[j] + timeCost * robots[j];
}
stash[0] -= blueprint.clay_cost;
robots[1]++;
mostGeodes = bestGeode(blueprint, stash, robots, sum, time - timeCost);
memcpy(stash, stashCopy, 4*sizeof(int));
memcpy(robots, robotsCopy, 4*sizeof(int));
if (mostGeodes > max) {
max = mostGeodes;
}
}
// Obsidian robot
// Only if we have at least 1 clay robot
if (robots[1] > 0) {
timeCost = timeCost2 = 0;
while (stash[0] + timeCost*robots[0] < blueprint.obsidian_cost[0]) {
timeCost++;
}
while (stash[1] + timeCost2*robots[1] < blueprint.obsidian_cost[1]) {
timeCost2++;
}
timeCost = max(timeCost, timeCost2);
// build time
timeCost++;
if (time - timeCost >= 0) {
for (int j = 0; j < 4; j++) {
stash[j] = stash[j] + timeCost * robots[j];
}
stash[0] -= blueprint.obsidian_cost[0];
stash[1] -= blueprint.obsidian_cost[1];
robots[2]++;
mostGeodes = bestGeode(blueprint, stash, robots, sum, time - timeCost);
memcpy(stash, stashCopy, 4*sizeof(int));
memcpy(robots, robotsCopy, 4*sizeof(int));
if (mostGeodes > max) {
max = mostGeodes;
}
}
}
// Geode robot
// Only if we have at least 1 obsidian robot
if (robots[2] > 0) {
timeCost = timeCost2 = 0;
while (stash[0] + timeCost*robots[0] < blueprint.geode_cost[0]) {
timeCost++;
}
while (stash[2] + timeCost2*robots[2] < blueprint.geode_cost[1]) {
timeCost2++;
}
timeCost = max(timeCost, timeCost2);
// build time
timeCost++;
if (time - timeCost >= 0) {
for (int j = 0; j < 4; j++) {
stash[j] = stash[j] + timeCost * robots[j];
}
stash[0] -= blueprint.geode_cost[0];
stash[2] -= blueprint.geode_cost[1];
robots[3]++;
mostGeodes = bestGeode(blueprint, stash, robots, sum + (time - timeCost), time - timeCost);
memcpy(stash, stashCopy, 4*sizeof(int));
memcpy(robots, robotsCopy, 4*sizeof(int));
if (mostGeodes > max) {
max = mostGeodes;
}
}
}
if (max > bestMax) {
bestMax = max;
}
return max;
}