-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day11.c
191 lines (174 loc) · 6.2 KB
/
Day11.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "./utils.h"
typedef enum {
OP_ADD,
OP_MULT,
OP_SQUARE,
} OperationType;
typedef union {
struct { OperationType type; } common;
struct { OperationType type; int arg; } add;
struct { OperationType type; int arg; } mult;
struct { OperationType type; } square;
} Operation;
typedef struct {
Operation operation;
int test_modulus;
int test_monkey_true;
int test_monkey_false;
} MonkeyInfo;
typedef struct {
int* items;
size_t items_length;
size_t items_capacity;
} MonkeyItems;
static void add_item(MonkeyItems *monkey, int item) {
if (monkey->items_length == monkey->items_capacity) {
monkey->items_capacity *= 2;
monkey->items = realloc(monkey->items, monkey->items_capacity * sizeof(int));
}
monkey->items[monkey->items_length] = item;
monkey->items_length++;
}
static MonkeyItems copy_items(MonkeyItems monkey_items) {
size_t items_length = monkey_items.items_length;
size_t items_bytes = items_length * sizeof(int);
int *items = malloc(items_bytes);
memcpy(items, monkey_items.items, items_bytes);
return (MonkeyItems) {
.items = items,
.items_length = items_length,
.items_capacity = items_length,
};
}
static uint64_t apply_operation(Operation op, uint64_t x) {
switch (op.common.type) {
case OP_ADD:
return x + op.add.arg;
case OP_MULT:
return x * op.mult.arg;
case OP_SQUARE:
return x * x;
}
}
static void do_round(
int num_monkeys,
MonkeyInfo *monkeys,
MonkeyItems *monkeys_items,
int *monkey_counts,
int relief_factor,
int shared_modulus
) {
for (int monkey_idx = 0; monkey_idx < num_monkeys; monkey_idx++) {
MonkeyInfo *monkey = &monkeys[monkey_idx];
MonkeyItems *monkey_items = &monkeys_items[monkey_idx];
for (int item_idx = 0; item_idx < monkey_items->items_length; item_idx++) {
monkey_counts[monkey_idx]++;
uint64_t item = monkey_items->items[item_idx];
item = apply_operation(monkey->operation, item);
item /= relief_factor;
int new_item = item % shared_modulus;
int next_monkey;
if (new_item % monkey->test_modulus == 0) {
next_monkey = monkey->test_monkey_true;
} else {
next_monkey = monkey->test_monkey_false;
}
add_item(&monkeys_items[next_monkey], new_item);
}
monkey_items->items_length = 0;
}
}
int main(int argc, char **argv) {
START_TIMER();
char *line = NULL;
size_t line_len;
// hardcoded to number of monkeys in input
size_t monkeys_length = 8;
MonkeyInfo monkeys[monkeys_length];
MonkeyItems initial_items[monkeys_length];
int curr_monkey = 0;
while ((line_len = get_line(&line, stdin)) != -1) {
MonkeyInfo *monkey = &monkeys[curr_monkey];
if (is_prefix(line, "Monkey")) {
sscanf(line, "Monkey %d:", &curr_monkey);
size_t initial_capacity = 10;
int *items = malloc(initial_capacity * sizeof(int));
initial_items[curr_monkey] = (MonkeyItems) {
.items = items,
.items_length = 0,
.items_capacity = initial_capacity,
};
} else if (is_prefix(line, " Starting items:")) {
MonkeyItems *monkey_items = &initial_items[curr_monkey];
int i = 18;
int curr_item = 0;
while (i <= line_len) {
char c = i < line_len ? line[i] : ',';
if ('0' <= c && c <= '9') {
curr_item = curr_item * 10 + (c - '0');
i++;
} else {
add_item(monkey_items, curr_item);
curr_item = 0;
i += 2;
}
}
} else if (is_prefix(line, " Operation:")) {
char *op_raw = line + 19;
if (strcmp(op_raw, "old * old") == 0) {
monkey->operation = (Operation) {
.square = { .type = OP_SQUARE },
};
} else if (is_prefix(op_raw, "old *")) {
int arg;
sscanf(op_raw, "old * %d", &arg);
monkey->operation = (Operation) {
.mult = { .type = OP_MULT, .arg = arg },
};
} else {
int arg;
sscanf(op_raw, "old + %d", &arg);
monkey->operation = (Operation) {
.add = { .type = OP_ADD, .arg = arg },
};
}
} else if (is_prefix(line, " Test:")) {
sscanf(line, " Test: divisible by %d", &monkey->test_modulus);
} else if (is_prefix(line, " If true:")) {
sscanf(line, " If true: throw to monkey %d", &monkey->test_monkey_true);
} else {
sscanf(line, " If false: throw to monkey %d", &monkey->test_monkey_false);
}
}
int num_monkeys = curr_monkey + 1;
int shared_modulus = 1;
for (int i = 0; i < num_monkeys; i++) {
shared_modulus *= monkeys[i].test_modulus;
}
// part 1
MonkeyItems part1_items[num_monkeys];
int part1_monkey_counts[num_monkeys];
for (int i = 0; i < num_monkeys; i++) {
part1_items[i] = copy_items(initial_items[i]);
part1_monkey_counts[i] = 0;
}
for (int i = 0; i < 20; i++) {
do_round(num_monkeys, monkeys, part1_items, part1_monkey_counts, 3, shared_modulus);
}
qsort(part1_monkey_counts, num_monkeys, sizeof(int), cmp_int_desc);
printf("Part 1: %d\n", part1_monkey_counts[0] * part1_monkey_counts[1]);
// part 2
MonkeyItems part2_items[num_monkeys];
int part2_monkey_counts[num_monkeys];
for (int i = 0; i < num_monkeys; i++) {
part2_items[i] = copy_items(initial_items[i]);
part2_monkey_counts[i] = 0;
}
for (int i = 0; i < 10000; i++) {
do_round(num_monkeys, monkeys, part2_items, part2_monkey_counts, 1, shared_modulus);
}
qsort(part2_monkey_counts, num_monkeys, sizeof(int), cmp_int_desc);
printf("Part 2: %llu\n", (uint64_t) part2_monkey_counts[0] * part2_monkey_counts[1]);
END_TIMER();
return 0;
}