Merge remote-tracking branch '2020/master'

This commit is contained in:
Kienan Stewart 2022-05-16 23:29:03 -04:00
commit 834924850b
54 changed files with 15409 additions and 0 deletions

200
day1/input-part1 Normal file
View File

@ -0,0 +1,200 @@
1322
1211
1427
1428
1953
1220
1629
1186
1354
1776
1906
1849
1327
1423
401
1806
1239
1934
1256
1223
1504
1365
1653
1706
1465
1810
1089
1447
1983
1505
1763
1590
1843
1534
1886
1842
1878
1785
1121
1857
1496
1696
1863
1944
1692
1255
1572
1767
1509
1845
1479
1935
1507
1852
1193
1797
1573
1317
1266
1707
1819
925
1976
1908
1571
1646
1625
1719
1980
1970
1566
1679
1484
1818
1985
1794
1699
1530
1645
370
1658
1345
1730
1340
1281
1722
1623
1148
1545
1728
1325
1164
1462
1893
1736
160
1543
1371
1930
1162
2010
1302
1967
1889
1547
1335
1416
1359
1622
1682
1701
1939
1697
1436
1367
1119
1741
1466
1997
1856
1824
1323
1478
1963
1832
1748
1260
1244
1834
1990
1567
1147
1588
1694
1487
1151
1347
1315
1502
546
730
1742
1869
1277
1224
1169
1708
1661
174
1207
1801
1880
1390
1747
1215
1684
1498
1965
1933
1693
1129
1578
1189
1251
1727
1440
1178
746
1564
944
1822
1225
1523
1575
1185
37
1866
1766
1737
1800
1633
1796
1161
1932
1583
1395
1288
1991
229
1875
1540
1876
1191
1858
1713
1725
1955
1250
1987
1724

94
day1/main.zig Normal file
View File

@ -0,0 +1,94 @@
const std = @import("std");
pub fn main() !void {
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
var f = std.fs.File { .handle = try std.os.open("input-part1", std.os.O_RDONLY, 0) };
var buffer : [1024]u8 = undefined;
var expenses = std.ArrayList(u32).init(&allocator.allocator);
defer expenses.deinit();
var byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
defer byte_buffer.deinit();
var read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
while (read != 0) {
for (buffer) | v, k | {
if (std.ascii.isDigit(v)) {
try byte_buffer.append(v);
}
if (v == '\n') {
var x = atoi(byte_buffer.items[0..]);
//std.log.debug("{}", .{x});
try expenses.append(x);
// Set the position back to zero, without freeing existing memory
byte_buffer.deinit();
byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
}
}
read = try f.read(&buffer);
//std.log.info("Read {} bytes", .{read});
}
//std.log.info("{}", .{expenses.items.len});
part1(expenses.items[0..]);
part2(expenses.items[0..]);
}
fn part2(expenses : []u32) void {
var i : u32 = 0;
var elements : [3]u32 = undefined;
while (i < expenses.len) : (i += 1) {
var j : u32 = 0;
while (j < expenses.len) : (j += 1) {
var k : u32 = 0;
while (k < expenses.len) : (k += 1) {
if (k == j or k == 1) {
continue;
}
if (expenses[i] + expenses[j] + expenses[k] == 2020) {
elements[0] = expenses[i];
elements[1] = expenses[j];
elements[2] = expenses[k];
}
}
}
}
std.log.info("{} and {} and {} sum to {} and multiply to {}",
.{elements[0], elements[1], elements[2], elements[0] + elements[1] + elements[2],
elements[0] * elements[1] * elements[2]});
}
fn part1(expenses : []u32) void {
var i : u32 = 0;
var elements : [2]u32 = undefined;
while (i < expenses.len) : (i += 1) {
var j : u32 = 0;
while (j < expenses.len) : (j += 1) {
if (i == j) {
continue;
}
if (expenses[i] + expenses[j] == 2020) {
elements[0] = expenses[i];
elements[1] = expenses[j];
}
}
}
std.log.info("{} and {} sum to {} and multiply to {}",
.{elements[0], elements[1], elements[0] + elements[1],
elements[0] * elements[1]});
}
fn atoi(a: []u8) u32 {
var i : u32 = 0;
for(a) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, (v - 48) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i;
}

27
day10/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day10", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

94
day10/input Normal file
View File

@ -0,0 +1,94 @@
138
3
108
64
92
112
44
53
27
20
23
77
119
62
121
11
2
37
148
34
83
24
10
79
96
98
127
7
115
19
16
78
133
61
82
91
145
39
33
13
97
55
141
1
134
40
71
54
103
101
26
47
90
72
126
124
110
131
58
12
142
105
63
75
50
95
69
25
68
144
86
132
89
128
135
65
125
76
116
32
18
6
38
109
111
30
70
143
104
102
120
31
41
17

299
day10/src/main.zig Normal file
View File

@ -0,0 +1,299 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var it = std.mem.tokenize(contents, "\n");
var joltages = std.ArrayList(u32).init(gpa);
defer joltages.deinit();
while (it.next()) |line| {
try joltages.append(atoi(line));
}
var chain = try JoltageChain.construct_chain(gpa, joltages.items[0..]);
defer chain.deinit();
std.log.info("Product of one_diffs and three_diffs of joltage chain: {}",
.{chain.part_one()});
var permutations = try chain.calculate_permutations();
std.log.info("{} permutations", .{permutations});
}
const Tree = struct {
children : std.ArrayList(*Tree),
allocator: *std.mem.Allocator,
value : u32 = 0,
dirty : bool = true,
perms : u64 = 0,
fn init(allocator: *std.mem.Allocator, value: u32) !*Tree {
var self = try allocator.create(Tree);
errdefer allocator.destroy(self);
self.allocator = allocator;
self.value = value;
self.children = std.ArrayList(*Tree).init(allocator);
return self;
}
fn deinit(self: *Tree) void {
self.children.deinit();
self.allocator.destroy(self);
}
fn add_child(self: *Tree, child: *Tree) !void {
try self.children.append(child);
self.dirty = true;
}
fn find_child_by_value(self: *Tree, value: u32) ?*Tree {
if (self.value == value) {
return self;
}
for (self.children.items) |c| {
var t = c.find_child_by_value(value);
if (t) |_t| {
return _t;
}
}
return null;
}
// caching the calculation of the perm count makes it possible to
// finish reasonbly quickly when revisiting nodes that have already
// been seen
fn perm_count(self: *Tree) u64 {
if (!self.dirty) {
return self.perms;
}
var count : u64 = 0;
if (self.children.items.len == 0) {
count = 0; // No permutation, since have can only go one way
}
else if (self.children.items.len == 1) {
// We only have ourself
count = std.math.max(1, self.children.items[0].perm_count());
}
else {
for(self.children.items) |c| {
count += std.math.max(1, c.perm_count());
}
}
self.perms = count;
self.dirty = false;
return count;
}
fn print_tree(self: *Tree) void {
std.log.warn("{} children:\n", .{self.value});
for(self.children.items) |c| {
c.print_tree();
}
}
};
const JoltageChain = struct {
allocator: *std.mem.Allocator,
joltages : std.ArrayList(u32),
pub fn construct_chain(allocator: *std.mem.Allocator, j: []u32) !*JoltageChain {
var self = try allocator.create(JoltageChain);
errdefer allocator.destroy(self);
self.joltages = std.ArrayList(u32).init(allocator);
self.allocator = allocator;
// This has a side effect of modifying j...
std.sort.insertionSort(u32, j[0..], {}, comptime std.sort.asc(u32));
try self.joltages.append(0); // Always start at zero
var last_joltage : u32 = 0;
for (j) |x| {
if ((x-last_joltage)<4) {
try self.joltages.append(x);
last_joltage = x;
}
else {
break;
}
}
try self.joltages.append(last_joltage + 3);
return self;
}
pub fn deinit(self: *JoltageChain) void {
self.joltages.deinit();
self.allocator.destroy(self);
}
pub fn part_one(self: *JoltageChain) u32 {
var one_diffs : u32 = 0;
var three_diffs : u32 = 0;
for (self.joltages.items) |v, k| {
if (k == 0) {
continue;
}
var delta : u32 = v - self.joltages.items[k-1];
if (delta == 1) {
one_diffs += 1;
}
if (delta == 3) {
three_diffs += 1;
}
}
std.log.debug("Found {} one diffs, and {} three diffs",
.{one_diffs, three_diffs});
return one_diffs * three_diffs;
}
// this is a garbage way of doing it and just crushes CPU/memory
// it does work for small datasets though
pub fn calculate_permutations(self: *JoltageChain) !u32 {
var tree = try Tree.init(self.allocator, self.joltages.items[0]);
var current_node : *Tree = undefined;
var count : u32 = 0;
// Finding in the tree seems v. slow, will use a hash map for lookup
// it is also much easier to try and deinit
var map = std.hash_map.AutoHashMap(u32, *Tree).init(self.allocator);
try map.ensureCapacity(@intCast(u32, self.joltages.items.len));
map.putAssumeCapacityNoClobber(self.joltages.items[0], tree);
for (self.joltages.items) |v, k| {
var _t = map.get(v);
if (_t) |t| {
current_node = t;
}
else {
unreachable;
}
//std.log.warn("Current node: {}", .{current_node});
var n : usize = k+1;
while (n < self.joltages.items.len) : (n += 1) {
//std.log.warn("{}", .{n});
if ((self.joltages.items[n] - v) <= 3) {
var value = self.joltages.items[n];
_t = map.get(value);
if (_t) |t| {
try current_node.add_child(t);
//std.log.warn("Added existing child {} to {}", .{value, v});
}
else {
var t = try Tree.init(current_node.allocator, value);
try current_node.add_child(t);
map.putAssumeCapacityNoClobber(value, t);
//std.log.warn("Added new child {} to {}", .{value, v});
}
}
}
}
std.log.warn("tree count: {}", .{tree.perm_count()});
// Need to do some cleanup
var it = map.iterator();
while (it.next()) |kv| {
kv.value.deinit();
// don't remove from map, since it may modifying the underlying structure? (source?)
// and we're about to deinit it anyway
}
map.deinit();
return count;
}
};
test "joltage_chain" {
var joltages = [_]u32 {
16,
10,
15,
5,
1,
11,
7,
19,
6,
12,
4,
};
var chain = try JoltageChain.construct_chain(std.testing.allocator, joltages[0..]);
var diff = chain.part_one();
std.testing.expectEqual(diff, 7*5);
var perm = chain.calculate_permutations();
chain.deinit();
}
test "joltage_chain" {
var joltages = [_]u32 {
28,
33,
18,
42,
31,
14,
46,
20,
48,
47,
24,
23,
49,
45,
19,
38,
39,
11,
1,
32,
25,
35,
8,
17,
7,
9,
4,
2,
34,
10,
3,
};
var chain = try JoltageChain.construct_chain(std.testing.allocator, joltages[0..]);
var diff = chain.part_one();
std.testing.expectEqual(diff, 220);
var perm = chain.calculate_permutations();
chain.deinit();
}
fn atoi(a: []const u8) u32 {
var i : u32 = 0;
var mul : u32 = 1;
var start : usize = 0;
if (a[0] == '-' or a[0] == '+') {
start = 1;
if (a[0] == '-') {
//mul *= -1;
unreachable;
}
}
for(a[start..]) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, @as(u32, (v - 48)) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1 - start)));
}
//std.log.debug("0x{x} --> {}", .{a, i});
return i * mul;
}
test "atoi_regular" {
var i = atoi("1234");
std.testing.expectEqual(i, 1234);
}
test "atoi_pos" {
var i = atoi("+1234");
std.testing.expectEqual(i, 1234);
}

27
day11/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day11", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

98
day11/input Normal file
View File

@ -0,0 +1,98 @@
LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLLLLLLLLL.LLLLL.LLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLL.LLLLLL
LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
L.L...L...LL.LL.......LL...LL.L...LL..LL..L.......LLLLL.....LL..LLLL.L....L..L...L.LL....LL...L
LLLLL.LLLLL.LLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLL.LL.LLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LL.LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLL.LLL.LL.LLLLLLLLL.LLLL.LLLL.LLLL.L.LLLL
LLLLL.LLLL.LLLL.LLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLL.LLL.LL.LLLLLLLLLLLLLLLLLLL.LLLL.LLLLLL
.L.....L.LL..LLL.L..L...L.LLL.L...L.L.L.L.....L..L.......L.LLL...L.......L.LLLL......L.L.L...LL
LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL..LLLLLL.LLLL.LLLL.L.LL.LLLLLLLLL.LLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLLLLL.LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
.L..LLL.L...LL.....LL......LL...L...LL...L.L..L....L.L.L.LL.L........L....LL......L..LL..LL....
LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL
LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLL.LLLLL.LLL..LLLL.LLLLLL.LLLLLLLLLLL.LL.LLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL..L.LLL.LLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLL.LLLLLLLLLL.LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL
L.LLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLL
LLLL....L.......L..LLL...........L..L...LL..L.L.LLL...L.....LL..LL..L....L....L..LL..LL.L....L.
LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.L.LLLLLLLLLLLL.LLLLLL
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLL
LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLL.LLLLLLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLL..LLL.LLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLL.L.LLLL.LL.L.LL.LLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
.LL........L.....L.L.L.......LL.L.L.......LLL.........L....LL........L.L..L......L.LL......L..L
LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLL.L.LLLLLLLLLLLLLL
LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLL
LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.L.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLL..LLLLLL.LLLLLLLLL.LLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLL.LL.L.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
.L..L...L........L.......L.L.LL.LLLL...LLL.L.L..L.L....L.................L.L.L.L....L...L...L..
LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL.LLLL
LLLLL.LL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLL...LLL.......LL..L.L.L.L...L........LL..............L.L......L.......L..LL....L....LL...LL.
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLL.LLLLLL.L.LLLLLLL.LLLLLLLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLL.LLLLLL..LLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.L.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLL.LLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLLLLL.LLLLL.LLLL.L.LL.LLLLLL.LLLLLLLLLLL.LL.LLLLLLLLL.LLL.LL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LL.LL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLL.LLLLLL
LLLL.L...LL.......LL..L.....L.LL..L....L.L..L.......L..L......LLLLL..L.L..L......L...L.L...L.L.
LLLLL.LLL..LLLL.LLLLLL.LLLLL.LLL.LLLLL.L.LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLLLLLLL.LLLLLLLL..LLLLLL
LLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL.LLLLLL.LLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLL.LLLL.LLLLLLLLLLLL.LLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
L.L...............L..L.LLLL...L..L...LLL.......LLL.LL........L..LL..L..L...L.L.L.LL..LLLL.L.LL.
LLLLLLLL.L.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLL
LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL
LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL
L.LLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLL.LLLLLLL.LLLL.LLLL.LLLLLL
.L..LL.L.L..L...L....L......LLL......L.LL..L....L.LLLL.LL.....L.L.LL.L.....L......L.LL.........
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLL.LLLL..LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLL
LLLLL.LLL..LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLL..LLL.LLLLLLLLLLLLLLLL
.LLL......L.L.L......L.....LL......L.LLL.LLL..LL...L.L.......L..L.......L....L.....L.......LL..
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LL...L...........L...L..L......LL...........L...L.LL..LL....L....LLL.LLLL....LLL...LL..L..L...L
LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLL.LLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLL
.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL
LLLLL.LL.LLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLL.LLLLLLLLLLL.LLLLLLLL..LLLL.LLL..LLLLLLLLLLL
.......L...LL.L.....L.L.....LLL.L.......L.....LL.......L..LLL.....L.LL.L..........LL...........
LLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLLLL.LL.LL.LLL.LLLLLLLLLLLLLL.LLLL.LLLLLLLLLLL
LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLL.LLLLLL.LLLLLLLL..LLLLLLLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLL.LLLL.LLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLL.LLLL.LLLL.LLLL.LLLLLL
LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLL

482
day11/src/main.zig Normal file
View File

@ -0,0 +1,482 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var seatmap = try SeatMap.init(gpa);
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
try seatmap.add_line(line);
}
var changed : usize = 0;
changed = try seatmap.process_round();
while (changed != 0) {
//changed = try seatmap.process_round();
changed = try seatmap.process_round_part2();
}
std.log.info("{} occupied seats", .{seatmap.count_occupied()});
}
const NeighbourState = struct {
count: usize = 0,
occupied: usize = 0,
free: usize = 0,
};
const SeatMap = struct {
allocator: *std.mem.Allocator,
data: std.ArrayList(u8),
width: usize = 0,
height: usize = 0,
pub fn init(a: *std.mem.Allocator) !*SeatMap {
var self = try a.create(SeatMap);
errdefer a.destroy(self);
// if we use self.* = .{}; then we don't forget
// obligatory fields
// also, when using self.* = .{} the fields with
// defaults are properly initialized!!! it is
// an error to not use it.
self.* = .{
.allocator = a,
.data = std.ArrayList(u8).init(a),
};
return self;
}
pub fn deinit(self: *SeatMap) void {
self.data.deinit();
self.allocator.destroy(self);
}
pub fn count_occupied(self: *SeatMap) u64 {
var c: u64 = 0;
for (self.data.items) |i| {
if (i == '#') {
c += 1;
}
}
return c;
}
pub fn print(self: *SeatMap) !void {
var stdout = std.io.getStdOut();
var i : usize = 0;
while (i < self.height) : (i += 1) {
_ = try stdout.write(self.get_row(i));
_ = try stdout.write("\n");
}
}
pub fn get_row(self: *SeatMap, row: usize) []u8 {
return self.data.items[self.width*row..(self.width*row)+self.width];
}
pub fn add_line(self: *SeatMap, line: []const u8) !void {
if (self.width != 0) {
std.debug.assert(line.len == self.width);
}
else {
self.width = line.len;
}
try self.data.appendSlice(line[0..]);
self.height += 1;
}
// returns the number of seats changed
pub fn process_round(self: *SeatMap) !u64 {
// First, since operations happen concurrently,
// we mark all of our changes to a temporary buffer
var buffer = try self.allocator.alloc(u8, self.data.items.len);
defer self.allocator.free(buffer);
// Iterate above (row, col) pairs
var row : usize = 0;
var n_changed : u64 = 0;
while (row < self.height) : (row += 1) {
var col : usize = 0;
while (col < self.width) : (col += 1) {
if (self.index_of(row, col)) |i| {
buffer[i] = self.get_new_seat_state(row, col, i);
if (buffer[i] != self.data.items[i]) {
n_changed += 1;
}
}
}
}
// Copy buffer to self.data.items
std.mem.copy(u8, self.data.items, buffer);
return n_changed;
}
pub fn get_new_seat_state(self: *SeatMap, row: usize, col: usize, index: usize) u8 {
// Floor remains unchanged
var c = self.data.items[index];
var new_c : u8 = undefined;
if (c == '.') {
new_c = '.';
}
// this gives us a struct w/ .count, .occupied, .free
var neighbour_state = self.get_neighbour_state(row, col);
if (c == 'L') {
if (neighbour_state.occupied == 0) {
new_c = '#';
}
else {
new_c = c;
}
}
if (c == '#') {
if (neighbour_state.occupied >= 4) {
new_c = 'L';
}
else {
new_c = c;
}
}
//std.log.debug("({},{}) was '{c}' and will be '{c}'. {} neighbors, {} occupied",
// .{row, col, c, new_c, neighbour_state.count, neighbour_state.occupied});
return new_c;
}
pub fn get_neighbour_state(self: *SeatMap, row: usize, col: usize) NeighbourState {
var r: usize = switch(row) {
0 => row,
else => row - 1,
};
var count: usize = 0;
var free: usize = 0;
var occupied: usize = 0;
while (r <= row+1) : (r += 1) {
var c: usize = switch(col) {
0 => col,
else => col - 1,
};
while (c <= col+1) : (c += 1) {
if (row == r and col == c) {
continue;
}
if (self.index_of(r, c)) |i| {
if (self.data.items[i] == '.') {
// Floor spots don't contribute to neighbour,
// free, or occupied counts.
continue;
}
count += 1;
if (self.data.items[i] == '#') {
occupied += 1;
}
else {
free += 1;
}
}
}
}
return NeighbourState {
.count = count,
.free = free,
.occupied = occupied,
};
}
// returns the number of seats changed
pub fn process_round_part2(self: *SeatMap) !u64 {
// First, since operations happen concurrently,
// we mark all of our changes to a temporary buffer
var buffer = try self.allocator.alloc(u8, self.data.items.len);
defer self.allocator.free(buffer);
// Iterate above (row, col) pairs
var row : usize = 0;
var n_changed : u64 = 0;
while (row < self.height) : (row += 1) {
var col : usize = 0;
while (col < self.width) : (col += 1) {
if (self.index_of(row, col)) |i| {
buffer[i] = self.get_new_seat_state_round2(row, col, i);
if (buffer[i] != self.data.items[i]) {
n_changed += 1;
}
}
}
}
// Copy buffer to self.data.items
std.mem.copy(u8, self.data.items, buffer);
return n_changed;
}
pub fn get_new_seat_state_round2(self: *SeatMap, row: usize, col: usize, index: usize) u8 {
// Floor remains unchanged
var c = self.data.items[index];
var new_c : u8 = undefined;
if (c == '.') {
new_c = '.';
}
// this gives us a struct w/ .count, .occupied, .free
var neighbour_state = self.get_neighbour_state_round2(row, col);
if (c == 'L') {
if (neighbour_state.occupied == 0) {
new_c = '#';
}
else {
new_c = c;
}
}
if (c == '#') {
if (neighbour_state.occupied >= 5) {
new_c = 'L';
}
else {
new_c = c;
}
}
//std.log.debug("({},{}) was '{c}' and will be '{c}'. {} neighbors, {} occupied",
// .{row, col, c, new_c, neighbour_state.count, neighbour_state.occupied});
return new_c;
}
pub fn get_neighbour_state_round2(self: *SeatMap, row: usize, col: usize) NeighbourState {
var count: usize = 0;
var free: usize = 0;
var occupied: usize = 0;
var direction_vectors = [_][2]i64 {
[_]i64{-1, -1}, // up and left,
[_]i64{-1, 0}, // left
[_]i64{-1, 1}, // down and left,
[_]i64{0, 1}, // down
[_]i64{1, 1}, // right and down
[_]i64{1, 0}, // right
[_]i64{1, -1}, // right and up,
[_]i64{0, -1}, // up
};
var row_signed = @intCast(i64, row);
var col_signed = @intCast(i64, col);
for (direction_vectors) |dv| {
var space_count : i64 = 0;
var has_neighbour: bool = false;
var last_neighbour_was_occupied = false;
while (true) {
space_count += 1;
var r : i64 = row_signed + (dv[0]*space_count);
var c : i64 = col_signed + (dv[1]*space_count);
if (r < 0 or c < 0) {
// invalid spot with negative indices
break;
}
if(self.index_of(@intCast(usize, r), @intCast(usize, c))) |index| {
if (self.data.items[index] == '.') {
// We see through floor spaces
continue;
}
else {
has_neighbour = true;
if (self.data.items[index] == '#') {
last_neighbour_was_occupied = true;
}
break;
}
}
else {
// The index was not valid, so we're out of bounds in some way
break;
}
}
if (has_neighbour) {
count += 1;
if (last_neighbour_was_occupied) {
occupied += 1;
}
else {
free += 1;
}
}
}
return NeighbourState {
.count = count,
.free = free,
.occupied = occupied,
};
}
pub fn index_of(self: *SeatMap, row: usize, col: usize) ?usize {
if (col >= self.width) {
return null;
}
if (row >= self.height) {
return null;
}
var i = (row*self.width) + col;
if (i < 0 or i >= self.data.items.len) {
return null;
}
return i;
}
};
test "part_one" {
var d = [_][]const u8 {
"L.LL.LL.LL",
"LLLLLLL.LL",
"L.L.L..L..",
"LLLL.LL.LL",
"L.LL.LL.LL",
"L.LLLLL.LL",
"..L.L.....",
"LLLLLLLLLL",
"L.LLLLLL.L",
"L.LLLLL.LL",
};
var print = true;
var stdout = std.io.getStdOut();
var sm = try SeatMap.init(std.testing.allocator);
defer sm.deinit();
for (d) |l| {
try sm.add_line(l[0..]);
}
var states = [_][]const u8 {
// 0
"L.LL.LL.LLLLLLLLL.LLL.L.L..L..LLLL.LL.LLL.LL.LL.LLL.LLLLL.LL..L.L.....LLLLLLLLLLL.LLLLLL.LL.LLLLL.LL",
// 1
"#.##.##.#########.###.#.#..#..####.##.###.##.##.###.#####.##..#.#.....###########.######.##.#####.##",
// 2
"#.LL.L#.###LLLLLL.L#L.L.L..L..#LLL.LL.L##.LL.LL.LL#.LLLL#.##..L.L.....#LLLLLLLL##.LLLLLL.L#.#LLLL.##",
// 3
"#.##.L#.###L###LL.L#L.#.#..#..#L##.##.L##.##.LL.LL#.###L#.##..#.#.....#L######L##.LL###L.L#.#L###.##",
// 4
"#.#L.L#.###LLL#LL.L#L.L.L..#..#LLL.##.L##.LL.LL.LL#.LL#L#.##..L.L.....#L#LLLL#L##.LLLLLL.L#.#L#L#.##",
// 5
"#.#L.L#.###LLL#LL.L#L.#.L..#..#L##.##.L##.#L.LL.LL#.#L#L#.##..L.L.....#L#L##L#L##.LLLLLL.L#.#L#L#.##"
};
// Confirm that initial map is correct
std.testing.expect(std.mem.eql(u8, sm.data.items, states[0]));
if (print) {
_ = try stdout.write("\nInitial map:\n");
try sm.print();
_ = try stdout.write("\n");
}
var round: u64 = 0;
var changed = try sm.process_round();
while (changed != 0) {
round += 1;
var matches = std.mem.eql(u8, sm.data.items, states[round]);
//std.log.warn("Round {} matches expected state: {}", .{round, matches});
//std.log.warn("len {}: {}", .{sm.data.items.len, sm.data.items});
//std.log.warn("len {}: {}", .{states[round].len, states[round]});
//std.log.warn("index of first diff {}",
// .{std.mem.indexOfDiff(u8, sm.data.items, states[round])});
std.testing.expect(matches);
if (print) {
var title = try std.fmt.allocPrint(std.testing.allocator, "\nRound {}:\n",
.{round});
_ = try stdout.write(title);
std.testing.allocator.free(title);
try sm.print();
_ = try stdout.write("\n");
}
changed = try sm.process_round();
}
if (print) {
_ = try stdout.write("Final state: \n");
try sm.print();
_ = try stdout.write("\n");
}
std.testing.expect(std.mem.eql(u8, sm.data.items, states[round]));
var n_occupied = sm.count_occupied();
std.testing.expectEqual(n_occupied, 37);
}
test "part two" {
var d = [_][]const u8 {
"L.LL.LL.LL",
"LLLLLLL.LL",
"L.L.L..L..",
"LLLL.LL.LL",
"L.LL.LL.LL",
"L.LLLLL.LL",
"..L.L.....",
"LLLLLLLLLL",
"L.LLLLLL.L",
"L.LLLLL.LL",
};
var print = true;
var stdout = std.io.getStdOut();
var sm = try SeatMap.init(std.testing.allocator);
defer sm.deinit();
for (d) |l| {
try sm.add_line(l[0..]);
}
var states = [_][]const u8 {
// 0
"L.LL.LL.LLLLLLLLL.LLL.L.L..L..LLLL.LL.LLL.LL.LL.LLL.LLLLL.LL..L.L.....LLLLLLLLLLL.LLLLLL.LL.LLLLL.LL",
// 1
"#.##.##.#########.###.#.#..#..####.##.###.##.##.###.#####.##..#.#.....###########.######.##.#####.##",
// 2
"#.LL.LL.L##LLLLLL.LLL.L.L..L..LLLL.LL.LLL.LL.LL.LLL.LLLLL.LL..L.L.....LLLLLLLLL##.LLLLLL.L#.LLLLL.L#",
// 3
"#.L#.##.L##L#####.LLL.#.#..#..##L#.##.###.##.#L.###.#####.#L..#.#.....LLL####LL##.L#####.L#.L####.L#",
// 4
"#.L#.L#.L##LLLLLL.LLL.L.L..#..##LL.LL.L#L.LL.LL.L##.LLLLL.LL..L.L.....LLLLLLLLL##.LLLLL#.L#.L#LL#.L#",
// 5
"#.L#.L#.L##LLLLLL.LLL.L.L..#..##L#.#L.L#L.L#.#L.L##.L####.LL..#.#.....LLL###LLL##.LLLLL#.L#.L#LL#.L#",
// 6
"#.L#.L#.L##LLLLLL.LLL.L.L..#..##L#.#L.L#L.L#.LL.L##.LLLL#.LL..#.L.....LLL###LLL##.LLLLL#.L#.L#LL#.L#",
};
// Confirm that initial map is correct
std.testing.expect(std.mem.eql(u8, sm.data.items, states[0]));
if (print) {
_ = try stdout.write("\nInitial map:\n");
try sm.print();
_ = try stdout.write("\n");
}
var round: u64 = 0;
var changed = try sm.process_round();
while (changed != 0) {
round += 1;
var matches = std.mem.eql(u8, sm.data.items, states[round]);
//std.log.warn("Round {} matches expected state: {}", .{round, matches});
//std.log.warn("len {}: {}", .{sm.data.items.len, sm.data.items});
//std.log.warn("len {}: {}", .{states[round].len, states[round]});
//std.log.warn("index of first diff {}",
// .{std.mem.indexOfDiff(u8, sm.data.items, states[round])});
std.testing.expect(matches);
if (print) {
var title = try std.fmt.allocPrint(std.testing.allocator, "\nRound {}:\n",
.{round});
_ = try stdout.write(title);
std.testing.allocator.free(title);
try sm.print();
_ = try stdout.write("\n");
}
changed = try sm.process_round_part2();
}
if (print) {
_ = try stdout.write("Final state: \n");
try sm.print();
_ = try stdout.write("\n");
}
std.testing.expect(std.mem.eql(u8, sm.data.items, states[round]));
var n_occupied = sm.count_occupied();
std.testing.expectEqual(n_occupied, 26);
}

27
day12/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day12", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

750
day12/input Normal file
View File

@ -0,0 +1,750 @@
W1
F91
W3
F82
N1
E2
N4
R90
F25
N2
F75
E4
R90
F91
R90
F64
L90
E1
L90
S2
L180
S2
E3
N2
E5
L90
N2
R90
F30
L90
N1
F37
S1
E5
F3
E2
F59
W3
L270
S5
W5
S4
F84
N5
R180
E4
F31
L90
E2
F77
L90
N5
F17
N4
N4
W2
F45
S1
F92
E1
F33
L270
F21
L90
E1
F81
N5
F20
E2
R90
N4
W3
L180
S2
F33
E5
F87
R90
N2
F29
E3
S4
L90
E4
R90
S2
F65
L90
F69
W2
N4
F73
R180
S3
R90
N3
R90
W1
L180
F96
N3
W2
L180
S5
F29
E3
S4
W1
F53
E1
L90
E5
F26
E3
R270
E2
S2
W2
F43
W2
F53
F74
R180
N5
W3
S4
F70
R90
W4
F56
L90
S5
R180
E4
S4
F80
S1
F91
R90
S4
F88
L90
S5
R90
E2
S1
F37
N1
R90
F92
W5
F14
N2
E5
S2
F89
L180
N4
E4
L90
F32
E4
R90
F99
N3
L180
F78
S1
R270
W1
F11
S4
F47
N4
L90
F17
R90
E4
S3
F14
S1
R90
N3
F52
W3
S5
L180
F41
R90
F62
W1
R90
E4
F1
W5
F86
W1
N5
F5
S1
E5
F67
W3
F97
E1
L90
S2
E1
R90
F82
E3
N2
F16
L90
W2
F35
R180
N2
E3
N4
W4
F13
S5
E1
S5
L90
E5
F65
E5
L90
S4
E3
W4
N1
R90
N5
F93
R90
S5
R90
L90
F86
E3
F90
E4
N2
E4
R180
W5
R90
E3
F98
F56
L90
F68
L90
N3
F35
S1
W5
F25
L180
F7
R270
F84
R90
S4
E5
S3
L270
F33
W3
R90
W5
N3
E4
R90
W2
F100
E5
S2
L90
F6
E1
L90
S1
F17
N3
E1
S3
F78
R90
W5
N4
L90
F13
W5
R90
F7
F74
R90
E4
F28
L90
S5
R90
F77
S2
E2
N3
F30
E1
R90
W2
S2
F62
E2
L90
E2
F56
L90
F61
S1
F14
W3
F23
L90
E3
S3
L270
S5
F97
E5
S1
F96
W2
F61
L180
F25
L90
W4
F100
W4
F14
W4
S5
R90
F67
E1
R90
F89
W5
S3
W2
N2
F64
L180
S4
R270
F47
E1
S1
E4
N1
R90
N2
E5
F97
N3
E5
S5
R180
E5
F34
L90
W1
W1
N3
R90
F17
N1
F75
S4
W5
N2
W1
N2
L90
W3
N2
F1
N1
W3
R90
F18
E4
N4
F18
N4
F73
W4
F61
W3
R90
N5
L90
N4
F70
E4
F10
L90
F33
N5
L90
W4
L180
E2
F41
E1
S4
E4
L90
F28
N2
W4
S2
F86
R180
S3
W3
S3
W2
F55
W1
F18
W2
F18
L90
S4
W1
L90
F47
L90
S4
F39
N5
L180
S3
W5
F95
W1
R90
E2
N3
L90
S4
F77
S1
W4
S5
E4
R90
W1
R90
W3
W2
N4
F1
W1
N5
F55
E4
N4
W5
L90
F90
E4
R90
E2
R90
S5
F44
N2
E3
R90
F64
W1
L180
L180
F55
L90
F15
S2
E1
R270
F10
R90
W4
F43
E1
F7
N2
W3
F10
N1
L270
N2
L90
E2
R90
F28
W2
N5
F70
R90
E3
E3
F75
W4
L90
S2
R90
F83
L270
E1
F87
R180
N3
L90
F30
L90
E1
N5
F87
N4
R90
F51
W5
N3
R90
S5
F98
W4
N2
E2
L90
E4
S1
E5
F60
N1
L180
E1
F10
R90
W5
F90
W5
F9
S1
W3
F9
E2
S4
L180
F61
W2
N3
F35
R90
E4
N3
W4
L90
E1
L90
S1
F62
S5
W1
N5
L180
F76
W3
L90
W4
L90
N2
E3
N5
E1
N2
F13
S1
F20
W5
L90
S1
F89
S3
L90
W2
L90
F48
W5
N1
R90
F93
L90
E4
L90
N2
F100
W5
S5
W1
S1
E2
S1
W4
R90
S2
F99
W2
F80
L90
F78
N4
L90
F67
S1
L90
F23
W3
N1
W5
F76
R270
F51
L90
W2
N1
E3
S3
L90
F83
L90
F46
S5
L180
N3
E3
F49
E5
N4
W5
L90
E3
R90
S4
F54
E1
F49
N4
L180
E3
L90
R90
F95
W2
N2
F12
R180
E4
R90
N5
L180
S3
W3
S1
F22
W1
F18
L90
F35
R90
F3
S4
L90
F53
W5
F58
L90
S2
F48
S5
R180
F67
L180
W1
S3
L90
F33
F34
R90
F54
W2
L180
S5
W4
R90
F80
W4
S1
W4
F35
E1
F48
N3
L270
F78
N4
S4
F11
S1
W3
L90
W1
F26
R180
E3
F43
S4
R180
W3
N2
F80
W4
F29
W5
W1
R270
N3
L90
F17
W4
F49
S4
S1
F47

197
day12/src/main.zig Normal file
View File

@ -0,0 +1,197 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
defer gpa.free(contents);
var ship = ShipPosition{};
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
ship.update(line[0], try std.fmt.parseInt(i64, line[1..], 10));
std.log.debug("After '{}', ship at ({}, {}) facing {}",
.{line, ship.position[0], ship.position[1], ship.facing});
}
std.log.info("Ship is at ({},{}) facing {}. It has travalled {} manhattan distance from start",
.{ship.position[0], ship.position[1], ship.facing,
ship.manhattan_distance_from([_]i64{0, 0})});
// Part 2
ship = ShipPosition{};
it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
ship.update_part2(line[0], try std.fmt.parseInt(i64, line[1..], 10));
std.log.debug("After '{}', ship at ({}, {}), with waypoint ({}, {})",
.{line, ship.position[0], ship.position[1],
ship.waypoint[0], ship.waypoint[1]});
}
std.log.info("Ship is at ({},{}) facing {} and waypoint ({}, {}). It has travalled {} manhattan distance from start",
.{ship.position[0], ship.position[1], ship.facing,
ship.waypoint[0], ship.waypoint[1],
ship.manhattan_distance_from([_]i64{0, 0})});
}
const ShipPosition = struct {
facing : i64 = 90,
position : [2]i64 = [_]i64{0, 0},
waypoint: [2]i64 = [_]i64{10, 1},
pub fn update(self: *ShipPosition, command: u8, value: i64) void {
switch(command) {
'N' => {
self.position[1] += value;
},
'S' => {
self.position[1] -= value;
},
'E' => {
self.position[0] += value;
},
'W' => {
self.position[0] -= value;
},
'R' => {
self.facing += value;
},
'L' => {
self.facing -= value;
},
'F' => {
std.log.debug("Facing before moving forward: {}", .{self.facing});
while (self.facing < 0) {
self.facing += 360;
}
if (self.facing >= 360) {
self.facing = @intCast(i64, @mod(self.facing, 360));
}
std.log.debug("Facing after normalizing, before moving forward: {}",
.{self.facing});
var c : u8 = switch(self.facing) {
0 => 'N',
90 => 'E',
180 => 'S',
270 => 'W',
else => {
std.log.warn("Unexpected facing {}", .{self.facing});
unreachable;
},
};
self.update(c, value);
},
else => {
std.log.warn("Unknown command: '{}'", .{command});
},
}
}
pub fn manhattan_distance_from(self: *ShipPosition, from: [2]i64) u64 {
return (std.math.absCast(self.position[0] - from[0])) +
(std.math.absCast(self.position[1] - from [1]));
}
pub fn update_part2(self: *ShipPosition, command: u8, value: i64) void {
switch(command) {
'N' => {
self.waypoint[1] += value;
},
'S' => {
self.waypoint[1] -= value;
},
'E' => {
self.waypoint[0] += value;
},
'W' => {
self.waypoint[0] -= value;
},
'R' => {
// Rotate around the ship
self.waypoint = rotate_point(self.waypoint, -value);
},
'L' => {
// Rotate around the ship
self.waypoint = rotate_point(self.waypoint, value);
},
'F' => {
// For forward value times towards the waypoint.
self.position[0] += self.waypoint[0] * value;
self.position[1] += self.waypoint[1] * value;
// Waypoint stays relative to ship
//self.waypoint[0] = self.position[0] + self.waypoint[0];
//self.waypoint[1] = self.position[1] + self.waypoint[1];
},
else => {
std.log.warn("Unknown command: '{}'", .{command});
},
}
}
};
pub fn rotate_point(point: [2]i64, degrees: i64) [2]i64 {
var radians : f64 = (@intToFloat(f64, degrees) * std.math.pi) / 180.0;
var old_x = @intToFloat(f64, point[0]);
var old_y = @intToFloat(f64, point[1]);
var x : f64 = old_x * std.math.cos(radians) - old_y * std.math.sin(radians);
var y : f64 = old_y * std.math.cos(radians) + old_x * std.math.sin(radians);
return [2]i64 {
@floatToInt(i64, std.math.round(x)),
@floatToInt(i64, std.math.round(y)),
};
}
test "part_one" {
var data = [_][]const u8 {
"F10",
"N3",
"F7",
"R90",
"F11",
};
var ship = ShipPosition{};
for (data) |d| {
ship.update(d[0], try std.fmt.parseInt(i64, d[1..], 10));
}
std.testing.expectEqual(ship.position[0], 17);
std.testing.expectEqual(ship.position[1], -8);
std.testing.expectEqual(ship.manhattan_distance_from([_]i64{0, 0}), 25);
}
test "part_two" {
var data = [_][]const u8 {
"F10",
"N3",
"F7",
"R90",
"F11",
};
var ship = ShipPosition{};
for (data) |d| {
ship.update_part2(d[0], try std.fmt.parseInt(i64, d[1..], 10));
std.log.warn("After '{}', ship at ({}, {}), with waypoint ({}, {})",
.{d, ship.position[0], ship.position[1],
ship.waypoint[0], ship.waypoint[1]});
}
std.testing.expectEqual(ship.position[0], 214);
std.testing.expectEqual(ship.position[1], -72);
std.testing.expectEqual(ship.manhattan_distance_from([_]i64{0, 0}), 286);
}
// test "rotate" {
// var point = [_]i64 {4,-3};
// var p = rotate_point(point, 90);
// std.testing.expectEqual(p[0], 3);
// std.testing.expectEqual(p[1], 4);
// p = rotate_point(point, 180);
// std.testing.expectEqual(p[0], -4);
// std.testing.expectEqual(p[1], 3);
// p = rotate_point(point, 270);
// std.testing.expectEqual(p[0], -4);
// std.testing.expectEqual(p[1], 3);
// }

27
day13/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day13", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

2
day13/input Normal file
View File

@ -0,0 +1,2 @@
1005595
41,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,37,x,x,x,x,x,557,x,29,x,x,x,x,x,x,x,x,x,x,13,x,x,x,17,x,x,x,x,x,23,x,x,x,x,x,x,x,419,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,19

467
day13/src/main.zig Normal file
View File

@ -0,0 +1,467 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
defer gpa.free(contents);
var buses = std.ArrayList(Bus).init(gpa);
defer buses.deinit();
var it = std.mem.tokenize(contents, "\n");
var estimated_arrival_at_bus_station: u64 = 0;
if (it.next()) |l| {
estimated_arrival_at_bus_station = try std.fmt.parseUnsigned(u64, l, 10);
}
if (it.next()) |l| {
var bus_it = std.mem.tokenize(l, ",");
var offset: u64 = 0;
while (bus_it.next()) |b| : (offset += 1) {
if (b[0] == 'x') {
continue;
}
var a = std.fmt.parseUnsigned(u64, b, 10) catch continue;
var bus = Bus{.id = a, .offset = offset};
std.log.debug("Bus: {}", .{bus});
try buses.append(bus);
}
}
var earliest_bus = find_earliest_bus_after(buses.items, estimated_arrival_at_bus_station);
var wait_time = earliest_bus.earliest_departure_after(estimated_arrival_at_bus_station) - estimated_arrival_at_bus_station;
std.log.info("Earliest bus '{}' will depart at {}, a wait of {}.",
.{earliest_bus.id, earliest_bus.earliest_departure_after(estimated_arrival_at_bus_station), wait_time});
std.log.info("Part one: {}", .{earliest_bus.id * wait_time});
// Part 2
// the challenge warns us it will "surely be" above 100000000000000
// 18446744073709551615 <-- u64 max
//var est_start : u64 = buses.items[0].earliest_departure_after(estimated_arrival_at_bus_station);
//est_start = 100000733946084;
est_start = 101775718927832;
// From Est start 101775718927832
// To 140354342739376 took 180.75m of CPU time,
// 598411311431841 <-- sol'n after using sieve + lcm
// It would have probably taken another (180.75)*3.26 = 9.82 hours to get there...
// lcm + sieve: ~ 0.003s, and starts working from 0.
var prize_start : u64 = 0;
var act = std.os.Sigaction {
.sigaction = handle_sigusr,
//.sigaction = std.os.linux.SIG_IGN,
.mask = std.os.empty_sigset,
.flags = 0,
};
std.os.sigaction(10, &act, null);
// Brute force approach
// while (prize_start == 0) : (est_start += buses.items[0].id) {
// var matches = true;
// for (buses.items[1..]) |b, k| {
// if (@mod(est_start + b.offset, b.id) % b.id != 0) {
// matches = false;
// //std.log.debug("Bus {} failed iteration starting at {}", .{b.id, est_start});
// break;
// }
// }
// if (matches) {
// prize_start = est_start;
// }
// }
prize_start = try find_bus_offset_departure(buses.items[0..], gpa);
std.log.info("Earliest depature match prize condition: {}", .{prize_start});
}
var t_last_sigusr : i128 = 0;
var est_start : u64 = 0;
var last_start_value : u64 = 0;
fn handle_sigusr(sig: i32, info: *std.os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void {
var values_per_second_avg : f64 = 0.0;
if (last_start_value == 0) {
std.log.warn("Last {}", .{est_start});
}
else {
var calcs_done : f64 = @intToFloat(f64, (est_start - last_start_value)/41);
values_per_second_avg = calcs_done
/ @intToFloat(f64, std.time.nanoTimestamp() - t_last_sigusr);
std.log.warn("Last {}, {}/s avg - {} calcs done",
.{est_start, values_per_second_avg * std.time.ns_per_s, calcs_done});
}
last_start_value = est_start;
t_last_sigusr = std.time.nanoTimestamp();
}
fn find_earliest_bus_after(buses: []Bus, time: u64) Bus {
var earliest_bus_index : u64 = 0;
var earliest_departure_time : u64 = std.math.maxInt(u64);
for (buses) |bus, k| {
var departs_at : u64 = Bus.earliest_departure(bus.id, time);
if (departs_at < earliest_departure_time) {
earliest_bus_index = k;
earliest_departure_time = departs_at;
}
}
return buses[earliest_bus_index];
}
const Bus = struct {
id: u64,
offset: u64 = 0,
pub fn earliest_departure_after(self: *Bus, time: u64) u64 {
return Bus.earliest_departure(self.id, time);
}
pub fn earliest_departure(id: u64, time: u64) u64 {
var d : u64 = ((time / id)+1) * id;
std.debug.assert(d >= time);
return d;
}
};
fn find_bus_offset_departure(buses: []Bus, a: *std.mem.Allocator) !u64 {
var list_pos : usize = 0;
var t : u64 = 0;
var increment : u64 = buses[0].id;
var bus_ids = try a.alloc(u64, buses.len);
defer a.free(bus_ids);
for (buses) |b, k| {
bus_ids[k] = b.id;
}
while (list_pos < (buses.len-1)) : (t += increment) {
// Check if (t+buses[list_pos+1].offset)%buses[list_pos+1].id == 0
if (@mod(t+buses[list_pos+1].offset, buses[list_pos+1].id) == 0) {
// Our bus arrives here, great.
increment = try lcm_by_factorization(std.testing.allocator, bus_ids[0..list_pos+2]);
std.log.debug("Bus {} (offset: {}) in pos {} at {}. New increment {}",
.{buses[list_pos+1].id, buses[list_pos+1].offset, list_pos+1, t, increment});
list_pos += 1;
}
}
// If we left the loop, we incremented, so decrement
t -= increment;
return t;
}
test "departure" {
var a : u64 = 939;
std.testing.expectEqual(Bus.earliest_departure(59, 939), 944);
}
test "prize_start" {
// 7,13,x,x,59,x,31,19
var buses = [_]Bus {
Bus{.id = 7},
Bus{.id = 13, .offset = 1},
Bus{.id = 59, .offset = 4},
Bus{.id = 31, .offset = 6},
Bus{.id = 19, .offset = 7},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 1068781);
// No LCM version, because the example's prize_start if based on the
// arbitrary offset.
}
test "prize_ex1" {
//17,x,13,19
var buses = [_]Bus {
Bus{.id = 17},
Bus{.id = 13, .offset = 2},
Bus{.id = 19, .offset = 3},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 3417);
// LCM version
prize_start = try find_bus_offset_departure(buses[0..], std.testing.allocator);
std.testing.expectEqual(prize_start, 3417);
}
test "prize_ex2" {
// 67,7,59,61
var buses = [_]Bus {
Bus{.id = 67},
Bus{.id = 7, .offset = 1},
Bus{.id = 59, .offset = 2},
Bus{.id = 61, .offset = 3},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 754018);
// LCM version
prize_start = try find_bus_offset_departure(buses[0..], std.testing.allocator);
std.testing.expectEqual(prize_start, 754018);
}
test "prize_ex3" {
// 67,x,7,59,61
var buses = [_]Bus {
Bus{.id = 67},
Bus{.id = 7, .offset = 2},
Bus{.id = 59, .offset = 3},
Bus{.id = 61, .offset = 4},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 779210);
// LCM version
prize_start = try find_bus_offset_departure(buses[0..], std.testing.allocator);
std.testing.expectEqual(prize_start, 779210);
}
test "prize_ex4" {
// 67,7,x, 59,61
var buses = [_]Bus {
Bus{.id = 67},
Bus{.id = 7, .offset = 1},
Bus{.id = 59, .offset = 3},
Bus{.id = 61, .offset = 4},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 1261476);
// LCM version
prize_start = try find_bus_offset_departure(buses[0..], std.testing.allocator);
std.testing.expectEqual(prize_start, 1261476);
}
test "prize_ex5" {
// 1789,37,47,1889
var buses = [_]Bus {
Bus{.id = 1789},
Bus{.id = 37, .offset = 1},
Bus{.id = 47, .offset = 2},
Bus{.id = 1889, .offset = 3},
};
est_start = 0;
var prize_start : u64 = 0;
while (prize_start == 0) : (est_start += buses[0].id) {
var matches = true;
for (buses[1..]) |b, k| {
if ((est_start + b.offset) % b.id != 0) {
matches = false;
break;
}
}
if (matches) {
prize_start = est_start;
}
}
std.log.warn("Earliest depature match prize condition: {}", .{prize_start});
std.testing.expectEqual(prize_start, 1202161486);
// LCM version
prize_start = try find_bus_offset_departure(buses[0..], std.testing.allocator);
std.testing.expectEqual(prize_start, 1202161486);
}
fn lcm_by_factorization(allocator: *std.mem.Allocator, values: []u64) !u64 {
var highest_powers = std.hash_map.AutoHashMap(u64, u64).init(allocator);
defer highest_powers.deinit();
// For each item in the set, get the prime factorization of the item's value
for (values) |v| {
var list = try prime_factors(v, allocator);
defer list.deinit();
for (list.items) |factor| {
std.log.warn("{}^{} is a prime factor of {}", .{factor.base, factor.power, v});
if (highest_powers.get(factor.base)) |other_power| {
if (factor.power > other_power) {
highest_powers.putAssumeCapacity(factor.base, factor.power);
}
}
else {
try highest_powers.put(factor.base, factor.power);
}
}
}
var lcm : u64 = 1;
var it = highest_powers.iterator();
while (it.next()) |entry| {
std.log.warn("{}^{} is part of the LCM", .{entry.key, entry.value});
lcm *= std.math.pow(u64, entry.key, entry.value);
}
return lcm;
}
const Factor = struct {
base: u64,
power: u64 = 1,
};
fn prime_factors(value: u64, allocator: *std.mem.Allocator) !std.ArrayList(Factor) {
var factors = std.ArrayList(Factor).init(allocator);
// Using the "test and fail method"
var current : u64 = value;
var divisor : u64 = 2;
if (is_prime(value)) {
try factors.append(Factor{.base = value});
return factors;
}
while(current != 1) {
//std.log.warn("{} rem {} = {}", .{current, divisor, @rem(current, divisor)});
if (@rem(current, divisor) == 0) {
current = current / divisor;
// Add divisor to the list of factors if it's not there, otherwise
// increment the power
var index: ?usize = null;
for (factors.items) |v, k| {
if (v.base == divisor) {
index = k;
break;
}
}
if (index) |i| {
factors.items[i].power += 1;
}
else {
try factors.append(Factor{.base = divisor});
}
}
else {
// Out of this factor, increment the divisor until the next prime number
// divisor is reached.
divisor += 1;
while(!is_prime(divisor)) : (divisor+=1) {}
}
}
return factors;
}
fn is_prime(value: u64) bool {
if (value == 1) {
return false;
}
var i: u64 = 2;
while (i < (value-1)) : (i += 1) {
if (@rem(value, i) == 0) {
return false;
}
}
return true;
}
test "is_prime_49" {
std.testing.expect(is_prime(49) == false);
}
test "is_prime_1009" {
std.testing.expect(is_prime(1009));
}
test "prime_factors_100" {
var a = std.testing.allocator;
var factors = try prime_factors(100, a);
defer factors.deinit();
// for (factors.items) |v| {
// std.log.warn("{}^{} ", .{v.base, v.power});
// }
std.testing.expectEqual(factors.items.len, 2);
std.testing.expectEqual(factors.items[0].base, 2);
std.testing.expectEqual(factors.items[0].power, 2);
std.testing.expectEqual(factors.items[1].base, 5);
std.testing.expectEqual(factors.items[0].power, 2);
}
test "prime_factors_1009" {
var a = std.testing.allocator;
var factors = try prime_factors(1009, a);
defer factors.deinit();
// for (factors.items) |v| {
// std.log.warn("{}^{} ", .{v.base, v.power});
// }
std.testing.expectEqual(factors.items.len, 1);
std.testing.expectEqual(factors.items[0].base, 1009);
std.testing.expectEqual(factors.items[0].power, 1);
}
// This is a pretty long test...
test "prime_factors_1289732" {
var a = std.testing.allocator;
var factors = try prime_factors(128973, a);
defer factors.deinit();
// for (factors.items) |v| {
// std.log.warn("{}^{} ", .{v.base, v.power});
// }
std.testing.expectEqual(factors.items.len, 3);
std.testing.expectEqual(factors.items[0].base, 3);
std.testing.expectEqual(factors.items[0].power, 1);
std.testing.expectEqual(factors.items[1].base, 13);
std.testing.expectEqual(factors.items[1].power, 1);
std.testing.expectEqual(factors.items[2].base, 3307);
std.testing.expectEqual(factors.items[2].power, 1);
}

27
day14/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day14", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

584
day14/input Normal file
View File

@ -0,0 +1,584 @@
mask = 1X11X010X000X0X101X00100011X10100111
mem[40278] = 36774405
mem[51306] = 55175378
mem[31036] = 805355
mem[8433] = 48148
mem[58481] = 45466
mask = 1000101X11001XXX00X01110X1X000XX0100
mem[42362] = 2765432
mem[20493] = 213778
mem[52954] = 756325
mask = 10010000X00X1010000101X0010X001X1X10
mem[34108] = 155448
mem[19047] = 166539692
mask = 1X0000111X0X10100X10X1110010X0100000
mem[44380] = 108787272
mem[50688] = 178803
mem[13224] = 18328
mem[47270] = 41220136
mem[1679] = 5379693
mem[25086] = 5316
mask = 100010X011001X1000X1000XXX0000X010X0
mem[8433] = 12191
mem[45074] = 466358
mem[57607] = 88673989
mem[1764] = 3258736
mask = X0011010110010010000X00100100X1001X0
mem[42636] = 8106931
mem[26732] = 819582135
mem[61324] = 115576
mem[46608] = 259438
mem[62850] = 325
mask = 11XX001111001X1001110X1XXX1110001X0X
mem[52922] = 2111
mem[39872] = 2919426
mem[49237] = 13351029
mem[25369] = 403711
mem[25714] = 525
mem[11361] = 930295699
mask = 100010001100X110X0111000X000X00X0000
mem[55023] = 398985
mem[1543] = 794
mem[47160] = 65745
mask = 1000001011X010XX00001001010X11101X01
mem[3993] = 6186451
mem[15936] = 678
mem[12520] = 889
mask = 110010XX10X0101X01X011X1010X00001100
mem[21281] = 1112
mem[1813] = 834
mem[23778] = 88
mem[877] = 4305190
mem[41759] = 688804
mem[31991] = 4165476
mask = 1000X0101X001010000X10X00X00X01X00X1
mem[62604] = 118285948
mem[25086] = 804036
mem[52954] = 414491
mem[61838] = 14920
mem[12372] = 14382
mask = XXX1X00010001000X00X101X001000X01111
mem[38767] = 23779
mem[15107] = 3739
mem[19591] = 35246
mem[64406] = 27640
mem[47997] = 1470326
mask = 1011101011X0X1X100X0X11110010100X011
mem[57638] = 42095143
mem[18633] = 7407282
mem[23584] = 1861
mem[9800] = 35320
mem[25647] = 17074
mask = X0XX10X0100X1010X000X00011X100001101
mem[19475] = 11720838
mem[22303] = 3396
mem[31371] = 963
mem[27119] = 913
mem[48910] = 28628571
mem[48457] = 3430746
mask = 1000101X1XX011010000010001000011XX00
mem[42746] = 439123
mem[26673] = 186688
mem[9335] = 104841
mem[47814] = 814
mem[31051] = 23
mem[26161] = 192849624
mask = 110000X1X100101X011X001X0011XX011001
mem[10584] = 8361
mem[21594] = 83379
mem[47043] = 458757662
mem[1767] = 3878
mem[37986] = 5338251
mem[59740] = 779934
mem[22725] = 495512
mask = 10110X10100010X1011010X00010X11101X1
mem[32885] = 15961
mem[49329] = 11659
mem[49589] = 883656
mem[58578] = 3299
mem[13410] = 16573
mem[57567] = 56589
mem[17446] = 2435
mask = 100100001XX01110X00010000X100101X0X0
mem[46571] = 57904
mem[64234] = 1904852
mem[17836] = 917
mem[3697] = 79951109
mem[17934] = 311
mem[62943] = 105198
mem[43632] = 127650
mask = 110X001X00001X100X001X011100X01X0X01
mem[32984] = 5679479
mem[2985] = 52007072
mask = 1000X01011001100XX0000X1110X00010101
mem[52709] = 46005248
mem[64106] = 148
mem[10607] = 177262862
mem[1672] = 768
mem[55771] = 114128471
mem[102] = 407505
mask = X0X01010X1X011000X0000000X1001101X10
mem[24357] = 37895788
mem[4818] = 12679
mem[1895] = 677
mem[19538] = 1012377512
mem[51317] = 290
mem[26273] = 3433
mask = 100X0X10X101100X1X10X111111001001X00
mem[30547] = 1084
mem[55023] = 38977
mem[62922] = 235723
mem[26793] = 2101257
mem[3343] = 846
mem[23767] = 749476
mask = 10001XXX11X01101X0101X11101X1110X010
mem[61302] = 2841122
mem[54867] = 8646
mem[50226] = 130817
mem[48234] = 29376
mem[39560] = 605311
mask = 110010101X001X1X000000000X0001110X10
mem[44651] = 1982752
mem[46095] = 7221
mem[22548] = 1154372
mask = 11X100X0XX101010X00011101110X1010X01
mem[28851] = 10138786
mem[40188] = 9003080
mem[46594] = 260547019
mem[13047] = 644
mem[61575] = 318501037
mem[17933] = 130721
mask = 10X000111X01X010XX1X0XX11001010001X0
mem[17836] = 11610
mem[60798] = 17334088
mem[18040] = 8111502
mem[5507] = 3549486
mask = 100010101X001XXX00X0X10001X10111X01X
mem[1101] = 1830700
mem[12750] = 44919
mem[61081] = 1145728
mem[221] = 98190
mem[5230] = 1674762
mask = 10110101X0X0100001X01101X1111X011011
mem[63476] = 774
mem[38765] = 6583
mem[53101] = 425799
mem[2689] = 76519
mask = 1X0X0X001XX010100000X1X0X1000X010100
mem[63306] = 25107559
mem[29367] = 7911
mem[33854] = 333886
mem[34129] = 1601023
mem[19106] = 105039
mem[20340] = 33500
mask = 1XX11X10100XX00X0X001010011010010111
mem[17552] = 318
mem[52954] = 755503843
mem[45796] = 251387
mask = 110010X01000101001000101X100001X010X
mem[19611] = 4546530
mem[94] = 16405
mem[37449] = 16299407
mem[63044] = 1717
mem[60882] = 53035
mask = 1X111010100010X10X00X110XX0010010XX1
mem[46825] = 38742
mem[1559] = 2601
mem[17127] = 10125964
mem[45796] = 17645381
mem[57067] = 650
mem[12750] = 7052753
mem[51876] = 223481
mask = X00X1010110010010X000X000110X0X0X00X
mem[20021] = 98402475
mem[62492] = 59443811
mask = 100X101X100X1010000100010X000010X011
mem[11361] = 790603
mem[32392] = 1461971
mem[16860] = 55486
mem[48278] = 118088
mem[6887] = 436990
mem[44042] = 244740
mask = 1000X01XX100X10000XX1X0011001XX01110
mem[20112] = 2750699
mem[12269] = 52907343
mem[42636] = 6065
mem[17001] = 169286
mask = 10X1101X1X001X010X00011X0X0111001X11
mem[37947] = 96
mem[63306] = 7396
mem[5465] = 1081
mem[14662] = 1011
mem[65279] = 131
mask = 110100111100XX1X0111011110101000000X
mem[37780] = 7990
mem[31512] = 40679485
mem[14491] = 737737
mem[30998] = 124949091
mask = X1011X001000101XX0001X0X00111101001X
mem[33157] = 12243
mem[56747] = 419147
mem[11586] = 6256
mem[64708] = 76550
mem[37957] = 243778
mem[5091] = 2456
mask = 11X110X0X0001011X0000X0000100101X0X1
mem[25324] = 2093940
mem[36379] = 2777325
mem[54213] = 228702576
mem[32976] = 5846431
mem[29430] = 119936
mask = 1101010000101000X0001111100XXX111X11
mem[31402] = 7431602
mem[2073] = 7956
mem[36885] = 3966
mem[32392] = 37896
mem[6832] = 173996362
mem[53853] = 16478619
mem[65160] = 667963
mask = 100XX10X100X101X0X00000011X00X110X00
mem[62304] = 3584301
mem[57317] = 963348
mem[16414] = 7872061
mem[34763] = 1271472
mask = 10XX001011000100000010X0100X01100111
mem[48910] = 527784663
mem[6555] = 360
mem[52875] = 2675
mem[18803] = 524
mem[42703] = 3789970
mask = 1X0100101X00X00X011100X1X11100X0101X
mem[45317] = 6806741
mem[48723] = 23187771
mem[34283] = 291852
mem[29981] = 115905
mem[63917] = 245041
mask = 10010X0011001X10000000001X1001X10XX0
mem[24836] = 124320580
mem[13017] = 387784
mem[49496] = 6149582
mem[40990] = 3612867
mem[42530] = 414515530
mask = 11010XX01100X001XX1100X00001XX001011
mem[49876] = 340001
mem[12520] = 447064754
mem[31346] = 2199326
mem[38744] = 3174513
mask = 100X101XX100100100101X000X00011111X0
mem[58504] = 161861
mem[51785] = 352
mem[5035] = 14642386
mask = 10XX0011100X101010110001110X11001X0X
mem[55328] = 912776
mem[54729] = 404668417
mem[1081] = 1230593
mem[43126] = 275450
mem[9568] = 6977
mem[38414] = 258888
mem[17523] = 628
mask = 11011X10110010001110110X0XX1XX001101
mem[14522] = 3706
mem[23442] = 84315
mem[60757] = 7650
mem[64106] = 4820
mem[12365] = 24537836
mem[46911] = 2142190
mem[60482] = 14617749
mask = 11X1001111001X10X11100X000X010100110
mem[30003] = 4640103
mem[46235] = 8912631
mem[28941] = 239
mem[3232] = 2552211
mem[14072] = 24479
mem[45848] = 97107
mem[27490] = 7267061
mask = X00XXX1111X01101X0101110001XXX101110
mem[50700] = 61091
mem[2006] = 46171
mem[54190] = 13801104
mem[437] = 700
mem[25806] = 370455
mask = 1X00X0X0X00010100X00X00X010XX1100101
mem[23418] = 3953103
mem[4151] = 16351752
mem[33858] = 2781804
mem[40347] = 48747047
mem[24323] = 185098
mem[13410] = 3244984
mem[22024] = 2046007
mask = 101110XXX1001X01X100X1XX000111111111
mem[42442] = 6862901
mem[37947] = 133
mem[52715] = 90558
mask = 1X0XX0X0100010X0000X010X010X0001010X
mem[41622] = 3864588
mem[37947] = 2574041
mem[36379] = 282
mem[7539] = 1884
mem[43885] = 252462770
mask = 1X0000XX110XX0X0X01101X0100X11101010
mem[31739] = 122014445
mem[12525] = 35483
mem[49565] = 120526
mask = 10000X00111X1010X0X00X0001X001X111X0
mem[50] = 184186855
mem[26970] = 28009237
mem[43747] = 57180
mask = XX01X010110X1XX101X11011X00101000011
mem[34649] = 23812
mem[19379] = 739289
mem[9427] = 290837028
mask = 1000001101X0X1000011111XX000101X11XX
mem[53212] = 976414185
mem[54319] = 309721
mem[61044] = 26059565
mem[58543] = 112
mem[47508] = 485916879
mem[58912] = 603
mask = 11X100000000100X000011101X001X0X0011
mem[12536] = 1079539
mem[60933] = 890
mem[38277] = 24422421
mem[31503] = 275497096
mask = 10111010111011110X001111X0X01XX0X011
mem[36315] = 732755
mem[12521] = 5283380
mem[14593] = 11354059
mask = 110X10001000100X00001100X10000001XX0
mem[178] = 10049489
mem[58352] = 1284
mem[55836] = 13364
mem[8955] = 148648
mask = 1001001X110010X01111001X0001010X1101
mem[51286] = 424
mem[24896] = 685
mem[35764] = 984973816
mem[1767] = 21227
mem[58224] = 509700911
mem[54139] = 681
mask = 10X0101001001100X010X11001110X1X1101
mem[4197] = 3959433
mem[28314] = 4080074
mem[64406] = 2275763
mask = 10111011110011010XX0X111X00X1111111X
mem[53633] = 24715
mem[12901] = 288197152
mem[61838] = 365048
mem[9985] = 113625770
mask = 1000101011X0110X00000XX001XX0X1XX011
mem[18728] = 2722863
mem[62115] = 373062209
mem[24406] = 14575043
mem[1135] = 1658799
mem[36109] = 27585
mem[43154] = 932674865
mask = 1X00001X1100101000XX01110001X01010X0
mem[38443] = 2595746
mem[45834] = 8200415
mem[32618] = 2473
mem[45317] = 204863
mem[36385] = 1258950
mem[1559] = 178687
mem[7129] = 274257
mask = 1X01X010110X1000111X11X00X1101011X01
mem[64351] = 89231
mem[23767] = 2060338
mem[8182] = 3870
mem[55067] = 3498
mem[27490] = 113212315
mask = 10000010110010100001XX01000X1XX00000
mem[22484] = 465878
mem[199] = 492230203
mem[40351] = 41069
mem[40347] = 28883121
mem[54190] = 132583179
mem[45157] = 1230
mem[3262] = 763080
mask = 1001010110011011X0X0100011X00X00X011
mem[9068] = 1859901
mem[65291] = 1860
mem[4025] = 21940594
mask = 11010X00X0X01X000000111010X0X1111X01
mem[33551] = 154606
mem[11586] = 6143673
mem[55294] = 602657
mem[25418] = 1846
mem[31307] = 32063880
mem[20048] = 1695818
mask = 1X111X10110010110100110X110110X00000
mem[24896] = 9413794
mem[37579] = 13947393
mem[62604] = 5335
mem[9937] = 13537
mem[14199] = 601827
mask = 111110101X00X0110X000110X000101000X0
mem[48234] = 1067197062
mem[43126] = 1849938
mem[26161] = 32826701
mem[42432] = 2056
mask = 10001X10110011000X100001X1100X000000
mem[35283] = 15811124
mem[6943] = 592604
mem[25032] = 189694567
mem[36455] = 163580
mem[23535] = 61178
mem[28952] = 363311
mask = 1XX0000000001X10000X100001001X10X1X1
mem[14987] = 1027
mem[59069] = 14400510
mem[27100] = 13017
mem[70] = 22529
mem[9653] = 120954062
mask = 1X001X1010001010X001X0101000X1100001
mem[36385] = 7634
mem[51785] = 373478
mem[62871] = 1219093
mem[48687] = 720
mem[46211] = 184017955
mem[44651] = 4180012
mask = 1X111X1X1100110100X0X11X011100010101
mem[30714] = 86493051
mem[9781] = 6458038
mem[44042] = 196093756
mem[54852] = 49986
mask = 1X0X001XX10010X0XX11001100X1000100X1
mem[59055] = 8554849
mem[30511] = 238
mem[59740] = 291
mem[46825] = 4021
mem[57257] = 47883555
mask = 1001XX0X100X10000000X101XX0101X1X011
mem[57317] = 3753201
mem[36109] = 89435982
mem[2071] = 92612
mem[51306] = 3807708
mem[60626] = 16185176
mem[6288] = 52787155
mem[51876] = 5014
mask = 10X10X0X10X0100X0X00010X100111010000
mem[47779] = 2632
mem[44258] = 3287861
mem[55067] = 554823
mem[5507] = 16374932
mask = X00000X01X0X101001XX00011010X010X110
mem[15082] = 734057
mem[20325] = 9406
mem[43154] = 681
mem[14046] = 2718549
mem[36608] = 18836
mask = 10001XX1110XX10X00X01100001011001010
mem[64106] = 948524
mem[63156] = 717606237
mem[21756] = 8193201
mem[61081] = 12060571
mem[26182] = 1980
mask = 100XX0X011001X0X00100101010100X100X0
mem[40347] = 7113
mem[20846] = 1812874
mem[52954] = 31235865
mem[15176] = 73255675
mem[33551] = 45182604
mask = 1000101X1000100000001001X10001010X1X
mem[53536] = 78486
mem[14207] = 25081
mem[6943] = 406911928
mem[20627] = 33813239
mem[52083] = 5810
mem[51593] = 2963
mask = 100XX01010X0100100XX1X0X011001111110
mem[50540] = 521342322
mem[25666] = 517512832
mem[19475] = 60787116
mask = 100X1010XX0011X000100010X0X1X0111X11
mem[44296] = 11404
mem[19921] = 12860
mask = 10011000XX0X100000X1X10X001X00X10X10
mem[15030] = 28046260
mem[36124] = 53286373
mem[18115] = 57486
mem[14821] = 6413
mem[46807] = 4097123
mem[5230] = 758650
mem[47154] = 2777
mask = 1001X0101X0010000X11011X01001XX11101
mem[61830] = 63370
mem[31503] = 16024
mem[12525] = 246729437
mem[33593] = 115066
mem[46594] = 59939695
mem[178] = 6489337
mask = 110XX000100010000000100110110XX0XX01
mem[61044] = 1681
mem[48145] = 78509
mem[14662] = 317884442
mask = 10010011110XX01000111011011X1011X111
mem[63129] = 26
mem[3729] = 72549
mem[60816] = 33039
mem[5097] = 620696594
mem[24325] = 1480
mem[52500] = 507
mem[9653] = 77992342
mask = 10X11010XX00X00100X0011X100X110X0011
mem[50406] = 75245910
mem[65160] = 121691
mem[10605] = 5972898
mem[31113] = 122549
mask = 10X0111111101101001X1XXX1X0011101010
mem[32648] = 13078
mem[16040] = 42554293
mem[49180] = 14823
mem[12178] = 18873
mem[45060] = 58303
mem[49248] = 59412
mask = 1000X010110X101001100X0010100100011X
mem[14950] = 106014
mem[41759] = 6142194
mem[53704] = 2925
mask = 1000001011001010000X10010000X110X10X
mem[38572] = 30247028
mem[23767] = 23066
mem[32618] = 542388
mem[10770] = 411
mem[16831] = 40856
mem[13505] = 2142
mem[28786] = 140994490
mask = 1100X0X000001XX00100X0010110X0X01X01
mem[17768] = 45460151
mem[4197] = 705
mem[2953] = 12201
mask = 1000000011XX10X00X0010X1011X111X0111
mem[18985] = 29719899
mem[45172] = 258207909
mem[49882] = 85394924
mem[21653] = 603
mem[31300] = 37290319
mem[5035] = 5768
mem[6427] = 15769266
mask = 10010011110010X0111101X000000101X0X1
mem[47082] = 157766
mem[13410] = 3842391
mem[58172] = 2576
mask = 10X000001000101000011101X0X000XX1001
mem[3121] = 198929928
mem[59740] = 16383
mem[12269] = 37852
mem[18190] = 1240
mask = 10000XX001000100XX0X100X1010110110X0
mem[9713] = 1435
mem[50404] = 1789
mem[28429] = 3239
mem[178] = 2804
mask = 1000010010X11011X0X01X0111010011X0X0
mem[44077] = 202823
mem[30483] = 3929
mem[25920] = 10040
mem[221] = 135771
mask = 10X0X01111001100000000000100X0001X1X
mem[9427] = 152879
mem[38057] = 11090
mem[58564] = 32957206
mask = 110X0010110X1X100010101X00100X001010
mem[30968] = 2095418
mem[3121] = 139148
mem[53666] = 26824

296
day14/src/main.zig Normal file
View File

@ -0,0 +1,296 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var map = std.hash_map.AutoHashMap(u64, u64).init(gpa);
defer map.deinit();
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
// Part one
var and_mask : u64 = std.math.maxInt(u64);
var or_mask : u64 = 0;
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
std.log.debug("{}", .{line});
if (std.mem.eql(u8, line[0..4], "mask")) {
// Set mask
var mask_iter = std.mem.tokenize(line, "=");
_ = mask_iter.next(); // skip the first one
if (mask_iter.next()) |v| {
set_masks(std.mem.trim(u8, v, " "), &and_mask, &or_mask);
}
}
else {
var memory_location: u64 = 0;
var memory_value: u64 = 0;
var mem_iter = std.mem.tokenize(line, "=[");
std.log.warn("{}", .{mem_iter.next()}); // skip 'mem['
if (mem_iter.next()) |location_line| {
std.log.debug("parsing '{}'", .{location_line});
memory_location = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, location_line, " ]"), 10);
}
if (mem_iter.next()) |value_line| {
memory_value = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, value_line, " "), 10);
}
try write_memory(&map, memory_location, memory_value, and_mask, or_mask);
}
}
var map_it = map.iterator();
var sum : u64 = 0;
while (map_it.next()) |entry| {
sum += entry.value;
}
std.log.info("Part 1: Sum of non-zero memory locations: {}", .{sum});
// Part 2
map.deinit();
map = std.hash_map.AutoHashMap(u64, u64).init(gpa);
gpa.free(contents);
try f.seekTo(0);
contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
it = std.mem.tokenize(contents, "\n");
var address_mask : [36]u8 = undefined;
while (it.next()) |line| {
std.log.debug("{}", .{line});
if (std.mem.eql(u8, line[0..4], "mask")) {
// Set mask
var mask_iter = std.mem.tokenize(line, "=");
_ = mask_iter.next(); // skip the first one
if (mask_iter.next()) |v| {
std.mem.copy(u8, &address_mask, std.mem.trim(u8, v, " "));
}
}
else {
var memory_location: u64 = 0;
var memory_value: u64 = 0;
var mem_iter = std.mem.tokenize(line, "=[");
_ = mem_iter.next(); // skip 'mem['
if (mem_iter.next()) |location_line| {
std.log.debug("parsing '{}'", .{location_line});
memory_location = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, location_line, " ]"), 10);
}
if (mem_iter.next()) |value_line| {
memory_value = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, value_line, " "), 10);
}
try write_memory_address_masked(&map, memory_location, memory_value, address_mask[0..]);
}
}
map_it = map.iterator();
sum = 0;
while (map_it.next()) |entry| {
sum += entry.value;
}
std.log.info("Part 2: Sum of non-zero memory locations: {}", .{sum});
}
fn write_memory_address_masked(map: *std.hash_map.AutoHashMap(u64, u64), location: u64, value: u64,
mask: []const u8) !void {
// Fuse the value into the character mask
var i : u6 = 0;
var new_mask : [36]u8 = undefined;
std.mem.copy(u8, &new_mask, mask);
while (i < 36) : (i += 1) {
if (new_mask[i] == 'X') {
continue;
}
else if (new_mask[i] == '1') {
continue;
}
else if (new_mask[i] == '0') {
// mask to isolate bit at position 35 - i
// kth() counts from LSB to MSB, we are going in string order from
// MSB to LSB
new_mask[i] = switch(kth_bit(location, 35-i)) {
0 => '0',
1 => '1',
else => {
unreachable;
},
};
//std.log.warn("Index {}: {c} -> {c}", .{i, new_mask[i], mask[i]});
}
}
std.log.warn("\nValue: {b:36} ({})\nPre-fuse: {}\nPst-fuse: {}", .{location, location, mask, new_mask});
var addresses = try generate_address_list(map.allocator, new_mask[0..]);
defer addresses.deinit();
for (addresses.items) |address| {
std.log.warn("Wrote {} to address {}", .{value, address});
try map.put(address, value);
}
}
// Caller is responsible for freeing this
// This function takes the "fused mask", where the only thing left to resolve
// if the 'X' bits.
fn generate_address_list(allocator: *std.mem.Allocator, mask: []const u8) !std.ArrayList(u64) {
var masks = std.ArrayList(u64).init(allocator);
var i : u64 = 0;
// Store the offsets of the locations of the X character
var x_locations = std.ArrayList(usize).init(allocator);
defer x_locations.deinit();
for (mask) |c, k| {
if (c == 'X') {
try x_locations.append(k);
}
}
var n_variants = std.math.pow(u64, 2, x_locations.items.len);
//std.log.warn("{} Xs in mask '{}', {} variants", .{x_locations.items.len, mask, n_variants});
while (i < n_variants) : (i += 1) {
var m = try allocator.alloc(u8, mask.len);
std.mem.copy(u8, m, mask);
var bit_index : u6 = 0;
while (bit_index < x_locations.items.len) : (bit_index += 1) {
// At 0, all Xs become zero,
// At 1, last X becomes one, otherwise Xs are zero
// ...
m[x_locations.items[bit_index]] = switch(kth_bit(i, bit_index)) {
0 => '0',
1 => '1',
else => {
unreachable;
},
};
}
var value = try std.fmt.parseUnsigned(u64, m, 2);
//std.log.warn("\nFrom: {:64}\nGot: {b:64}", .{m, value});
try masks.append(value);
allocator.free(m);
}
return masks;
}
// @see https://www.geeksforgeeks.org/find-value-k-th-bit-binary-representation/
fn kth_bit(value: u64, k: u6) u64 {
//std.debug.warn("\nKey: {}, V: {}\nOrig: {b:64}\n", .{k, value, value});
var one: u64 = 1;
var shifted: u64 = 0;
var overflowed = @shlWithOverflow(u64, one, k, &shifted);
if (overflowed) {
std.log.warn("OVERFLOWED", .{});
}
//std.debug.warn("Shft: {b:64}\n", .{shifted});
//std.debug.warn("Andd: {b:64}\n", .{value & shifted});
//std.debug.warn("Rslt: {b:64}\n", .{(value & shifted) >> k});
return (value & shifted) >> k;
}
fn write_memory(map: *std.hash_map.AutoHashMap(u64, u64), location: u64, value: u64, and_mask: u64, or_mask: u64) !void {
// Mask
var new_value = value;
new_value &= and_mask;
new_value |= or_mask;
try map.put(location, new_value);
std.log.debug("Wrote '{}' to '{}' (pre-masked: '{}')",
.{new_value, location, value});
//std.log.warn("\npre_mask: {b:64}\nand_mask: {b:64}\nor_mask :{b:64}\npst_mask: {b:64}",
// .{value, and_mask, or_mask, new_value});
}
//const maskWidth : u64 = 36;
fn set_masks(line: []const u8, and_mask: *u64, or_mask: *u64) void {
and_mask.* = std.math.maxInt(u64);
or_mask.* = 0;
var one: u64 = 1;
for (line) |c, k| {
var offset = @intCast(u6, line.len - k - 1);
switch(c) {
'1' => {
// Only need to tweak the or_mask
or_mask.* |= (one << offset);
},
'0' => {
and_mask.* &= ~(one << offset);
},
'X' => {
continue;
},
else => unreachable,
}
}
std.log.debug("and mask:{b:64}", .{and_mask});
std.log.debug("or mask:{b:64}", .{or_mask});
}
test "mask_setting" {
var and_mask : u64 = 0;
var or_mask : u64 = 0;
var l = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X";
set_masks(l, &and_mask, &or_mask);
}
test "memory_writing" {
var and_mask : u64 = 0;
var or_mask : u64 = 0;
var l = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X";
set_masks(l, &and_mask, &or_mask);
var map = std.hash_map.AutoHashMap(u64, u64).init(std.testing.allocator);
defer map.deinit();
try write_memory(&map, 8, 11, and_mask, or_mask);
try write_memory(&map, 7, 101, and_mask, or_mask);
try write_memory(&map, 8, 0, and_mask, or_mask);
if (map.get(8)) |v| {
std.testing.expectEqual(v, 64);
}
else {
unreachable;
}
if (map.get(7)) |v| {
std.testing.expectEqual(v, 101);
}
else {
unreachable;
}
}
test "kth_bit" {
var value : u64 = 13;
// 0000 1101
var expected = [_]u64 {
// goes from LSB to MSB
1, 0, 1, 1,
0, 0, 0, 0,
};
for (expected) |v, k| {
var key : u6 = @intCast(u6, k);
std.testing.expectEqual(kth_bit(value, key), expected[k]);
}
}
test "generate_address_list" {
var mask = "000000000000000000000000000000X1101X";
var addresses = try generate_address_list(std.testing.allocator, mask[0..]);
defer addresses.deinit();
//std.log.warn("\n26: {b:64}\n27: {b:64}\n58: {b:64}\n59: {b:64}\n", .{26, 27, 58, 59});
std.testing.expectEqual(addresses.items.len, 4);
std.testing.expectEqual(addresses.items[0], 26);
std.testing.expectEqual(addresses.items[1], 58);
std.testing.expectEqual(addresses.items[2], 27);
std.testing.expectEqual(addresses.items[3], 59);
}
test "part2" {
var map = std.hash_map.AutoHashMap(u64, u64).init(std.testing.allocator);
defer map.deinit();
try write_memory_address_masked(&map, 42, 100, "000000000000000000000000000000X1001X");
try write_memory_address_masked(&map, 26, 1, "00000000000000000000000000000000X0XX");
var map_it = map.iterator();
var sum : u64 = 0;
while (map_it.next()) |entry| {
sum += entry.value;
}
std.testing.expectEqual(sum, 208);
}

27
day15/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day15", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

203
day15/src/main.zig Normal file
View File

@ -0,0 +1,203 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
//var f = try std.fs.cwd().openFile("input", .{});
//var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
// Starting numbers 0,8,15,2,12,1,4
var seed = [_]u64 {0, 8, 15, 2, 12, 1, 4};
var game = try MemoryGame.create(gpa);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
std.log.info("Round {} spoke {}", .{game.round-1, game.last_number});
// Part 2
try game.run_until(30000000);
std.log.info("Round {} spoke {}", .{game.round-1, game.last_number});
}
const NumberEntry = struct {
last: u64,
second_last: ?u64 = null,
};
const MemoryGame = struct {
map: std.hash_map.AutoHashMap(u64, NumberEntry),
allocator: *std.mem.Allocator,
round: u64 = 1, // Starting at one to match the puzzle
last_number: u64 = 0,
pub fn create(a: *std.mem.Allocator) !*MemoryGame {
var self = try a.create(MemoryGame);
errdefer a.destroy(self);
self.* = .{
.map = std.hash_map.AutoHashMap(u64, NumberEntry).init(a),
.allocator = a,
};
return self;
}
pub fn deinit(self: *MemoryGame) void {
self.map.deinit();
self.allocator.destroy(self);
}
// Assumes there's not repeated number in the seed
pub fn seed_game(self: *MemoryGame, seed: []u64) !void {
for (seed) |s, k| {
try self.map.put(s, NumberEntry{.last = self.round});
self.last_number = s;
self.round += 1;
}
}
// Returns the number spoken, but also updates everything
pub fn do_round(self: *MemoryGame) !u64 {
// Consider last number "spoken"
// Has it been said before?
var retval : u64 = 0;
if (self.map.get(self.last_number)) |v| {
//std.log.debug("Found previously spoken number {} for round {}. Previous spoken on round {}, has a previous occurence: {}\n",
// .{self.last_number, self.round, v.last, v.second_last != null});
if ((v.last == (self.round-1)) and (v.second_last == null)) {
// The previously spoken number was new
retval = 0;
if (self.map.get(0)) |v2| {
self.map.putAssumeCapacity(0, NumberEntry {.last = self.round, .second_last = v2.last});
}
else {
// 0 is our new number
try self.map.put(0, NumberEntry {.last = self.round});
}
}
else {
// The previous number was already spoken, so we speak the diff
retval = v.last - v.second_last.?;
if (self.map.get(retval)) |v2| {
self.map.putAssumeCapacity(retval, NumberEntry {.last = self.round, .second_last = v2.last});
}
else {
try self.map.put(retval, NumberEntry {.last = self.round});
}
}
}
else {
unreachable;
}
self.last_number = retval;
self.round += 1;
return retval;
}
pub fn run_until(self: *MemoryGame, target_round: u64) !void {
var last : u64 = 0;
while (self.round <= target_round) {
//std.log.warn("Round {} before running do_round()", .{self.round});
last = try self.do_round();
//std.log.warn("Round {} spoke {}", .{self.round-1, self.last_number});
}
}
};
test "036_ten_turns" {
var seed = [_]u64 {0, 3, 6};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
if (game.map.get(0)) |value| {
std.testing.expectEqual(value.last, 1);
}
if (game.map.get(3)) |value| {
std.testing.expectEqual(value.last, 2);
}
if (game.map.get(6)) |value| {
std.testing.expectEqual(value.last, 3);
}
var response = try game.do_round();
std.testing.expectEqual(response, 0); // Round 4
response = try game.do_round();
std.testing.expectEqual(response, 3); // Round 5
response = try game.do_round();
std.testing.expectEqual(response, 3); // ROund 6
response = try game.do_round();
std.testing.expectEqual(response, 1); // Round 7
response = try game.do_round();
std.testing.expectEqual(response, 0); // Round 8
response = try game.do_round();
std.testing.expectEqual(response, 4); // Roiund 9
response = try game.do_round();
std.testing.expectEqual(response, 0); // Round 10
}
test "132_to_2020" {
var seed = [_]u64 {1, 3, 2};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 1);
}
test "213_to_2020" {
var seed = [_]u64 {2, 1, 3};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 10);
}
test "123_to_2020" {
var seed = [_]u64 {1, 2, 3};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 27);
}
test "231_to_2020" {
var seed = [_]u64 {2, 3, 1};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 78);
}
test "321_to_2020" {
var seed = [_]u64 {3, 2, 1};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 438);
}
test "312_to_2020" {
var seed = [_]u64 {3, 1, 2};
var game = try MemoryGame.create(std.testing.allocator);
defer game.deinit();
try game.seed_game(seed[0..]);
try game.run_until(2020);
//std.log.warn("Last number spoken was {}", .{game.last_number});
std.testing.expectEqual(game.last_number, 1836);
}

27
day16/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day16", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

235
day16/input Normal file
View File

@ -0,0 +1,235 @@
136,368,517,218,187,318,185,172,146,646,804,747,816,625,695,701,420,588,167,302
144,452,191,495,196,652,878,605,607,61,932,897,539,82,456,806,587,595,153,168
517,981,569,738,886,608,935,882,943,627,884,644,228,698,640,53,748,570,880,322
65,428,312,692,61,465,626,312,644,645,539,189,485,182,310,555,442,493,550,275
701,547,434,796,278,451,179,397,233,645,741,512,442,800,693,213,188,429,654,707
898,573,456,132,190,898,705,447,875,160,688,592,627,520,434,81,517,634,240,185
155,433,198,917,513,425,143,149,421,131,815,13,69,887,928,451,497,923,623,347
908,896,430,539,532,406,439,75,857,134,589,631,552,541,633,933,522,557,807,917
367,397,712,343,276,195,334,131,137,881,884,912,197,548,817,744,54,226,457,899
340,453,916,915,430,487,816,543,485,712,703,899,638,756,431,649,364,925,238,815
525,70,427,894,279,430,792,365,278,946,624,568,371,61,453,595,324,947,598,104
986,444,243,741,822,745,484,878,457,486,937,368,746,652,126,589,907,317,828,741
171,830,687,65,815,368,508,799,71,230,560,595,364,303,312,757,112,274,597,881
917,135,661,130,898,699,618,58,206,73,149,488,458,818,69,803,572,328,888,75
270,133,228,458,519,56,425,450,277,750,365,538,591,522,925,201,533,982,857,190
810,599,315,529,515,898,857,605,92,438,629,533,899,491,360,603,537,458,542,597
307,128,930,489,156,323,924,900,309,216,101,127,312,647,605,491,237,523,746,875
632,660,660,701,700,106,169,144,341,625,432,196,799,880,808,944,443,200,341,750
349,881,943,793,541,772,643,171,540,572,647,55,882,569,934,365,944,199,278,568
703,755,639,929,140,196,897,235,342,79,360,370,302,314,818,786,565,535,186,444
936,458,393,624,509,563,540,830,788,902,200,628,896,917,795,95,496,332,941,308
154,234,305,793,927,947,632,661,367,271,273,205,527,638,151,547,285,806,186,328
641,530,616,660,626,274,368,171,280,149,269,456,658,336,306,194,659,102,318,149
322,72,125,138,550,365,688,280,442,303,491,509,136,696,996,235,202,704,334,913
640,571,170,700,803,650,592,545,421,703,600,638,590,242,316,203,3,531,906,233
424,899,571,333,226,66,159,698,326,330,62,662,140,191,933,742,755,478,349,99
645,790,316,205,637,935,187,700,565,485,746,947,130,188,436,726,311,827,309,58
153,200,307,361,169,634,608,312,228,163,313,654,520,511,527,705,300,173,306,433
125,56,770,177,237,447,425,55,557,192,275,652,160,568,495,508,525,100,487,588
877,457,275,799,205,889,890,304,568,893,237,825,597,202,911,175,917,164,337,822
312,306,427,893,562,326,904,931,703,693,946,71,181,631,328,566,552,190,750,709
91,137,910,193,277,702,142,457,562,335,228,568,672,195,349,139,759,754,946,57
548,892,303,808,883,514,69,705,942,615,128,822,514,366,54,934,554,420,433,926
306,518,931,549,652,792,282,808,157,752,60,857,341,104,632,202,806,98,336,940
144,991,568,185,756,367,893,695,784,631,901,797,607,69,545,696,369,944,948,641
60,542,350,690,178,793,273,322,688,321,719,433,592,67,518,808,449,758,180,447
901,740,339,828,898,913,895,284,93,794,789,894,529,238,75,439,519,797,54,890
301,314,556,624,202,207,161,277,140,138,330,740,908,553,190,432,99,532,789,54
534,67,160,994,129,272,550,599,657,630,786,556,626,319,245,692,64,948,397,532
518,545,351,652,920,142,105,706,185,167,268,549,540,184,140,347,597,830,653,753
275,75,743,916,512,918,162,805,150,798,797,178,67,935,603,300,94,494,491,452
555,322,542,648,363,787,747,747,909,245,305,203,455,758,920,110,349,150,451,315
640,309,891,542,541,519,69,720,699,435,799,131,699,686,948,541,520,703,529,696
918,924,201,345,458,359,821,535,528,431,164,93,563,497,657,187,606,102,325,897
154,877,828,160,346,675,144,300,304,174,605,708,437,831,934,234,234,911,550,793
428,128,570,341,530,891,303,184,366,752,485,573,156,277,335,104,217,202,174,149
500,558,336,927,881,135,640,440,931,242,648,304,338,235,895,232,126,61,308,551
201,899,52,447,175,624,677,518,519,915,343,788,429,664,647,233,420,276,655,490
396,884,892,744,877,186,988,203,639,103,143,181,900,510,346,556,631,788,742,177
630,534,685,517,134,590,908,627,370,525,541,907,320,807,302,186,706,340,815,247
791,490,78,232,73,273,890,589,543,271,655,169,180,530,441,137,629,918,278,920
814,0,436,661,362,458,497,787,72,318,900,341,190,130,897,896,487,602,95,904
918,179,141,508,886,99,307,894,686,634,641,318,546,232,563,165,543,885,705,929
652,807,144,143,642,265,420,887,55,51,157,513,748,169,420,427,651,692,880,937
318,565,305,929,754,587,318,308,306,825,568,457,72,218,146,805,160,342,269,70
555,688,323,557,816,651,229,491,237,795,694,517,931,827,629,586,150,229,108,663
907,230,149,455,109,536,910,601,801,548,346,942,159,125,158,59,74,174,446,496
396,756,177,597,157,940,802,337,122,623,795,938,883,746,397,227,741,70,900,55
536,159,803,195,336,426,228,888,434,911,887,753,888,735,309,185,876,920,799,623
280,920,396,155,202,367,656,454,454,875,324,24,240,562,885,821,493,519,702,142
491,199,150,134,433,186,949,200,101,97,546,152,706,788,337,56,760,366,145,857
644,528,644,422,752,165,351,593,549,347,941,243,244,512,757,537,99,626,905,804
631,901,747,424,904,510,206,99,594,820,180,910,357,171,231,488,59,328,805,656
229,923,194,517,656,364,74,485,99,804,943,190,946,343,573,751,392,819,420,236
616,823,922,633,149,746,565,558,322,593,319,897,695,496,914,568,552,511,94,587
119,568,129,320,302,305,804,554,232,647,303,194,923,891,915,744,485,551,540,68
74,336,432,197,715,923,914,527,278,660,910,53,692,452,422,513,568,531,650,944
787,604,243,646,429,56,73,546,553,883,170,883,432,200,634,701,920,22,54,896
318,271,875,590,360,445,177,63,999,154,746,637,535,329,92,892,949,204,442,435
51,558,155,421,441,325,920,568,820,300,804,537,544,423,74,231,91,616,245,312
659,652,941,431,349,351,50,662,520,646,305,642,96,490,350,697,671,637,495,797
776,131,949,887,272,457,910,642,940,425,702,176,746,510,271,245,885,928,886,562
313,420,594,938,946,571,193,999,938,534,161,100,607,136,101,894,934,595,561,590
269,745,143,347,305,593,722,69,487,662,60,137,569,240,653,71,590,891,648,632
542,623,629,806,515,178,898,230,496,143,748,509,485,604,518,445,918,981,818,626
706,303,536,635,196,190,642,884,300,55,179,920,813,634,520,328,796,189,560,101
239,542,116,685,104,801,759,52,567,436,322,745,628,487,687,520,203,856,191,641
332,748,664,896,929,593,740,881,318,654,427,148,7,235,939,205,422,348,128,800
919,553,103,430,426,727,437,663,368,368,795,103,912,751,933,922,361,492,231,516
231,586,567,204,101,574,762,167,567,567,161,568,317,934,603,510,68,655,892,907
491,273,431,135,161,192,930,484,167,361,396,197,247,830,938,454,939,363,605,931
339,888,500,830,328,630,629,750,273,300,279,603,562,103,57,277,127,342,309,306
733,68,884,341,650,602,804,656,307,891,551,789,201,485,185,488,69,188,183,600
525,601,168,649,235,519,922,453,130,193,87,105,529,943,799,880,898,788,320,56
822,164,814,195,519,700,546,896,595,94,916,492,457,745,491,919,597,278,67,894
703,310,529,551,898,564,857,924,915,538,530,61,529,788,920,819,730,314,493,699
497,337,168,443,698,502,911,496,700,800,814,905,422,62,493,202,881,820,430,891
185,794,689,155,191,797,131,103,163,91,897,602,902,154,520,927,686,447,364,277
927,607,746,440,322,752,202,596,427,101,194,22,346,630,127,128,752,947,561,508
159,513,441,763,644,856,146,698,527,595,239,439,178,918,142,600,149,494,820,552
343,557,340,70,452,655,381,883,785,137,130,908,496,653,877,894,940,791,151,433
169,586,177,757,332,717,367,540,826,536,815,750,542,800,520,792,831,364,324,902
935,516,687,946,99,337,447,625,936,422,351,518,79,661,149,826,184,457,73,434
744,289,881,568,484,703,640,334,520,917,828,133,199,328,304,137,345,370,560,439
804,487,367,273,67,239,739,587,892,697,158,508,929,143,523,909,418,637,184,135
297,627,931,235,828,324,941,586,703,520,934,634,423,439,941,158,67,180,883,902
432,155,443,557,254,311,340,450,807,239,277,243,628,817,789,689,591,554,696,517
307,73,278,429,881,197,328,792,900,918,882,332,105,740,58,758,933,195,92,81
697,759,167,816,537,430,875,444,790,943,498,649,144,525,655,359,463,909,324,573
370,883,875,67,428,97,206,143,518,124,920,513,439,201,918,179,791,176,650,641
792,63,139,564,738,520,175,520,365,591,694,932,631,249,887,438,103,946,174,98
945,909,559,597,605,270,928,692,881,149,366,571,703,754,784,744,572,898,495,162
754,316,191,157,704,153,111,551,883,535,362,800,925,130,929,949,425,686,91,923
551,440,753,714,104,749,691,445,143,340,427,555,277,167,758,606,300,305,314,302
433,604,649,372,751,889,568,305,654,160,194,536,921,930,573,337,230,552,303,817
568,926,140,332,144,183,724,924,313,935,132,935,795,535,798,823,146,201,591,233
351,605,724,662,56,704,443,562,896,787,347,234,793,816,494,561,659,898,552,454
857,893,188,127,184,93,562,795,125,490,54,243,361,943,276,348,988,818,103,540
308,787,793,232,426,273,704,397,740,907,830,311,126,100,985,542,628,636,157,485
650,551,594,909,534,514,277,554,745,432,569,494,582,230,590,922,750,562,126,311
814,904,444,204,821,160,492,205,324,489,792,912,699,454,828,341,983,275,830,187
637,924,804,175,948,515,211,604,624,827,746,820,798,742,485,451,785,488,184,100
153,208,199,827,200,56,530,185,655,821,177,700,148,170,535,337,707,900,343,521
192,878,310,319,922,133,898,368,794,804,898,96,311,622,787,894,564,690,589,942
242,899,820,143,58,623,811,52,661,342,702,562,878,146,538,510,307,206,795,900
928,893,947,827,895,161,275,266,99,338,882,930,227,445,129,50,192,626,337,906
756,554,564,101,96,287,198,800,192,92,798,639,687,878,932,321,785,694,153,631
789,743,557,565,915,188,481,740,538,422,159,625,70,270,660,143,139,695,523,701
437,657,397,336,698,592,329,175,452,913,492,816,492,478,313,923,915,181,819,645
926,248,489,490,180,526,273,91,819,515,742,875,65,875,62,307,439,930,701,442
787,892,816,592,332,299,331,786,151,547,161,755,798,95,572,235,499,567,644,311
754,125,490,559,71,553,514,279,397,437,929,5,204,327,228,132,234,340,560,633
913,87,426,522,242,240,184,193,708,750,510,558,697,103,151,651,625,332,948,571
300,427,555,241,423,949,59,230,339,590,685,806,647,914,100,630,544,213,71,100
755,343,926,350,822,445,943,693,932,200,905,97,129,664,159,916,251,450,557,589
698,54,529,201,71,55,693,187,488,24,607,915,456,448,179,489,454,160,876,545
437,756,54,565,445,901,194,206,945,821,349,59,696,496,902,532,166,160,633,150
101,177,158,698,165,928,572,364,60,545,547,554,706,350,319,200,95,97,327,697
51,68,223,67,883,827,533,432,949,643,497,906,519,66,312,593,188,97,635,66
306,98,918,128,664,184,428,140,181,492,758,325,291,922,590,441,231,878,562,789
468,541,235,433,334,946,192,97,449,940,168,61,495,155,560,639,657,825,587,948
451,541,754,99,586,534,692,19,132,758,441,366,929,531,420,690,633,876,178,532
553,331,320,193,887,433,104,817,241,374,91,700,708,498,269,708,151,269,635,739
630,824,178,166,829,645,68,339,397,747,103,132,857,243,596,204,690,97,898,335
550,741,634,426,58,381,934,363,456,895,345,487,898,703,99,906,528,498,635,360
907,934,498,698,793,810,691,275,423,238,313,438,575,425,141,563,322,884,135,201
14,330,588,105,146,173,309,897,59,176,334,891,785,656,492,315,571,426,104,795
153,876,887,321,657,931,855,510,362,333,556,92,64,591,180,641,54,179,931,910
361,328,275,565,359,532,894,133,61,567,701,632,470,67,509,806,626,747,911,271
2,198,322,698,608,447,817,454,532,68,888,540,690,447,434,921,949,705,946,97
182,361,485,348,368,922,52,799,433,187,298,369,238,168,693,797,156,631,200,936
754,553,559,545,685,191,490,634,589,539,392,879,128,105,701,509,549,815,511,687
882,564,261,156,564,655,455,908,739,359,137,516,485,426,904,933,597,307,349,660
419,896,64,802,443,543,804,300,746,914,793,593,426,314,489,803,929,743,275,59
171,636,681,93,927,315,520,587,168,694,50,130,333,441,795,628,702,202,68,920
139,738,164,895,128,344,806,653,438,887,136,939,351,458,361,239,746,102,510,594
921,911,367,799,548,897,51,122,366,934,929,229,625,157,685,945,130,513,916,367
947,195,626,827,707,535,439,700,707,326,657,455,109,179,147,450,599,96,690,159
438,95,521,520,937,226,794,364,522,127,883,645,424,423,524,704,312,917,1,344
947,635,455,738,814,740,422,450,793,138,519,988,232,947,792,64,426,65,663,428
840,367,447,188,909,333,130,245,927,241,73,315,574,173,229,325,273,508,878,689
882,143,361,90,309,447,909,929,330,234,509,363,743,50,931,756,336,603,516,332
129,829,154,143,646,350,105,155,524,443,171,65,338,345,336,742,302,644,982,688
575,739,805,347,944,747,308,509,686,569,928,203,757,92,436,912,822,281,205,808
744,710,565,141,237,67,694,569,147,434,664,949,700,528,820,623,337,597,68,340
719,185,486,550,369,316,831,175,420,632,490,629,899,364,912,485,923,657,61,646
885,276,511,745,789,313,400,545,573,708,687,650,72,692,876,625,202,823,750,608
74,930,695,875,635,608,335,658,642,689,227,657,743,16,896,142,944,795,167,525
423,831,603,795,452,351,794,238,857,97,606,360,735,426,426,895,931,336,514,315
902,227,487,754,520,177,98,191,316,332,745,738,502,645,828,240,148,826,703,541
136,173,317,265,640,348,653,894,75,686,563,125,949,443,641,183,634,104,650,334
191,628,943,661,808,657,645,160,316,148,316,637,166,606,652,344,277,943,565,448
370,949,693,569,147,938,204,926,796,700,880,437,328,891,172,308,5,100,635,145
498,304,533,453,446,52,184,310,634,527,933,59,405,913,650,624,545,521,59,446
451,14,454,313,143,799,643,784,485,690,651,58,565,938,330,742,300,756,193,556
799,103,882,650,785,603,820,317,636,453,111,593,626,902,630,795,638,928,534,527
303,134,527,820,145,127,548,825,200,232,801,573,594,598,920,456,925,723,593,341
829,540,461,605,702,534,785,237,587,155,635,143,176,489,930,205,126,705,228,320
915,144,484,559,142,804,158,76,237,335,921,660,531,370,194,457,891,660,627,508
426,239,910,745,557,805,435,154,431,795,528,856,989,539,206,346,659,231,182,326
54,893,815,195,567,142,940,452,628,638,533,319,936,760,547,425,569,695,749,818
663,157,244,699,323,129,489,510,93,100,143,821,72,543,549,172,335,648,165,228
597,426,936,829,799,315,787,148,98,259,913,497,200,326,344,641,276,278,201,822
250,941,689,157,312,639,631,588,572,902,632,334,311,226,921,522,647,240,566,820
746,928,535,791,342,51,931,167,637,935,155,655,848,831,926,342,881,882,126,136
437,792,745,628,556,69,91,893,161,436,64,877,186,436,533,679,423,184,552,170
147,192,755,556,570,199,181,642,103,128,125,549,593,741,934,202,984,435,101,308
275,948,568,340,538,947,338,156,541,487,334,336,219,561,738,365,530,188,624,422
531,397,664,617,908,57,93,171,149,364,598,148,875,818,199,823,455,128,328,820
193,489,794,169,159,365,76,803,75,484,915,634,276,330,229,421,156,98,587,456
324,159,6,66,237,458,489,167,887,155,530,934,321,53,226,97,748,605,359,179
744,596,339,431,759,453,889,456,441,130,12,485,927,877,498,561,746,545,457,300
944,194,517,587,426,489,129,96,136,885,801,788,554,157,457,538,615,154,527,428
628,485,820,803,883,203,888,599,204,794,784,564,245,692,606,288,327,906,434,146
510,314,660,644,698,568,262,351,359,513,946,361,657,607,56,310,351,884,624,498
798,928,439,531,555,159,4,331,742,75,931,790,532,822,425,792,144,196,305,902
786,751,749,893,808,91,190,445,944,877,921,887,686,165,97,820,135,234,337,662
829,925,635,819,559,748,205,594,803,71,791,319,449,937,203,132,71,386,62,520
892,226,631,900,803,172,203,305,495,397,143,175,328,194,72,171,588,130,722,320
301,518,630,913,143,548,226,132,184,448,304,229,662,231,608,763,245,906,828,437
453,273,189,550,269,600,441,703,125,299,631,759,436,321,882,125,644,263,815,426
787,879,590,455,154,203,74,95,334,359,559,314,552,319,513,454,24,299,364,656
429,437,322,739,827,230,168,197,708,701,186,441,749,312,635,856,445,777,902,635
946,4,831,146,508,326,450,206,492,662,69,98,897,650,658,547,333,889,197,129
300,917,642,791,661,825,306,450,278,237,940,943,188,158,138,713,630,946,550,817
511,340,588,630,545,554,359,443,269,824,325,639,752,829,128,423,493,936,787,123
928,92,807,754,161,280,317,337,877,493,299,546,940,802,820,877,716,143,707,902
207,424,789,178,179,552,707,785,275,233,455,598,887,68,921,641,522,754,432,738
514,116,60,191,534,633,598,427,327,369,341,54,130,599,347,572,707,337,102,232
807,530,347,364,543,330,695,93,901,190,333,603,615,57,648,697,449,320,592,822
878,696,303,298,892,366,697,234,754,186,443,572,488,188,172,700,443,935,927,183
495,147,901,788,647,197,171,925,745,919,701,941,73,568,542,390,429,912,529,131
800,696,330,793,655,914,59,180,447,816,50,321,806,917,58,51,78,900,430,881
166,808,924,185,139,428,64,888,659,151,519,336,277,194,91,484,875,488,526,363
875,172,904,364,919,794,926,236,915,816,816,135,909,118,595,750,530,925,656,193
807,379,919,57,440,741,931,426,307,757,487,940,487,362,485,195,226,623,323,493
206,789,424,130,573,831,355,945,60,658,790,368,931,944,548,534,757,942,341,486
948,280,664,190,126,560,436,885,571,893,550,785,68,281,159,889,881,312,942,705
557,542,818,697,913,351,635,130,801,930,66,946,351,230,170,260,508,93,438,903
890,570,314,658,785,245,882,510,325,636,929,322,337,710,923,451,303,550,187,458
891,790,943,449,689,549,519,588,2,443,304,160,556,240,553,75,320,275,436,572
56,946,556,623,142,930,875,318,686,285,454,562,637,935,152,902,496,704,97,917
637,102,294,643,179,522,493,442,546,453,884,185,351,652,178,206,129,341,931,168
522,626,821,308,198,547,637,792,984,827,693,456,596,330,73,204,646,234,698,149
198,327,324,564,815,904,947,702,798,70,203,758,233,129,647,96,880,269,2,904
682,420,455,944,928,168,368,943,947,273,940,556,552,424,924,135,346,324,56,561
508,101,190,526,934,622,945,925,341,159,586,549,180,703,437,820,65,368,635,396
748,787,876,487,158,589,169,653,905,334,631,637,329,270,338,615,625,324,238,228
183,803,751,563,206,204,320,876,13,949,594,647,568,317,750,628,877,155,546,880
90,818,606,509,636,172,59,599,818,498,435,229,234,801,904,168,802,315,567,458
522,327,105,857,186,641,131,234,821,154,817,887,718,608,232,140,566,598,804,485
645,744,827,913,103,602,229,525,569,187,544,163,370,793,450,925,245,510,68,738
932,365,93,115,147,237,654,137,50,913,485,92,458,787,342,174,898,58,817,910
315,488,205,645,638,699,235,364,663,74,687,597,771,749,896,631,139,532,897,550
145,130,336,914,322,76,492,338,359,798,536,64,361,509,917,370,95,586,934,935
525,544,796,226,96,572,367,916,652,71,634,745,161,998,591,942,547,344,227,626
794,806,486,897,231,361,808,739,183,370,227,192,69,136,560,439,887,109,269,331
496,928,270,550,800,179,788,646,197,789,906,511,640,550,904,227,592,81,895,92
396,334,738,230,104,929,502,137,302,440,927,175,449,169,304,451,421,559,901,513
899,187,303,161,608,545,638,160,496,537,338,426,516,374,66,303,650,430,453,758
95,991,554,932,943,95,740,276,323,190,856,697,888,270,498,595,600,786,149,454
384,155,54,630,181,230,645,58,540,745,548,520,430,935,155,755,171,571,592,892
892,695,529,937,330,605,60,901,520,539,553,330,205,588,538,472,689,753,934,423
53,195,67,817,21,625,543,912,368,945,509,183,425,486,367,922,156,829,755,793
271,337,271,229,827,947,313,163,548,278,823,186,687,747,59,328,149,897,926,892

20
day16/input_fields Normal file
View File

@ -0,0 +1,20 @@
departure location: 29-458 or 484-956
departure station: 40-723 or 738-960
departure platform: 30-759 or 784-956
departure track: 37-608 or 623-964
departure date: 31-664 or 685-950
departure time: 27-498 or 508-959
arrival location: 36-245 or 269-961
arrival station: 35-808 or 814-973
arrival platform: 40-831 or 856-951
arrival track: 36-857 or 875-971
class: 43-161 or 167-963
duration: 25-75 or 91-966
price: 37-708 or 724-972
route: 39-370 or 396-971
row: 47-280 or 299-949
seat: 41-105 or 125-952
train: 43-351 or 359-966
type: 34-575 or 586-965
wagon: 27-397 or 420-953
zone: 48-206 or 226-965

1
day16/input_myticket Normal file
View File

@ -0,0 +1 @@
61,151,59,101,173,71,103,167,127,157,137,73,181,97,179,149,131,139,67,53

432
day16/src/main.zig Normal file
View File

@ -0,0 +1,432 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var fields = try read_fields("input_fields", gpa);
defer fields.deinit();
// for (fields.items) |f| {
// std.log.debug("Field '{}' has {} limits", .{f.name, f.limits.items.len});
// for (f.limits.items) |i| {
// std.log.debug(" {} - {}", .{i.min, i.max});
// }
// }
var tickets = try read_tickets("input", gpa);
defer tickets.deinit();
var error_tickets = std.ArrayList(usize).init(gpa);
defer error_tickets.deinit();
var error_rate : u64 = 0;
for (tickets.items) |t, kt| {
for (t.values) |v, kv| {
if (!valid_for_any_field(v, fields.items[0..])) {
std.log.debug("Field {} ({}) from ticket #{} is not valid for any field",
.{kv, v, kt});
error_rate += v;
try error_tickets.append(kt);
break;
}
}
}
std.log.info("Error rate from nearby tickets: {}, from {} tickets", .{error_rate, tickets.items.len});
// Part 2, discard invalid tickets.
while (error_tickets.popOrNull()) |v| {
var t = tickets.orderedRemove(v);
std.log.debug("Removed ticket #{}: '{}'\n{}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n{}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
.{v, t, t.values[0], t.values[1], t.values[2], t.values[3], t.values[4], t.values[5], t.values[6], t.values[7], t.values[8], t.values[9], t.values[10], t.values[11], t.values[12], t.values[13], t.values[14], t.values[15], t.values[16], t.values[17], t.values[18], t.values[19]});
}
std.log.debug("{} valid tickets to use for field position search", .{tickets.items.len});
try determine_field_positions(tickets.items[0..], fields.items[0..], gpa);
for (fields.items) |f, idx| {
std.log.info("Field '{}' has position {}",
.{f.name, f.position.?});
}
var my_ticket = Ticket {
.values = [_]u64 {
61,151,59,101,173,71,103,167,127,157,137,73,181,97,179,149,131,139,67,53,
},
};
var part2_result : u64 = 1;
for (fields.items) |f, idx| {
if (std.mem.startsWith(u8, f.name, "departure")) {
part2_result *= my_ticket.values[f.position.?];
}
}
std.log.info("Product of all values for the departure codes on my ticket: {}", .{part2_result});
}
pub fn determine_field_positions(tickets: []Ticket, fields: []Field, allocator: *std.mem.Allocator) !void {
// While there are fields with unknown positions, loop through the fields from 0..len,
// To improve performance, we could cache which fields are not valid for a given position
// in the ticket values to avoid re-calculating across the list.
// If the input tickets contain invalid examples, then this resolution with loop forever.
// while(fields_with_unknown_positions_exist(fields)) {
// for (fields) |f, f_idx| {
// if (f.position != null) {
// continue;
// }
// std.log.warn("Testing field '{}' ({}) to determine position",
// .{f.name, f_idx});
// var pos : usize = 0;
// while (pos < fields.len) : (pos += 1) {
// if (already_known_position(fields, f_idx)) {
// continue;
// }
// std.log.warn("Checking to see if all tickets match field {} in value index {}",
// .{f.name, pos});
// if (all_tickets_fit_field_limits(tickets, &fields[f_idx], pos)) {
// fields[f_idx].position = pos;
// std.log.warn("Found position {} for field {}",
// .{pos, f.name});
// break;
// }
// }
// }
// }
// We have field.len positions to resolve. For each field, we build a list of possible
// columns that could match. If after the first pass, fields with only a single possible
// column are assigned that column, then those column numbers of removed from the
// possibilities of the remaining fields.
var completely_resolved_positions = std.ArrayList(usize).init(allocator);
defer completely_resolved_positions.deinit();
var possible_positions_per_field = try allocator.alloc(std.ArrayList(usize), fields.len);
defer allocator.free(possible_positions_per_field);
for (fields) |f, idx| {
possible_positions_per_field[idx] = std.ArrayList(usize).init(allocator);
var ticket_value_index : usize = 0;
while (ticket_value_index < fields.len) : (ticket_value_index += 1) {
if (all_tickets_fit_field_limits(tickets, &fields[idx], ticket_value_index)) {
std.log.warn("Adding {} as option for field {}", .{ticket_value_index, f.name});
try possible_positions_per_field[idx].append(ticket_value_index);
}
}
std.log.warn("Field '{}' has possible ticket value indices:", .{f.name});
for (possible_positions_per_field[idx].items) |i| {
std.log.warn(" {}", .{i});
}
}
var most_constrained_field_index : usize = 0;
var min_possibilities : usize = std.math.maxInt(usize);
// Check to make sure we can start to solve without making a decision of some sort
for (fields) |f, idx| {
if (possible_positions_per_field[idx].items.len < min_possibilities) {
min_possibilities = possible_positions_per_field[idx].items.len;
most_constrained_field_index = idx;
}
}
std.debug.assert(min_possibilities == @as(usize, 1));
while (completely_resolved_positions.items.len < fields.len) {
var ok = try process_solution_round(fields, possible_positions_per_field, &completely_resolved_positions);
if (!ok) {
std.log.warn("Unable to solve", .{});
break;
}
for (fields) |f, idx| {
std.log.warn("After round, field {} has {} possibilities remaining.",
.{f.name, possible_positions_per_field[idx].items.len});
for (possible_positions_per_field[idx].items) |i| {
std.log.warn(" {}", .{i});
}
}
}
// Set the position for each field
for (fields) |f, idx| {
std.log.warn("Field {} has {} remaining possibilities after solution rounds: {}",
.{f.name, possible_positions_per_field[idx].items.len,
possible_positions_per_field[idx].items[0]});
std.debug.assert(possible_positions_per_field[idx].items.len <= 1);
fields[idx].position = possible_positions_per_field[idx].items[0];
}
// Cleanup
for (possible_positions_per_field) |p| {
p.deinit();
}
}
fn process_solution_round(fields: []Field, possibilities: []std.ArrayList(usize), resolved: *std.ArrayList(usize)) !bool {
// Check to make sure we can start to solve without making a decision of some sort
for (fields) |f, idx| {
if (possibilities[idx].items.len == 1) {
std.log.warn("{} only solution for {}", .{possibilities[idx].items[0], f.name});
var already_in_resolved = in_array(idx, resolved);
if (!already_in_resolved) {
try resolved.append(idx);
}
// Remove the from possibilities of other fields
var value_to_remove = possibilities[idx].items[0];
for (fields) |f2, idx2| {
std.log.warn("Checking {} for removal of possibility {}",
.{f2.name, value_to_remove});
if (idx2 == idx) {
continue;
}
var need_to_remove = false;
var remove_index : ?usize = null;
if (possibilities[idx2].items.len == 1) {
continue;
}
for (possibilities[idx2].items) |i, k| {
std.log.warn("pos {}: {}", .{k, i});
if (i == value_to_remove) {
std.log.warn("want to remove index {} (value: {}) from possibilities", .{k, i});
need_to_remove = true;
remove_index = k;
break;
}
}
if (need_to_remove) {
if (remove_index) |ri| {
std.log.warn("Removed index {} from possibilities for {}",
.{ri, f2.name});
_ = possibilities[idx2].orderedRemove(ri);
}
else {
std.log.warn("Wanted to remove {} from possibilities for {}, but remove_index not set",
.{idx2, f2.name});
}
}
}
if (!already_in_resolved) {
// Only process one removal per round
break;
}
}
}
// @TODO Verifiy we still have at least another round left
//std.debug.assert(min_possibilities == @as(usize, 1));
// if (min_possibilities > 1) {
// std.log.warn("Unable to provide solution, minimum of two possibilities for all remaining fields.", .{});
// return false;
// }
var min_possibilities_remaining : usize = std.math.maxInt(usize);
for (fields) |f, idx| {
if (in_array(idx, resolved)) {
continue;
}
min_possibilities_remaining = std.math.min(min_possibilities_remaining,
possibilities[idx].items.len);
}
if (min_possibilities_remaining > 1) {
std.log.warn("Unable to process more rounds, at least all non-resolved items have multiple solutions remaining", .{});
return false;
}
if (fields.len == resolved.items.len) {
std.log.debug("Resolve items length matches field items length, should be done doing solution rounds", .{});
return false;
}
return true;
}
fn in_array(value: usize, a: *std.ArrayList(usize)) bool {
for (a.items) |v, k| {
if (value == v) {
return true;
}
}
return false;
}
fn all_tickets_fit_field_limits(tickets: []Ticket, field: *Field, index: usize) bool {
for (tickets) |t, k| {
//std.log.warn("Checking ticket for field '{}', index {}: {}",
// .{field.name, index, t});
if (!field.in_limits(t.values[index])) {
//std.log.warn("Ticket #{} has a value {} at index {} which does not match limits of field '{}'",
//.{k, t.values[index], index, field.name});
return false;
}
}
return true;
}
fn already_known_position(fields: []Field, position: usize) bool {
for (fields) |f| {
if (f.position) |p| {
if (p == position) {
return true;
}
}
}
return false;
}
fn fields_with_unknown_positions_exist(fields: []Field) bool {
for (fields) |f| {
if (f.position == null) {
return true;
}
}
return false;
}
pub fn read_tickets(filename: []const u8, a: *std.mem.Allocator) !std.ArrayList(Ticket) {
var f = try std.fs.cwd().openFile(filename, .{});
var contents = try f.readToEndAlloc(a, std.math.maxInt(u32));
defer a.free(contents);
var tickets = std.ArrayList(Ticket).init(a);
errdefer tickets.deinit();
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
var ticket = std.mem.zeroes(Ticket);
var count : u64 = 0;
var ticket_it = std.mem.tokenize(line, ",");
while (ticket_it.next()) |v| {
ticket.values[count] = try std.fmt.parseUnsigned(u64, v, 10);
count += 1;
}
try tickets.append(ticket);
}
return tickets;
}
const Ticket = struct {
values: [20]u64,
};
pub fn valid_for_any_field(value: u64, fields: []Field) bool {
var r = false;
for (fields) |f| {
r = f.in_limits(value);
// for (f.limits.items) |l| {
// if (value >= l.min and value <= l.max) {
// r = true;
// //std.log.debug("{} is at least valid for field '{}', between {} and {}",
// // .{value, f.name, l.min, l.max});
// break;
// }
// }
if (r == true) {
break;
}
}
return r;
}
fn read_fields(filename: []const u8, a: *std.mem.Allocator) !std.ArrayList(Field) {
var f = try std.fs.cwd().openFile(filename, .{});
var contents = try f.readToEndAlloc(a, std.math.maxInt(u32));
defer a.free(contents);
var it = std.mem.tokenize(contents, "\n");
var fields = std.ArrayList(Field).init(a);
errdefer fields.deinit();
var limits : std.ArrayList(Limit) = undefined;
var name : []u8 = undefined;
while (it.next()) |line| {
var lit = std.mem.tokenize(line, ":");
limits = std.ArrayList(Limit).init(a);
errdefer limits.deinit();
if (lit.next()) |n| {
name = try a.dupe(u8, n);
}
if (lit.next()) |limit_line| {
// split on the 'o', just cause. I don't think we have a handy split
// for a complete string
var limit_line_it = std.mem.tokenize(limit_line, "o");
while(limit_line_it.next()) | range_line | {
var min: u64 = 0;
var max: u64 = 0;
var range_line_it = std.mem.tokenize(range_line, "-");
if (range_line_it.next()) |v| {
min = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, v, "r "), 10);
}
if (range_line_it.next()) |v| {
max = try std.fmt.parseUnsigned(u64, std.mem.trim(u8, v, "r "), 10);
}
try limits.append(Limit {.min = min, .max = max});
}
}
try fields.append(Field {.name = name, .limits = limits, .allocator = a});
}
return fields;
}
const Limit = struct {
min: u64,
max: u64,
};
const Field = struct {
name: []u8,
limits: std.ArrayList(Limit),
allocator: * std.mem.Allocator,
position: ?u64 = null,
pub fn deinit(self: *const Field) void {
self.allocator.free(self.name);
self.limits.deinit();
}
pub fn in_limits(self: *const Field, value: u64) bool {
//std.log.warn("Testing if {} fits in limits for field '{}'",
// .{value, self.name});
for (self.limits.items) |l| {
//std.log.warn("{}", .{l});
if (value >= l.min and value <= l.max) {
return true;
}
}
//std.log.warn("{} does not fit in limits for field '{}'", .{value, self.name});
return false;
}
};
test "valid_for_any_field" {
var fields = try read_fields("test_input_fields", std.testing.allocator);
std.testing.expect(valid_for_any_field(40, fields.items[0..]));
std.testing.expect(valid_for_any_field(4, fields.items[0..]) == false);
std.testing.expect(valid_for_any_field(55, fields.items[0..]) == false);
std.testing.expect(valid_for_any_field(12, fields.items[0..]) == false);
for(fields.items) |f| {
f.deinit();
}
fields.deinit();
}
test "field_resolution" {
var fields = try read_fields("test_input_fields2", std.testing.allocator);
var tickets = [_]Ticket {
Ticket { .values = [_]u64 {3, 9, 18, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
},
Ticket { .values = [_]u64 {15, 1, 5, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
},
Ticket { .values = [_]u64 {5, 14, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
},
};
var fit = all_tickets_fit_field_limits(tickets[0..], &fields.items[1], 0);
std.testing.expect(fit);
fit = all_tickets_fit_field_limits(tickets[0..], &fields.items[0], 0);
std.testing.expect(fit == false);
try determine_field_positions(tickets[0..], fields.items[0..], std.testing.allocator);
std.testing.expectEqual(@as(u64, 1), fields.items[0].position.?);
std.testing.expectEqual(@as(u64, 0), fields.items[1].position.?);
std.testing.expectEqual(@as(u64, 2), fields.items[2].position.?);
for(fields.items) |f| {
f.deinit();
}
fields.deinit();
}

3
day16/test_input_fields Normal file
View File

@ -0,0 +1,3 @@
class: 1-3 or 5-7
row: 6-11 or 33-44
seat: 13-40 or 45-50

3
day16/test_input_fields2 Normal file
View File

@ -0,0 +1,3 @@
class: 0-1 or 4-19
row: 0-5 or 8-19
seat: 0-13 or 16-19

27
day17/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day17", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

8
day17/input Normal file
View File

@ -0,0 +1,8 @@
####...#
......#.
#..#.##.
.#...#.#
..###.#.
##.###..
.#...###
.##....#

633
day17/src/main.zig Normal file
View File

@ -0,0 +1,633 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u64));
defer gpa.free(contents);
var sim = try Simulation.init(gpa);
defer sim.deinit();
var sim4d = try Simulation4D.init(gpa);
defer sim4d.deinit();
var it = std.mem.tokenize(contents, "\n");
var y : i64 = 0;
while (it.next()) |line| {
for (line) |c, k| {
var state : CubeState = .inactive;
if (c == '#') {
state = .active;
}
try sim.add_cube([_]i64 {@intCast(i64, k), y, 0}, state);
try sim4d.add_cube([_]i64 {@intCast(i64, k), y, 0, 0}, state);
}
y += 1;
}
// Run 6 rounds
try sim.do_round(); // 1
try sim.do_round(); // 2
try sim.do_round(); // 3
try sim.do_round(); // 4
try sim.do_round(); // 5
try sim.do_round(); // 6
std.log.info("After 6 rounds, there are {} active cubes",
.{sim.count_active_cubes()});
// Part 2
try sim4d.do_round(); // 1
try sim4d.do_round(); // 2
try sim4d.do_round(); // 3
try sim4d.do_round(); // 4
try sim4d.do_round(); // 5
try sim4d.do_round(); // 6
std.log.info("After 6 rounds, there are {} active cubes",
.{sim4d.count_active_cubes()});
}
const CubeState = enum {
inactive,
active
};
const Cube = struct {
pos: [3]i64,
state: CubeState = .inactive,
next_state: ?CubeState = null,
neighbours: u64 = 0,
pub fn get_neighbour_positions(self: *Cube) [26][3]i64 {
return [_][3]i64 {
// z-1
[_]i64 {self.pos[0], self.pos[1], self.pos[2]-1},
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]-1},
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]-1},
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]-1},
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]-1},
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]-1},
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]-1},
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]-1},
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]-1},
// z+0
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]},
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]},
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]},
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]},
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]},
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]},
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]},
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]},
// z+1
[_]i64 {self.pos[0], self.pos[1], self.pos[2]+1},
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]+1},
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]+1},
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]+1},
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]+1},
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]+1},
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]+1},
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]+1},
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]+1},
};
}
pub fn print_state(self: *Cube) !void {
var stdout = std.io.getStdOut().writer();
var c : u8 = '.';
if (self.state == .active) {
c = '#';
}
try stdout.print("({}x, {}y, {}z) {c}\n", .{self.pos[0], self.pos[1], self.pos[2], c});
}
};
const Simulation = struct {
map: std.hash_map.AutoHashMap([3]i64, Cube),
allocator: *std.mem.Allocator,
pub fn init(allocator: *std.mem.Allocator) !*Simulation {
var self = try allocator.create(Simulation);
errdefer allocator.destroy(self);
self.* = Simulation {
.map = std.hash_map.AutoHashMap([3]i64, Cube).init(allocator),
.allocator = allocator,
};
return self;
}
pub fn deinit(self: *Simulation) void {
self.map.deinit();
self.allocator.destroy(self);
}
pub fn add_cube(self: *Simulation, pos: [3]i64, state: CubeState) !void {
try self.map.put(pos, Cube {.pos = pos, .state = state});
}
pub fn print_state(self: *Simulation) !void {
// @TODO Organize the output somehow
var stdout = std.io.getStdOut().writer();
var z_min : i64 = std.math.maxInt(i64);
var z_max : i64 = std.math.minInt(i64);
var y_min : i64 = std.math.maxInt(i64);
var y_max : i64 = std.math.minInt(i64);
var x_min : i64 = std.math.maxInt(i64);
var x_max : i64 = std.math.minInt(i64);
var it = self.map.iterator();
while (it.next()) |entry| {
//try entry.value.print_state();
x_max = std.math.max(x_max, entry.value.pos[0]);
x_min = std.math.min(x_min, entry.value.pos[0]);
y_max = std.math.max(y_max, entry.value.pos[1]);
y_min = std.math.min(y_min, entry.value.pos[1]);
z_max = std.math.max(z_max, entry.value.pos[2]);
z_min = std.math.min(z_min, entry.value.pos[2]);
}
// For from lowest to highest then
var z_pos = z_min;
while (z_pos <= z_max) : (z_pos += 1) {
try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
var y_pos = y_min;
while (y_pos <= y_max) : (y_pos += 1) {
var x_pos = x_min;
while (x_pos <= x_max) : (x_pos += 1) {
//try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
var c : u8 = '.';
if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
if (cube.state == .active) {
c = '#';
}
}
try stdout.print("{c}", .{c});
}
_ = try stdout.write("\n");
}
_ = try stdout.write("\n");
}
_ = try stdout.write("\n");
}
pub fn print_state_neighbour_count (self: *Simulation) !void {
// @TODO Organize the output somehow
var stdout = std.io.getStdOut().writer();
var z_min : i64 = std.math.maxInt(i64);
var z_max : i64 = std.math.minInt(i64);
var y_min : i64 = std.math.maxInt(i64);
var y_max : i64 = std.math.minInt(i64);
var x_min : i64 = std.math.maxInt(i64);
var x_max : i64 = std.math.minInt(i64);
var it = self.map.iterator();
while (it.next()) |entry| {
//try entry.value.print_state();
x_max = std.math.max(x_max, entry.value.pos[0]);
x_min = std.math.min(x_min, entry.value.pos[0]);
y_max = std.math.max(y_max, entry.value.pos[1]);
y_min = std.math.min(y_min, entry.value.pos[1]);
z_max = std.math.max(z_max, entry.value.pos[2]);
z_min = std.math.min(z_min, entry.value.pos[2]);
}
// For from lowest to highest then
var z_pos = z_min;
while (z_pos <= z_max) : (z_pos += 1) {
try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
var y_pos = y_min;
while (y_pos <= y_max) : (y_pos += 1) {
var x_pos = x_min;
while (x_pos <= x_max) : (x_pos += 1) {
//try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
var c : u64 = 0;
if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
c = cube.neighbours;
}
try stdout.print("{:02}", .{c});
}
_ = try stdout.write("\n");
}
_ = try stdout.write("\n");
}
_ = try stdout.write("\n");
}
pub fn do_round(self: *Simulation) !void {
// For each cube, check all of it's neighbours
var it = self.map.iterator();
var neighbours_to_add = std.ArrayList([3]i64).init(self.allocator);
defer neighbours_to_add.deinit();
// Get the neighbours we need possibly create for this round
while (it.next()) |entry| {
var neighbours = entry.value.get_neighbour_positions();
var n_active : u64 = 0;
for (neighbours) |n_pos| {
if (self.map.get(n_pos)) |n| {
// Noop, we already have a cube
}
else {
// The neighbour doesn't yet exist, we should create it
// but we don't want to do that while iterating over
// the current entries.
// We also want to make sure that we're not adding a
// value that's already in the list to be added.
// For the moment, we'll check that when iterating
// over neighbours_to_add.
try neighbours_to_add.append(n_pos);
}
}
}
// Add any new neighbours
for (neighbours_to_add.items) |new_pos| {
// Double-check we don't already have this neighbour
if (self.map.get(new_pos)) |v| {
continue;
}
else {
try self.map.putNoClobber(new_pos, Cube {.pos = new_pos, .state = .inactive});
}
}
self.calculate_neighbour_states();
try self.print_state_neighbour_count();
// Now next state should be set, we go through again to swap
// @TODO Update state
it = self.map.iterator();
while (it.next()) |entry| {
if (entry.value.state == .active) {
if (entry.value.neighbours >= 2 and entry.value.neighbours <= 3) {
entry.value.state = .active;
}
else {
entry.value.state = .inactive;
}
}
else {
if (entry.value.neighbours == 3) {
entry.value.state = .active;
}
}
entry.value.next_state = null;
}
}
pub fn calculate_neighbour_states(self: *Simulation) void {
var it = self.map.iterator();
while (it.next()) |entry| {
var neighbours = entry.value.get_neighbour_positions();
var n_active : u64 = 0;
std.log.warn("Checking neighbours for ({}, {}, {})",
.{entry.value.pos[0], entry.value.pos[1], entry.value.pos[2]});
for (neighbours) |n_pos| {
if (self.map.get(n_pos)) |n| {
if (n.state == .active) {
std.log.warn("Neighbour at ({}, {}, {}) is active",
.{n.pos[0], n.pos[1], n.pos[2]});
n_active += 1;
}
}
else {
// Noop, another function creates our neighbours, and it should
// be run before this one.
}
}
entry.value.neighbours = n_active;
}
}
pub fn count_active_cubes(self: *Simulation) u64 {
var it = self.map.iterator();
var count : u64 = 0;
while (it.next()) |entry| {
if (entry.value.state == .active) {
count += 1;
}
}
return count;
}
};
// Part 2, is just more tedious
const Cube4D = struct {
pos: [4]i64,
state: CubeState = .inactive,
neighbours: u64 = 0,
pub fn get_neighbour_positions(self: *Cube4D, a: *std.mem.Allocator) [80][4]i64 {
var neighbours : [80][4]i64 = undefined;
var x = self.pos[0]-1;
var idx : usize = 0;
while (x <= self.pos[0]+1) : (x += 1) {
var y = self.pos[1]-1;
while (y <= self.pos[1]+1) : (y +=1) {
var z = self.pos[2]-1;
while (z <= self.pos[2]+1) : (z +=1) {
var w = self.pos[3]-1;
while (w <= self.pos[3]+1) : (w+=1) {
if (x == self.pos[0] and y == self.pos[1] and z == self.pos[2]
and w == self.pos[3]) {
continue;
}
neighbours[idx] = [_]i64{x, y, z, w};
idx += 1;
}
}
}
}
return neighbours;
}
};
const Simulation4D = struct {
map: std.hash_map.AutoHashMap([4]i64, Cube4D),
allocator: *std.mem.Allocator,
pub fn init(allocator: *std.mem.Allocator) !*Simulation4D {
var self = try allocator.create(Simulation4D);
errdefer allocator.destroy(self);
self.* = Simulation4D {
.map = std.hash_map.AutoHashMap([4]i64, Cube4D).init(allocator),
.allocator = allocator,
};
return self;
}
pub fn deinit(self: *Simulation4D) void {
self.map.deinit();
self.allocator.destroy(self);
}
pub fn add_cube(self: *Simulation4D, pos: [4]i64, state: CubeState) !void {
try self.map.put(pos, Cube4D {.pos = pos, .state = state});
}
// pub fn print_state(self: *Simulation) !void {
// // @TODO Organize the output somehow
// var stdout = std.io.getStdOut().writer();
// var z_min : i64 = std.math.maxInt(i64);
// var z_max : i64 = std.math.minInt(i64);
// var y_min : i64 = std.math.maxInt(i64);
// var y_max : i64 = std.math.minInt(i64);
// var x_min : i64 = std.math.maxInt(i64);
// var x_max : i64 = std.math.minInt(i64);
// var it = self.map.iterator();
// while (it.next()) |entry| {
// //try entry.value.print_state();
// x_max = std.math.max(x_max, entry.value.pos[0]);
// x_min = std.math.min(x_min, entry.value.pos[0]);
// y_max = std.math.max(y_max, entry.value.pos[1]);
// y_min = std.math.min(y_min, entry.value.pos[1]);
// z_max = std.math.max(z_max, entry.value.pos[2]);
// z_min = std.math.min(z_min, entry.value.pos[2]);
// }
// // For from lowest to highest then
// var z_pos = z_min;
// while (z_pos <= z_max) : (z_pos += 1) {
// try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
// var y_pos = y_min;
// while (y_pos <= y_max) : (y_pos += 1) {
// var x_pos = x_min;
// while (x_pos <= x_max) : (x_pos += 1) {
// //try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
// var c : u8 = '.';
// if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
// if (cube.state == .active) {
// c = '#';
// }
// }
// try stdout.print("{c}", .{c});
// }
// _ = try stdout.write("\n");
// }
// _ = try stdout.write("\n");
// }
// _ = try stdout.write("\n");
// }
// pub fn print_state_neighbour_count (self: *Simulation) !void {
// // @TODO Organize the output somehow
// var stdout = std.io.getStdOut().writer();
// var z_min : i64 = std.math.maxInt(i64);
// var z_max : i64 = std.math.minInt(i64);
// var y_min : i64 = std.math.maxInt(i64);
// var y_max : i64 = std.math.minInt(i64);
// var x_min : i64 = std.math.maxInt(i64);
// var x_max : i64 = std.math.minInt(i64);
// var it = self.map.iterator();
// while (it.next()) |entry| {
// //try entry.value.print_state();
// x_max = std.math.max(x_max, entry.value.pos[0]);
// x_min = std.math.min(x_min, entry.value.pos[0]);
// y_max = std.math.max(y_max, entry.value.pos[1]);
// y_min = std.math.min(y_min, entry.value.pos[1]);
// z_max = std.math.max(z_max, entry.value.pos[2]);
// z_min = std.math.min(z_min, entry.value.pos[2]);
// }
// // For from lowest to highest then
// var z_pos = z_min;
// while (z_pos <= z_max) : (z_pos += 1) {
// try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
// var y_pos = y_min;
// while (y_pos <= y_max) : (y_pos += 1) {
// var x_pos = x_min;
// while (x_pos <= x_max) : (x_pos += 1) {
// //try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
// var c : u64 = 0;
// if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
// c = cube.neighbours;
// }
// try stdout.print("{:02}", .{c});
// }
// _ = try stdout.write("\n");
// }
// _ = try stdout.write("\n");
// }
// _ = try stdout.write("\n");
// }
pub fn do_round(self: *Simulation4D) !void {
// For each cube, check all of it's neighbours
var it = self.map.iterator();
var neighbours_to_add = std.ArrayList([4]i64).init(self.allocator);
defer neighbours_to_add.deinit();
// Get the neighbours we need possibly create for this round
while (it.next()) |entry| {
var neighbours = entry.value.get_neighbour_positions(self.allocator);
//defer self.allocator.free(neighbours);
var n_active : u64 = 0;
for (neighbours) |n_pos| {
if (self.map.get(n_pos)) |n| {
// Noop, we already have a cube
}
else {
// The neighbour doesn't yet exist, we should create it
// but we don't want to do that while iterating over
// the current entries.
// We also want to make sure that we're not adding a
// value that's already in the list to be added.
// For the moment, we'll check that when iterating
// over neighbours_to_add.
try neighbours_to_add.append(n_pos);
}
}
}
// Add any new neighbours
for (neighbours_to_add.items) |new_pos| {
// Double-check we don't already have this neighbour
if (self.map.get(new_pos)) |v| {
continue;
}
else {
try self.map.putNoClobber(new_pos, Cube4D {.pos = new_pos, .state = .inactive});
}
}
self.calculate_neighbour_states();
// Now next state should be set, we go through again to swap
// @TODO Update state
it = self.map.iterator();
while (it.next()) |entry| {
if (entry.value.state == .active) {
if (entry.value.neighbours >= 2 and entry.value.neighbours <= 3) {
entry.value.state = .active;
}
else {
entry.value.state = .inactive;
}
}
else {
if (entry.value.neighbours == 3) {
entry.value.state = .active;
}
}
}
}
pub fn calculate_neighbour_states(self: *Simulation4D) void {
var it = self.map.iterator();
while (it.next()) |entry| {
var neighbours = entry.value.get_neighbour_positions(self.allocator);
//defer self.allocator.free(neighbours);
var n_active : u64 = 0;
//std.log.warn("Checking neighbours for ({}, {}, {})",
// .{entry.value.pos[0], entry.value.pos[1], entry.value.pos[2]});
for (neighbours) |n_pos| {
if (self.map.get(n_pos)) |n| {
if (n.state == .active) {
//std.log.warn("Neighbour at ({}, {}, {}) is active",
// .{n.pos[0], n.pos[1], n.pos[2]});
n_active += 1;
}
}
else {
// Noop, another function creates our neighbours, and it should
// be run before this one.
}
}
entry.value.neighbours = n_active;
}
}
pub fn count_active_cubes(self: *Simulation4D) u64 {
var it = self.map.iterator();
var count : u64 = 0;
while (it.next()) |entry| {
if (entry.value.state == .active) {
count += 1;
}
}
return count;
}
};
test "get_neighbour_positions" {
var cube = Cube{
.pos = [_]i64{0, 0, 0},
};
var neighbours = cube.get_neighbour_positions();
for (neighbours) |n| {
std.log.warn("({}, {}, {})", .{n[0], n[1], n[2]});
}
}
test "small_cubeway" {
var sim = try Simulation.init(std.testing.allocator);
defer sim.deinit();
try sim.add_cube([_]i64 {0, 0, 0}, .inactive);
try sim.add_cube([_]i64 {1, 0, 0}, .active);
try sim.add_cube([_]i64 {2, 0, 0}, .inactive);
try sim.add_cube([_]i64 {0, 1, 0}, .inactive);
try sim.add_cube([_]i64 {1, 1, 0}, .inactive);
try sim.add_cube([_]i64 {2, 1, 0}, .active);
try sim.add_cube([_]i64 {0, 2, 0}, .active);
try sim.add_cube([_]i64 {1, 2, 0}, .active);
try sim.add_cube([_]i64 {2, 2, 0}, .active);
try sim.print_state();
sim.calculate_neighbour_states();
try sim.print_state_neighbour_count();
std.testing.expectEqual(@as(u64, 5), sim.count_active_cubes());
std.log.warn("\n\n --- First round --- \n", .{});
try sim.do_round(); // 1
try sim.print_state();
std.testing.expectEqual(@as(u64, 11), sim.count_active_cubes());
try sim.do_round(); // 2
try sim.do_round(); // 3
try sim.do_round(); // 4
try sim.do_round(); // 5
try sim.do_round(); // 6
var active = sim.count_active_cubes();
std.testing.expectEqual(@as(u64, 112), active);
}
test "4d_cubeway" {
var sim = try Simulation4D.init(std.testing.allocator);
defer sim.deinit();
try sim.add_cube([_]i64 {0, 0, 0, 0}, .inactive);
try sim.add_cube([_]i64 {1, 0, 0, 0}, .active);
try sim.add_cube([_]i64 {2, 0, 0, 0}, .inactive);
try sim.add_cube([_]i64 {0, 1, 0, 0}, .inactive);
try sim.add_cube([_]i64 {1, 1, 0, 0}, .inactive);
try sim.add_cube([_]i64 {2, 1, 0, 0}, .active);
try sim.add_cube([_]i64 {0, 2, 0, 0}, .active);
try sim.add_cube([_]i64 {1, 2, 0, 0}, .active);
try sim.add_cube([_]i64 {2, 2, 0, 0}, .active);
try sim.do_round(); // 1
try sim.do_round(); // 2
try sim.do_round(); // 3
try sim.do_round(); // 4
try sim.do_round(); // 5
try sim.do_round(); // 6
var active = sim.count_active_cubes();
std.testing.expectEqual(@as(u64, 848), active);
}

27
day18/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day18", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

381
day18/input Normal file
View File

@ -0,0 +1,381 @@
(7 * (7 * 6 * 4 + 3)) * 3 + ((8 + 5 * 3 + 7 + 8) + 3 * (2 + 9 * 5 + 7 * 5 * 6) * 2 + 3 * 9) + (4 + 5 + 5 * 2 + 2) + ((5 + 6 + 9 + 6) + 3 + 4 * 6 * 5)
7 * 5
(9 * (9 + 7) * 7 + (4 + 5 * 5 + 2 + 3) + 3) * 7 * 5 + 8 + (4 + (7 + 9 + 6 * 9) * 2)
((6 + 4) * 6 * (5 + 3) * 9 * (3 * 5 * 5 * 9 * 4 + 9) * 4) * 2 * 8 + 9
7 * 7 + (9 + 2 * 9 + 9)
9 + (7 * 7 * 5 * 9 * 7) * 2 + 3 * 3
5 * (5 * (8 * 4) * 7 + 8 + 7) * (5 * (4 * 3 * 5 + 2 * 5) + (6 * 6 * 7 * 2 + 2) + 4) + (5 + 4 * 7 + 5 * 9 + 9) * 2
((7 + 3 + 8) + (2 + 6 * 4 * 5)) + 8
8 * (6 * 7 + 3 * (8 * 5 * 2 * 4)) * (3 + (5 + 5 + 6) * (4 * 3 + 7 * 5 + 7) + (3 * 5 * 9 * 3)) + 8
6 + 4 + 8 + 4 * ((3 + 5 * 8) + 7 * 7 * 8 * 7 * 2)
3 * (9 + 4) * (9 + 2 + 6 + 5) + 4 * (7 * 2) + 6
4 * 6 + (8 + 3) + 7
2 + (8 * (5 + 6 * 5) + 9 * 7 + (7 * 7)) + 5 + 5
(8 + (5 * 7 * 3 + 6) + 8) * 8 + 6
8 * 6 * 6
8 * 6 + (9 + 4 * 5 * 3) * 9 * (4 * 2 + 6 + 7 + 4 * 8)
(5 * 9 * 8 * 9 * 6) * 8
7 * 5 + ((2 * 7 * 5 + 2 + 6 + 3) * 9) * 5 + ((2 * 2 * 4 + 3) * 5)
(2 + 3 * 4 * (2 + 4 * 9 + 8) * 8) + 6 + 8 + 7 * 2
3 + 7 + (3 * 4 * (8 * 6 + 8 * 8 * 2 + 9)) * 4
9 * 9 + 9 + (3 * 7 * 9 * 4)
(7 * 7 + (2 * 5 * 8) * 4) * 9 + (9 + 4 * 8 * (9 + 3 * 5 * 4 * 7 * 4)) + 3 * 3
7 + 6 + 3 * 8 * 4 * (9 * 4 * (5 + 7 * 2 * 8 + 7 * 8))
(7 + 2) * 5 * 8 + 6 * 2
9 + 4 + (5 + (7 * 7 * 9 + 5) + 6 * 5 + 2 * (4 * 7 * 7 + 8 * 5 * 5)) * 2 + 2
8 + 2 * 2 * (2 + (2 + 7 + 7 * 7 * 3) + 7)
3 + 4 * (3 + 3 * 3 + 4) * 9 * 6 + 8
((4 + 4 + 6) + (5 * 5 + 4 * 9 * 5) + 5) + 2 * 2
9 * 5 * 6 * 2 + 6 + (2 * 9 + (2 * 3 + 4))
(3 * 9) + 2 * (2 * 5 + 7 + 9 * 7 * 6) + 5 * 5 * 2
7 + 3 + 5 * 6
7 + 5 + (2 * 8 + (6 * 6) + 6) + (4 + 7)
2 * (9 + 5 * 3 + 5 + 5 + 4) * (3 + 4 + 3 + 5 + 2 + 7) + 2 * 2
(4 * 5 + 6 * 3 + (5 * 3)) * 5 + 5
9 + 8 + 7 * (7 + 9 + 2 * 2 + 7) * 7
3 * 3 * ((4 + 3 * 4 * 2 * 2 * 6) * (9 + 6) * 3) * 5
9 + 6 + 7 + 6
8 * (4 * 8 * 8 * 7 + 4 + 9)
2 + (7 * 9 * 2) + 6 * 6 * 4 * 6
((4 * 6 + 7 + 9 * 4) + 9) * 4 * ((6 * 3 + 3 + 9 * 7) * 8 * 4 * 5 * (2 * 6 * 8 * 5 + 5 * 3)) * 7
(4 * 7) + 5
6 + 9 * 6 + 9 + ((5 + 7 * 5 * 8) + 7 + 7 + 8 * (2 + 8 * 2 * 4 * 7 + 9) * 7)
6 + 3 + (9 + 6 * (4 + 7 + 4 * 6 * 7)) + 6
5 * 7 * (4 * 6 * (3 + 8 + 6 * 8)) + 8
(5 * 6) * 8 + 2 * 3 + (7 + 4 + 3)
3 + 4 * 9 * 2 + (7 + (5 * 9 * 7 + 7 * 4) * 4) + 3
2 * 9 + ((3 + 5 + 2 + 9 * 9 + 6) + 4 + (6 * 4) + 2) + 3
3 + 6 + (3 + 6 + 8 + 2 + 2)
8 * ((8 * 6) + (7 + 2 * 2 * 2 + 4 * 3) * (9 + 8 + 4 * 8) + 8 * 4) + 2
9 + 4 * (7 * (2 * 4 + 9 * 3 + 7) * 8 + (4 * 3 * 9 + 9 * 5 + 7) + 9 * (6 * 4 * 2)) + ((5 + 6 + 7 * 9 * 6 + 6) + (6 * 2 + 8 + 9 + 4 + 4) + (8 * 5 * 2 + 6 + 7) * 5 + 3) * 9 * 8
9 + 2 + (5 + 3 * 2 * (7 + 4 * 5 * 5 + 3 * 7) * 8 * (5 * 6))
7 * (3 + 3 + 7 * 7 * 9) + (2 + 5 * 6 * 4)
9 + 8 + 9
8 * (7 + (5 * 7) + (7 + 3) * 2 + 7) + 4 * 3
2 * (2 * 6 + 5 * 7) * 2 + (3 + 3) * ((2 * 3 + 2) + (5 * 3 * 4 + 8 * 2))
4 * (3 + 7 + 6 + 8 + 3 + 6) + 8 + (2 * 3 * (5 * 2 + 6 + 5 * 8))
2 + 5 + 3 + 2 + 4 + (2 + (6 + 4) + 5)
2 * (4 * 4) + (5 + 2 * (4 + 2 * 2 + 4) * 4 + (5 * 9 * 9) + 2)
(6 + 9 + (3 + 5 * 3) + 4 * 2 * 2) + 7 + ((6 * 6 + 4 * 5 * 5 + 4) + 5) + ((8 + 4 + 9 * 8 * 9 + 2) + (7 + 2 + 9) + 4) + 5
7 * 3 + (6 + (8 * 5) * 6 * 8) * 2 * 9 * 4
9 + 9 + 9 + 2
(7 * 9 * 2 + 8 * 7 * 4) + 9 + (9 * 6 * 9 + 7) * 3 * (9 * 5 * 5)
4 * 7 * ((7 + 9 * 5 * 4 + 7 * 4) + (2 + 3 + 5 * 4 + 2) + (2 + 5 * 8 * 5 * 5 + 6)) * 6
5 + 8 * (9 + (9 + 3 + 9 + 5 + 5))
(3 * 7 * 2 * 3 + (8 + 8 + 3 * 9)) + 8 + 8 * 6 + 8 + 6
9 + 4 + 8 * (7 * 8 + 8 + 4 * 8)
2 * 9 + 2 * (5 + 3) * 2 * (5 * 5 * 8 + (3 + 4 + 4 + 5) + 4 * 4)
5 * 7 + 2 * ((2 * 8 * 8 + 8 * 2 * 7) * 6 * 7 + 7 + 2) * 2 + 9
4 * (6 * (6 * 3 * 3)) * (7 * 5 * 4 * 2 * (5 + 5 + 8 * 3)) + 7 + 7 * 8
3 * 2 + 4
9 + 6 * 2 * 4 + 2
((5 * 5 + 3 + 7 * 2) * 2 * 5 + (9 + 9)) + 3 + 6 * (9 + 8) * 8 * 9
4 * (8 + 2 + 3 * 9 * 6) * 6 * 3
2 * (9 * 6 + (8 + 6 * 4) * (5 * 5) + 9 * 2)
6 + (3 * (6 * 6 + 4 + 5) + 3 * 5 * 4 + (6 + 9 + 4 * 5 * 3)) + 6 * (3 + (6 + 5 + 5 + 6) * 8 + 8 * 4) * 4 + 6
9 * 9 * 2 + (6 * 4 * 2 + 4 * 7 * 9) * 7 + ((5 + 6 + 7 + 7) * (7 * 3 + 9) + 9)
(2 + (6 + 8 + 6 * 5 + 5) + 8 * 5) * 9 + 3
2 * 9 + 2 + (9 * (4 + 6 + 4 + 2) * 9 * 5 + 7 + 2)
8 + 6 + 4 + 6
3 + ((6 * 4 + 2 + 4 + 3 + 8) * (4 * 3) * (9 + 4 * 6 + 2 * 7 * 6)) + 5 + 7
3 * (8 * 4 + 9 + 4) * 7 * 2 + ((5 + 9 * 6 * 4 * 4) * 8 * 4 * (6 + 2))
((8 * 7 + 6) * 3 + 2 + 5) + 8 * 5 * 8
(3 * 2 * 6 * 3 * 2) * 6 * 2 * 9
(4 * 8 * 3 + 5) + (8 + 9) + 7 * 7 + 3 * 3
(2 + 7 * (7 * 8)) + 8 + (6 * (4 * 8) * 4 * 2 * 8) * 4 * ((7 + 8 + 4 + 3 + 6) * 4 + 9 + 4) + 3
((7 + 2 + 3 * 3) * 5 * 5 + 4) + 9 * 2 + 7 + 9 + 2
(6 + (2 + 7)) * 4 + 7 + 8 * 5
(9 * 8) + (8 + (2 + 4 + 5 + 6 * 9) + 2 * (8 + 9))
2 * (9 + 8) * 8 * ((7 * 6 + 7 * 3) + 2 + 5 * (7 * 2 + 7 + 8) + 3 * 3) + 8
4 * 6 + 6 + 4 * 9
(2 + 4 + 5 + 3 + 6) + 3 * 3 * 3 + (5 * 2 * 9 + 6 * 6 + 5)
7 * 5 + (6 + 2 * 2 * 8 + 5) * 6 + 6
(5 + 8 + 2) + 3
3 + 3 * 5 * ((3 + 8 + 5 + 9) * 4 + 4 * 4 + 4) + 8 * 3
2 + (5 + 5 + (6 * 5 * 2 * 8) * 4 + 8)
8 + (5 * 7 * 2 * 2) * (7 + 9 * 5) * 2 + 9 + 4
((9 * 9) + 6 + 4 + 9) * 5
5 + 3 * ((4 + 8) + 9 * 2 * 6 + 7)
6 + 7 + 5 * (2 + 9 * 4 * 5 * 7 + 5) + 9 * 4
(7 * 2 + 4 + (8 * 8 + 2 * 5 * 3 * 6)) + (4 + 4 * 3 + 7) + 4 * 6
2 * (5 * 9 * (5 + 3 * 5) * 5 + 6) + 4 + 5
5 * (4 + 7 + 4)
9 * 7 + 8 + 4 + (6 * (6 * 2 * 4 + 9)) + 5
6 * 3
(5 * 6 + 2 * (2 + 5 * 6 * 4 + 9 + 2)) + (4 + 3 * (9 * 9 + 4 * 8 * 8 * 9) * 4) * (8 + 7 + (4 + 8 * 2 + 4) * 9)
8 * 5 + 9
7 + 4 * 9 * 6 + 6
9 + 6 * (8 * (7 * 6 + 2 + 4 + 6 + 9) * 2 + 2 + 2 + (7 + 7 + 9))
6 * (7 * 6 * 6) * 9 * 6 + 7
(5 * 7 + 9) * 7 + ((4 * 5 + 3) * 5 * (3 + 8 * 7) + 2 + 3 * (7 + 6 + 2)) + (3 * 5 * 5) + 2
4 * 2 * 2 * 2 * (6 + 4 + 9 + 4 * 5)
((9 * 7 + 7) + 8 * 7) * 4 + (7 + 9 * 9) * 6
8 * (6 * (8 + 4) + (5 + 6) * 6) * 7 + 4 * 7 * 2
(7 + 7 * (8 * 5 + 4)) * 5 * (3 * 6 * 2 * 3 * 9) * 3
4 + (7 * 5 * 3 * 5 + 3 * 5) * 7
(6 + 5 + 6 * 3 * (6 * 4 + 6)) + 2 * 5 * 9 + 3 * 5
3 * (6 + 3 + 5 * 3) + 6 * 3 + (7 + 8) * 9
(3 + 8 + (5 * 4 + 4 + 7) + 5 * 2) + 2 + 5 + 6 * 9 + (4 + 2 + 6)
9 * 8 + (3 + (4 + 2 * 8 + 7 * 5 + 3) + (3 * 3) * 3 + (2 * 8))
7 * 4 + (3 + 7 + 6 + 4 * (3 * 6) * 2) + ((5 + 5 * 5) + 6 + 2 * (2 * 3 * 3 + 3))
9 * 5 * (6 + (2 * 3)) + (3 * 4 + 3 + 9 + 6) + (9 + 5 + 2 + (3 * 4 * 9 * 9 * 5) + 2 * 7) * 5
(6 + 9 * 4 + 5 * 4 * (8 + 2 * 4 * 2 * 3)) + 4 * 9 + 6 * (4 * 5 * 9)
9 * 7 + (2 + (6 + 3) + (4 * 3 + 9) + 9) + 8 + 9 * 3
3 * (8 + 7 + 7 + 8) * (5 + 5 + 2 + 6 + 9 + 7)
7 + (7 * 5 + 3 * 4 * 9 + 2) * (8 * 6 + (5 + 2) + 6) * 4 + (6 * 3) + 2
(4 * 5 + 7 + 3 * (7 * 8) + 8) + 6 * 2 + 9 + 3
7 * 4 * 8 * (7 + 5 + 2) + (8 * 8 * 2) + 3
7 + 7 * (6 + (4 * 7 + 3 + 2 + 7) + 3)
2 + (8 + (5 + 9 + 2 * 6 * 6 + 8) * 8 + 2 * (5 * 2 + 8) * 4) + 2 * 6
(4 * 9 * (7 * 6 * 9 + 8 * 6) * 9) * 2 * 2
3 + (8 + 2 + (2 + 3 * 2) * 6 + (5 * 8 * 8 * 8 + 2 + 3)) * 4 * (9 + 3) * 6
8 + 3 * (3 + 5) + 3 + 5
4 + ((9 * 5 * 2 + 7 + 5) + 6 + 3 + 6 * (7 * 6) + 6) * 2 * 3 * (3 * 9 + 9)
((4 * 9) * 8 * 6) + 8 * 8 + 6 + ((6 + 4 + 7) * (2 + 2 * 4 * 9) + 3 + (5 * 9 + 9 * 9 + 5) + 2)
(8 * 4) + (8 + 8)
((4 + 5 + 2 * 4 * 7 + 3) * 6 * (4 * 6 + 8) * 9 * (9 + 7 + 5 + 3)) * 5
8 * 2 + 8 + (7 * (8 + 2 + 6 * 7 + 9) + (5 + 9 + 3) + 6 * 6) * (8 + (4 * 2 + 4 + 7 * 5) + 2 * 6) * 5
(2 * 5 + (8 * 7 + 9 + 2 + 2)) * 2 + (8 * (2 + 4) + 4 * 5 + 7) + 4
4 + (2 + (4 * 3 * 9) * 5 * 4)
((3 + 4) * 7 + 6 + (5 * 3 * 8 + 8 * 9) * 3 + 6) + 8 * 4 * ((7 + 4 * 3) * (6 + 9 + 9 * 4 * 7) + 9 + 5 + 2 + (5 + 8 * 4 * 6 + 4 * 8))
4 * (9 * 5 * (5 * 7 * 7 + 4)) * 5 * (5 * 7 + (4 * 5) * 4 + 9)
5 + (8 * 6 + 8) + 8
7 + (8 + 6) * 4 + 2
(3 * (9 + 6 * 8)) * 8
3 + 6 + 4 + ((5 + 4 * 2) + 7)
7 * 3 + 5 * (2 * 5 + 4) * 8
5 * 5 + (6 * (8 + 5) * 7) * 7 + 4
7 + 9 + (2 + (3 + 8 + 4) + 9 * 2 + 6) * (7 + (3 + 6 * 8 + 8 * 7) + 9 * 3 * 8 + (9 * 6 + 2 + 8 + 4 * 4))
6 * (2 * 8 + 3 + 5 + 5) + (3 + (8 * 2 * 3) * (2 + 9 * 8 * 5 + 3) + 4 + 7) * 7 + (5 * 5 + 7)
(2 * 2 * 6 * 4 * 9 + (9 * 5 + 7 * 4 + 6 * 2)) * 4 + (4 + (8 * 2 + 3 + 6))
2 + (8 + 4 * 8 + 3) * 6 + 7 + 4
(6 + 6 * (2 * 5 * 5 * 4 * 5 * 4) + 8 * 7 * 3) + 5 + (3 * 6 + 3 * 7) + 5 + 5 * 3
2 * (8 + 2 + 6 * (9 * 9 * 9 + 4 * 2 * 7) * 3 * (4 + 6 * 3 + 8 + 4)) + 8
(6 * 7 + 8 * 6 * 7 + (5 + 9 * 3 + 6 + 9 * 5)) + 2 * 6
(7 + 2 * 4 + 3) + 4 * 5 + 3
((7 * 7 + 2 + 7) + (3 + 3 + 5 + 9 * 3 + 2) * (2 * 4 * 7 + 6 * 3)) * (2 + (7 + 4 + 3 * 9 + 4 * 5) * 4 + 3 * (5 + 8 * 3)) + 5 + (2 + 8 * 2 * 8 * (6 * 7 + 4 + 5)) * (3 * (7 * 6 * 3 * 8)) + 7
3 * 4 * ((8 + 8 + 9) * 6 + 6 + 7 + 6) + 8 + 3
(6 + (7 * 4) + (9 + 6 + 3 * 9)) + 2 * (4 + 6 * 5 + (2 + 8) * 5 + 9) + 3 * (6 + 8 + 8 * (7 * 8 * 3 * 2 + 2 + 8))
(9 + 8 * 4 + (5 * 8 + 7 * 2 * 8 * 9) * 8 + 9) * 3
9 + ((5 * 3 + 6) + (8 + 6 * 6 + 7 + 2 + 8) * 8 + 5 + (9 + 8 + 2 * 9 + 2)) * 7
((8 + 2 + 6 + 3) * 8 + 5 + 8 + 2) * 9
(6 + (4 * 4 * 7 * 2 + 6) * 4 + 2 * 8 * (6 + 2 * 8)) * 2 * 8
3 * (4 + 3 + 3 + (3 * 7 * 7)) + 6 + 7 + 4 + 8
(6 * 8 + 7) * 8 * 9 + 8 + 4
(7 * 7) * 2 + (8 * 7) + 4 * (5 * 2 * (3 + 4 + 7 * 8 * 3) * 9) + 6
7 + (9 * (6 + 8 * 7 + 6 * 3) + 4) * 4 + 3
6 + 3 * ((2 + 2 + 3 + 9 + 9 + 8) * 6 + 2) + 5
3 * 6 * 6 + 2 + 2 + (2 * 2)
6 + (4 + 9 * (5 + 9 * 4 * 6 + 6) + 4 * 6 * (2 * 7 * 7 * 4 + 8)) + 5
((2 + 6) + 2 + 5) + 7 + 3 + 5 * 3 + 5
(6 * (2 + 8 + 7) + 4 * (2 + 8) * 9) + 9 * 6
(2 * (9 * 4 * 3 * 2) + (4 + 4 * 3 + 2)) + 4
(6 + 4 * (5 + 9)) + 7 * 7 * 8 * 5 * 3
(3 + (5 + 4 * 3 + 9)) * 2 * (9 + 6 * 6 * (7 + 8 + 2 * 5) * 8 * 6)
8 + 6 * 6
8 + (8 * 9) + 5
8 + (7 * (6 + 8) * 7 * (5 * 7 * 8 * 7) + (8 + 4 + 6 * 9 + 8) + 4) + (6 * 4) * 3 * 7
9 + 4 + 3 * 7 * 5
(8 + 9) + 6 + 4 * 7
5 * (4 * 6 + 4 + 2 * (5 * 2 * 2 * 8)) * 3
3 * 3 + 2 + ((8 + 5 + 4 + 8 + 8) * 7 * 6 + 9 * 8)
9 + (8 + (8 + 9) + 7 + 8)
(8 + 2) + (2 + 5 + 7) + 6 * 6 * 6 * 6
5 + 7 + (5 + 4 * (5 * 6 + 3 + 3) + (7 * 9 * 5 * 6 * 6 + 3) * 8) * 7
6 + ((7 * 3) * 6 * 5 + 5 + (3 + 3 + 9)) + (6 * 2 + 6 + 9 + (2 + 4 * 3 * 4) + 7)
8 * 5 + (9 * 2 * 7 * 2 * 6 + 8) * 2 + 2 + 6
6 * 8
(2 * 3 + 5 + (8 + 6 * 8 * 7 * 2)) * 3 + 2 + 6 + 2 * 5
(7 + 6 * (2 + 2 * 4 * 9 + 7 * 5) * 4 + 2) + 4 * (9 + 6) + (9 + 5) + 7
5 * (3 + 7 + 7 * 4)
2 * ((2 * 7 * 8 * 4 * 3 + 7) + 6 + 3) * 5 * 7
8 * 4 + 7 + (6 * 4 + 3 + 2) + 7 * 8
7 * 9 + (2 * 9 * 2) * 6
8 + (6 * (2 + 8) + 9) + (7 + 6 + 6 * (8 * 3 * 5 * 5 * 9) + 3 + 7) + 8
2 + 5 * 4 + (4 * (3 + 7 * 5 + 8) * 8 + 2) + 3 * 7
(8 * (9 * 7 + 9 + 9 + 4) * 3 + 2) * 8
4 + (6 + (2 + 4 * 6) + 4)
(8 * (4 + 6 + 2 * 6 + 7)) * 9 + 8 + 3 * 5
((2 * 7 + 3 * 5) * (5 + 7 + 7 + 3 * 7 * 3) * 8) * 2 * ((2 * 9 * 4 * 6 + 4) + 6 + (8 * 5 * 4 * 5 * 6 * 8) + 7 * (9 * 6 + 7 * 3 + 4 + 7)) + 9
6 + 8 + (3 * 3 + 2) + 5 + 4
5 * 6 + 6 * 5 * ((3 + 5 * 8 + 4 * 8) * 9 * 9 + 6 * 4 + 6) + (4 * 7 * 5 + 9 + 7)
2 * 7 * (4 * 7 + (4 + 7 + 4 + 3 * 2 + 7) + 7)
((8 + 3 * 6 * 6 + 4) + (9 + 5 + 3 * 3) + 7 * (3 * 4 + 4 + 9 * 4 + 6) + (8 + 5 + 2 * 2 * 5)) * 8 * 6 * 7 + ((5 + 6 + 2 * 4 + 2) * (9 + 8 + 9) + 6 + (6 * 5 * 9 + 7) * 4 * 6) * 7
4 * 5 * (9 * 3) + (9 + 6 + 5 * 8)
3 * 8
9 + 2 * (7 + (2 + 9) * 9) + 4 * 4 * 8
(8 + 4 + 7 * 2 + 8 * (8 + 7 * 4 + 4)) + 4
4 + 8 + ((7 * 9 + 9) + 3 + 2 + 3) * 8
(6 + (4 + 3 + 8 + 6 * 8)) * (5 + 9 * (5 + 2 * 7 + 8) + (6 * 7 * 4 + 2 * 5) + 4 * 9) * 8 * 5
8 + 3 + 4 * 9 * ((4 * 9 + 3 + 6) + 3 * 3 + 9) * 2
6 + ((3 * 2) * (4 + 9 + 9 * 5 * 2) * (2 * 8 + 4 * 7 + 4 + 8)) * 5 + (9 * 4 * 6 + 6 * 4 + 8)
2 + (5 + 4 * 8) + (9 * 9)
8 * 3 + 7 * 3 + ((2 * 2 + 6 * 3) * 3 * 7 * 8 + 5) + 9
4 * 7 + ((6 + 7 * 3 * 4 + 8) * 2 + 6 + (4 * 6 + 9 + 6 * 8 * 3) + 3 * 3) + 3
5 * (9 * 9 + (7 + 6 + 2 + 9 + 9 + 9)) * 8
5 + 4 * 2 + 7 * (5 * 5 + 2 + 3)
2 * 2 + 6 + ((2 + 2 + 5) * 6 * (2 + 7 + 3 * 9) * 5 + 9 * 8)
((2 * 4 + 7) + 9 * 8) + 5 * 6 * 2 + 9
6 + ((7 * 9 * 9 + 2) * 2)
6 * (7 + (4 + 7 * 2) * 5 + 2 + 7) + 6 * 7 + 5
8 * (6 * 8 + (7 + 2 + 7) + 3) + 7 + 6
(7 * 2 * 3 * 7) + 4 * 3 + 6 * 9 + 7
8 * 7 * (8 * 9 * 3)
9 + (9 * 4 * (9 + 3 * 5 + 9 + 9) * 8 + 5 + 9)
6 * (9 * 2 * 9 + 6 + 9 + 8) + (6 * 9 * 5) + 2 * 4
2 * 5 * (7 + 8 + 3 + 8 + 6 * 4) * 4 + 5
2 * 2 * (4 + 3) + 2 + 4 * 4
(6 * (9 * 6 + 2 * 2) * 4 * 3 * 4 * 7) + 2
(2 * 5) * 3 + 3 * 3 * 7 * 8
3 + 6 + ((6 * 6) * (9 + 8 * 2) * 7 + 5 + 9 * 2)
9 + 7 + (2 * 8)
(8 * 7) + (8 + 6 * 7 + (3 * 9 + 6) * 6 + 8) + (4 * 2 * 9)
2 + 2 + 2 + 9 * ((4 + 5 * 7 * 5 * 4 * 7) * (9 + 9) + 4 * 4 + 9) * 8
4 + 2 + ((6 + 8 * 4 + 7) * 7 + 3 * 9 + (9 + 5))
7 + 8 * (3 * (3 + 9 + 6 * 5) + 6 * 8) * 7 + 4
8 + 7 * (2 * (5 * 7)) + (4 * 3 + 7)
(2 + 8 * 7) + ((8 * 9 * 3 + 3 + 5 * 7) * 2 * (9 + 6 * 3 * 5) * 4 * (4 + 6 * 6 + 4 * 9) * 3) * 6 + 4 * 4 + 2
3 * (9 + 4 + (9 + 5 + 8 + 6 * 3 * 4) * 8 + (9 * 3 + 8 + 4 + 7)) * 8
(4 + 4 * (4 * 7)) * 2 + 7 * 3
((4 * 9) * (9 + 6 + 9 * 8 + 7)) + 6 + 7 + 7
6 + ((9 * 5 + 9 + 6 * 6 + 4) * 7 + (9 + 5 + 5) * 9 + 3) * (5 * 9) + 8 + 9
(3 + 8 * (7 * 3 * 4)) * (6 * (6 + 4) + (9 + 8) * (2 * 5 + 4) + (8 + 5 * 6 + 5 * 2 + 2)) * 6 + 9 + (7 + 6 * 5) + (5 + 4 + (6 + 8 * 2) * 2)
4 * ((6 * 8 + 7 * 6 + 4) + 4)
((5 * 6) + 4) + (9 + 4 + 9) + 2
5 * 9 * 7 * 6 + (9 * 7)
5 + (2 + 7) * 5 + 9 + 7
6 * 2 * 8 + 4
(3 + 2 * 4 + 8) + ((7 * 5 + 7 * 2 * 8) + 7 + 2) * 6 * 2 + 5
(2 * 5) * (3 * 9 * 4 * 8 + 5 * 3) * ((9 + 5 * 6 * 3) + 3 * 7 + 4) * 5
((3 + 6 * 3) * (4 + 9 * 5 * 6 + 4 * 7)) + ((8 * 7 * 2 + 7) + 5 * 6) * 6 + 7
(8 + 4 * 8 * 8) * 9 * 9 + 7 + 4
(7 * 9 + 5) * 5 + (9 + 4 + 4 + (7 * 9 * 2 * 8 * 2 + 9)) * ((7 * 5 * 7 * 3 * 7) * 5 * 2) + 8
5 + (6 * (8 + 9) * 7 + 9) + 3 + 3
8 + 8 * (6 * 5 * (3 + 5 + 9 * 2 * 9 * 7))
5 * (4 + 7) * 5 + 7 + 8 + 6
3 * ((5 + 6 + 2 + 7) * 4 * 6) * 5 * 5
(6 + 3 * (9 * 9 * 7 * 8 * 9 + 9) + 5) * 8 * 6 + 7 + 2
8 * (4 + 3 * 5 + (5 + 2 * 3 + 8) * 2 + (8 + 7 * 7 + 4 * 7 + 7)) + 8 * 6 + 4 * 5
4 + 7 * 8 * (2 + 6 + 5) * (4 + 8 + 4)
9 + 8 * ((2 * 3 * 6 + 4 * 2) + (6 * 5 * 9 + 7) * 5 * 2 * 9 * 7) + (9 + 4 * (2 * 8 * 7) * 3 + (9 + 8)) + 3 + 6
7 * 3 * 8 + ((6 + 7) * 9) * 2
5 + 3
4 + 9 * 7 * ((7 * 8 + 7 * 2 + 5 * 7) + 5 * 4) + (5 * 5 + (7 * 6) * 6)
((2 + 4) * 5) * 3 + 5
5 + (2 + 8 * 9 * 6 * 2 * (2 + 8 + 3 + 5)) * 9 * 8 + 3 * (9 + (4 + 2 + 4 + 7 * 4) * 9 * 9 + 7)
2 + 6 * 9 + 3 + (7 + 8 + 2) * 4
5 * 4 * (2 * 4 + 3 + 3 * (9 + 6 + 6) + (3 * 8 * 4)) * 4 * 3 + (9 * 7)
7 * (5 * 5 + 4 + 8 + (3 * 4 + 6 + 9)) * 2 * 9 * (6 + 7)
2 + (5 + 3 * 5 * 8) + 3 * 8 + (9 + 9 * 8 * 2 * 2)
((7 + 9 * 9) * 7 * 2) + 6 * 6 * 9
(6 * (9 + 9 + 4 + 5 + 6 + 2) + 6 + 8 + (7 * 3 * 8)) + 2 + 6 + 2
(3 + (6 * 2 + 2 + 6 * 7 + 8) * 9 * 2) * ((2 + 9) + 8 * 9 + 2) + 3 * (3 + 4 * 7 * (3 + 2 * 8 * 6 + 7) * (5 + 3)) * 5
(9 * (9 * 9 + 7 * 4) + (7 * 4 * 7 * 5) * (9 * 2 + 8 + 5 * 6)) * (6 * (7 + 9 + 6 * 7 + 9) + 4 * 4 * 2 + 6) * 9
4 + (3 + (4 + 5)) + 7 * (6 + 4 * (5 + 3 + 9 + 5 + 2) * 4 + 4) + 8 + 8
((5 + 8) + 5) * 9 + 6 + 8 * 7
8 * (5 + (3 * 3 + 6 * 3)) * 5 + 2 + 8 * 8
6 * 2 * 9 * (8 * 7 * (2 * 4 + 6 + 7 + 4 * 5)) + 9 + 7
(5 * 3 * (8 * 2 * 8 + 2 + 8) * (8 + 8 + 9 * 7 * 6 * 3) + (4 * 2 * 7) * 4) + (4 * 3 + 9 * 5) + 5 + (5 + 9)
(6 + 3) * 5 + (6 + 7 + 5 + 7)
(9 * (6 + 6 * 8 + 4) * (3 * 6 + 6 + 7 + 7 + 5) + (5 * 7 + 4) * 9) * (7 + 3 + 7 * 2 + (5 + 7 * 6 + 8) * 4) * 7
6 + 8 * (5 * 5 + (3 * 2 * 2 * 7 + 4 * 9) * 7 + 4) + 8 + 4
9 + (5 * 7) * (5 * 6 * 8 * (5 * 2) + 9) * (6 + 3 + 6 + 9 + 2) * 6
8 * (8 + 8 + 9 + 9 * 6 * 3) + 8 * (3 * 3) + 3 * 3
7 * 7 * (5 + 5 * 9) + (6 * 6 * 3 * 4 * 8 + 8) + 3
(3 * 2) + 5 * (6 * (9 + 2 + 3 + 2 * 9 + 5) + 6) + 2 + 7 * 9
9 * 2 + 3 + (3 * 7) + 4
7 * 5 * 7 * (4 + 3 * 7 + 3 + (4 * 5 + 5) + (5 * 8)) * (8 * 3 * (8 + 9))
((3 * 8 * 8 + 6 + 5 * 5) + 3 + (3 * 8 * 7)) * 2 * (9 + (9 * 8) * 5) * 5 * 4 + 7
4 * 9 * (4 + (3 * 7) + (6 * 4 * 9)) + 2 + 8
5 * ((7 + 2 + 6 + 6) * 2 + 4 * 8)
5 + 9 * ((7 + 2) * 5 * 4 * (5 + 7) + (8 + 4 * 8 * 7 * 9))
((4 + 3) + 6 * 3) * (4 * (4 * 6) * 3 * 2 + 8 * 4) + 8
5 + (6 + 3 + 6 * 8 * 7 * 2) + 3 * 9 + (8 + 2 + 6 * (4 + 6 * 6 * 8 * 3 * 3)) + 7
7 + (8 + 8 * (8 + 3 * 3 * 5 + 2)) + 4 + (2 + 3 * 7 * 7 + 6 + 2) * 9
7 * 3 * 2 + 6 + 7 * 4
(3 + 4 * 7 + (8 * 3 * 5 * 8 + 5 * 3) * (7 + 4 * 8 + 9)) + 8 + (4 * 3 * 4) * (6 + 4 + 8) + 5 + (9 + 6 + 2 + 4)
((3 + 9 + 5) * 7 * 2 * (3 + 7)) + 5 + 3
(4 * 9 + 3 + 9) * 8 * 8 + ((7 * 2 + 6 * 2 * 2) + 8 * 3 * 2 + 2 + 6) * 3 + 7
(5 * 6 * (8 + 8) + 2) + 6 + 2 * (5 + 4) + 2
(3 * 8 + 2 + 5 + 6 + 6) + (8 + 7 + 9 * 4 * 4 + (4 * 4 + 4 * 7 + 7)) * 4
(7 * 7 * 4) * 7 * 3 + 6
(9 * 3 + 7) * 7 + 4 + 2 * 7 * 3
6 * 9 + (6 * 6 + 6 * (3 * 9 + 7))
5 + 6 * 7 + 8 + (3 * 3 + 5 + 3 + 6) + 8
(6 + 4 + 6 * 9) + (3 * (6 * 3 * 2 + 2 + 9)) + (2 + 9 + 8 * 3 * 8 + 9) + 4 + (4 + 4 + 7)
4 + 3 * ((6 * 3 * 2) + 3 * 3 + (6 * 4 + 5 * 5 * 7) * 6 + 3)
2 + (7 * 5 * 6 + 8 + 4 * 8) * 3 * 6 * 3
9 * (8 * (6 * 7 + 7) * 3 + 9) + 7 * 5 + 6
((3 * 5) + 2 * 4 * 2) * 7 + (4 + (4 * 2 * 6) + 2) + (3 + 5 * 8 + 6) + (5 + 2 * 6) * 2
8 + 9 * (4 + 6 + 9 + 2 + 4 + 6) * (9 + 4 * 5) * 2
(6 + 9 + 4 + 7 * 7 + (6 + 5 + 4 * 6 + 4 * 5)) * 3 + 7 + (2 + 9 + 7 + 8 + 4 * 5)
(6 * 7 * (7 * 7 + 3 * 9 + 4 * 2) + 8 * 7) * 3 * 2
(7 * (5 * 2 + 2 + 8 * 4 + 6)) + 7 + 7 * 8 * 7 + 2
(8 * 6 * (4 + 6 * 8 * 8)) * 8 + 4
(4 + 7) * (7 * 4 + 4 + 5 + (9 * 9 * 4 * 5) + 8) + 4 + (8 * 9 + 2 + 4 * (2 * 2 + 8) * (5 * 7 * 4 * 6 + 2)) + 6
4 * (8 * (2 * 5) + 4 * (7 * 2 + 7 + 8) * 7) * 4 * 9 * 7 + ((5 * 4 * 5 + 7 + 9) + 7 * 7 + (6 * 3 + 8 + 7 * 4) + (6 + 4 * 3))
((3 + 4 + 7 * 8 * 5) * 9 * 6) + 6 + 3
((7 + 3 * 8) * (3 * 7 + 4 * 3) + 5 + 2 * 9) * 8 + 4 + 2
((3 + 8 * 8 + 9) * 5 * (5 * 6 + 5 + 7)) + 2 * (6 * 5 + 4 * 6 * 4 * 8) * 9 * 7
4 + 9 * 8 * ((8 * 6) + 7 * 2 + 2 * 6)
(2 * 3 * 3) + 4 * 8 * (3 * 5)
(8 * (5 + 9) + (5 * 6 * 7 * 2) + 4 + 4 + (6 * 9 + 8 + 7 + 2)) * 7 * 2 * 6 + 2 * 2
(8 * 9 * 7 + 3 * 6) + 5 + 4 * ((9 + 8) + (3 + 7 + 6 * 2) + (7 * 5 * 9 + 5) * 8 * 3) + (6 + 9 * (6 * 8) + 2 + 4 * 4)
6 + 8 * 9 + (4 * (9 + 2 + 3 + 5 + 3 + 8) + (3 + 7 * 4) + 4 * 7 * (6 + 2))
2 + 4 * 7 * 5 + (8 * 3) + 6
9 + 9 + 4 + (4 * 3 + 3 * 2 + (7 + 2 + 9 + 8) + 4)
3 * 7 * 7 * 9 + 7
(3 * 2 * 3 * 5 + 6) + 4 * 5 + 8 + 5
7 * 6 + 7 * 8 + 8 * 3
(6 + 2 + (6 * 8 * 5) * 6 + 3 * (8 * 5 * 9 * 2 * 7 + 4)) * 3
(8 + (4 + 2 * 3 + 7 * 5) * 9) * 3 + 9 + 4 + 6
(9 + 6 + (6 + 3 * 2 + 8 * 5 + 7) + (8 + 8 * 3 + 9 * 4 * 8) + 6 * 2) * (7 + 9 + 5 + 8) * 7 + 4 * ((6 * 5 * 7 + 7 * 9 * 3) + (2 * 4 + 4 * 2))
(5 * (3 + 5 + 5 * 6) * 7) + 8 + 3 * 4 + 7
3 * 7 * (9 * 5 + 9 + 7) + 9 * (3 * 4 * 4 * (8 * 4 + 2 + 5)) + (9 * (5 * 3 * 4 * 9) + 5 * 8 + 9 * 5)
6 + 7 + ((2 * 4 * 5 + 7) * 2 * (8 + 8 * 4 * 3) * 3) * 5 * 6 * 4
7 * (9 * 6 * 4) + 7 + (8 * 2 * 7 * 4 + 8)
4 + 7 * (8 * 4 * 2 * (2 + 5 + 9 + 5 * 2 + 5) * (5 * 6 + 2 * 5 + 9) + 3) * 9 * (3 * 6 + 3 * (4 * 4 * 6 + 6 * 2 * 9)) + 8
2 + 6 * (8 + 9 + 6 + 2 * (9 + 4 * 7 * 5 + 5)) * (7 * 7 * 2 * 9)
4 * 3 + (8 * (6 * 8 + 8 + 6) + 3) + 5
(5 + 6) + (2 + 6 + 4 + 8)
(9 * 5 * 3 + 6 * 6) + (5 * 4)
3 * 2 + (7 + 7 * 2 + (6 + 6 + 2 * 8 * 4) * 3) * 8
(4 * 6 + 6) + 4 * 9
6 + (9 * 3 * 3 * 3) + 8
(5 + (9 + 6 + 3 + 7 * 3 + 5)) + 5 + (4 * 3 + 4) * 9 * 3
(6 + 8 * (8 + 3 * 2 + 4 + 5 + 9)) * 7
6 + 3 * 3 * 5 + ((7 + 4 * 8) + 2 * 7 + 4 * (5 + 8) * 8) + ((5 * 4 * 2) * 4 * 5 + (3 + 4 + 4 * 7 + 7))
2 * 3 * 3 * 4 * 7 + 2
6 * (7 + 9 * 9 + (9 * 6) + 5) + 4
8 * (2 * 7 + 5 * 5 + 8) + 5
(4 * 5) + (3 + 3 * (5 * 9 + 8 * 2) + 6 * 4 + 4) * 5 + 6
4 * 9 + (3 + 3 * 2 + (2 + 4 * 4 * 7 * 7 + 5) * 9) * 5 * 3
(5 * 3 * 6 + 8 + 2 + 4) * 6 * 8 * ((6 * 2 + 2 * 4 + 6 * 2) * 6)
4 * (5 * 4 * 6 + (7 + 3 * 9 + 3)) + (3 * 4 + 4 + (5 + 7 * 6 * 2 + 7) + 3)
3 * (5 + 2 * 6 + 8 + 5) + ((8 + 3 * 6 + 8 * 3) * (7 * 7)) + 8 * 4 * 5
4 + (8 + 6 * (4 + 3)) * 4 + 4
4 * 3 * (3 + (8 * 9) * (9 * 7 * 4 * 9 * 4 * 8) * (5 + 2 + 2 + 2))
8 + (2 + 2 * 5 * 3 * (4 * 3 + 7 + 6 + 3)) + 7 * 2 * 5 * 5
4 * (7 * 9 * (2 * 2 * 5) + 2 + 8 * (6 + 2)) * 4 * 7 * 8
(2 * 3 * 3 * 2 + (9 * 8 + 5 + 4)) + 7 * 2 * 6
((6 * 7 + 3 + 3 * 4) * (5 + 9 + 5) + 7 * 6) + 9
6 * 9 + 8 + 3 + 6 * (6 * 9 + 9 + 3 * 2 * 2)
(3 * 5 + 2 + 9) * (6 + 9 + (6 * 8 + 2 + 8 * 3 + 8) + (2 + 6 + 6 + 6 * 3)) * ((7 * 5 * 9) * 3 + 9 + 3 + 8 * 2) * 8 * 6 + 8
3 * (4 + 4 + 6 * (5 + 7) * 8) * (3 * (6 * 7 + 3 + 7 + 7) + 7)
6 * 8 + 8 * (6 + 9 + 5) * 7 + 7
3 * (8 + 5 + 8 * 7 * 7 * 8) + 7 + 9 * 4 + 9
(4 + 5 + 7 + 6) * (9 * (6 * 3 + 9 + 3 + 3) + 6 * 8 + (2 * 8 * 4 + 7 + 5 * 4))
7 * 2 + 3 * (5 + 9) + 7 * 3
7 * 8 + 5 + 7 * 4 * ((7 * 4 + 8 * 8) * (6 + 5 * 8 + 7 + 5 * 3))
(7 * 4 + 3) + (7 + 9 * 7 * 9 * (3 + 2 * 2 * 8 * 2 * 6)) + 5 * 3 + 3 + 3
5 + 6 * (3 + 6) * (6 + (7 + 2) * 3 + (8 * 6 + 3 + 8 + 5 * 9)) * 7
(9 + 6 + 8) + 3 + 5 + 2 + (3 * 9 + (8 + 3) + 7 * 3)
6 + (9 + 7 * 2 * (8 * 9 * 2 + 7 + 6 * 7) * 6)
2 + 4 * ((7 * 2 + 4) * 8) + 9 * 3 * 3
3 + ((5 + 4) * 4 * 7 * (3 + 5 * 4 + 3) + 3)
(7 + 4 * 3 * 6 * 7 * 5) * 2 * 7 + 4
(7 * (7 * 9) + 8 + 2 * (6 + 9 + 9 * 2 * 5) + 7) * 7 * 7 + 9
(2 * 5 + 9 * 5) * 3
3 * 9 + 5 + 7 * 9 + 6
9 * 3 * ((3 * 6 + 4 + 8) + 9 + 2) * 3
8 * 3 + 6 * 8 * 2 + 4

672
day18/src/main.zig Normal file
View File

@ -0,0 +1,672 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var sum : i64 = 0;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
defer gpa.free(contents);
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
var tree = try Tree.init(gpa);
defer tree.deinit();
try tree.parse_line(line);
sum += tree.resolve();
}
std.log.info("Sum of all operations from input: {}", .{sum});
sum = 0;
it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
var tree = try Tree.init(gpa);
defer tree.deinit();
try tree.parse_line_part2(line);
sum += tree.resolve();
}
std.log.info("Part2: Sum of all operations from input: {}", .{sum});
}
const Operation = enum {
addition,
multiplication,
unknown,
};
const TreeValueTag = enum {
value,
operation,
};
const TreeValue = union(TreeValueTag) {
value: i64,
operation: Operation,
};
/// Binary tree node
const TreeElement = struct {
parent: ?*TreeElement = null,
children: [2]?*TreeElement = [_]?*TreeElement {null, null},
value: TreeValue,
pub fn add_child(self: *TreeElement, c: *TreeElement) void {
//std.log.warn("Adding child {*} to {*}", .{c, self});
for (self.children) |ch, k| {
//std.log.warn("{}: {*} ({})", .{k, ch, ch == null});
if (ch == null) {
//std.log.warn("Set child {} of {*} to {*}", .{k, self, c});
self.children[k] = c;
return;
}
}
// We're not meant to call add_child 3+ times on a TreeElement
unreachable;
}
pub fn get_root_node(self: *TreeElement) *TreeElement {
var r = self;
while(r.parent) |p| {
r = p;
}
return r;
}
pub fn print(self: *TreeElement, depth: u64) anyerror!void {
var _type = switch(@as(TreeValueTag, self.*.value)) {
.value => "value",
.operation => "operation"
};
var i : u64 = 0;
var stdout = std.io.getStdOut().writer();
while (i < depth) : (i += 1) {
try stdout.print(" ", .{});
}
try stdout.print("{*} ({}) - {}\n", .{self, _type, self.value});
for (self.children) |c, k| {
//std.log.warn("Child {} of {*} is {*}", .{k, self, c});
if (c != null) {
try TreeElement.print(self.children[k].?, depth + 2);
//try self.children[k].?.print(depth + 2);
}
}
}
pub fn resolve(self: *TreeElement) i64 {
if (@as(TreeValueTag, self.value) == TreeValueTag.value) {
return self.value.value;
}
else {
std.debug.assert(self.value.operation != .unknown);
var v : i64 = undefined;
var l = self.children[0].?.resolve();
var r = self.children[1].?.resolve();
if (self.value.operation == .addition) {
v = l + r;
std.log.warn("{} + {} = {}", .{l, r, v});
}
else {
v = l * r;
std.log.warn("{} * {} = {}", .{l, r, v});
}
return v;
}
}
pub fn swap_child(self: *TreeElement, old: *TreeElement, new: *TreeElement) void {
for (self.children) |v, k| {
if (v == old) {
self.children[k] = new;
return;
}
}
// maybe we don't want to fail at swapping a child right now
unreachable;
}
pub fn nearest_operation(self: *TreeElement) ?*TreeElement {
var t : ?*TreeElement = self;
var r : ?*TreeElement = null;
while (t) |node| {
if (@as(TreeValueTag, node.value) == TreeValueTag.operation) {
r = node;
break;
}
else {
t = node.parent;
}
}
return r;
}
pub fn nearest_unknown_parent(self: *TreeElement) ?*TreeElement {
var t : *TreeElement = self;
var r : ?*TreeElement = null;
while(t.parent) |p| {
if (@as(TreeValueTag, p.*.value) == TreeValueTag.value) {
t = p;
continue;
}
else {
r = p;
break;
}
}
return r;
}
};
const Tree = struct {
allocator: *std.mem.Allocator,
// we want constant pointers for the TreeElements, but
// maybe we can use this object to simplify keeping track
// of them
children: std.ArrayList(*TreeElement),
pub fn init(a: *std.mem.Allocator) !*Tree {
var self = try a.create(Tree);
errdefer a.destroy(self);
self.* = Tree {
.allocator = a,
.children = std.ArrayList(*TreeElement).init(a),
};
return self;
}
pub fn deinit(self: *Tree) void {
for (self.children.items) |c| {
self.allocator.destroy(c);
}
self.children.deinit();
self.allocator.destroy(self);
}
pub fn resolve(self: *Tree) i64 {
std.debug.assert(self.children.items.len > 0);
var root = self.children.items[0].get_root_node();
return root.resolve();
}
pub fn create_number_node(self: *Tree, buf: []const u8, previous: ?*TreeElement) !*TreeElement {
var t = try self.create_node();
var last : *TreeElement = undefined;
t.* = .{
.value = TreeValue { .value = try std.fmt.parseInt(i64, buf, 10) },
};
if (previous) |l| {
l.add_child(t);
t.parent = l;
last = l;
}
else {
last = t;
}
return last;
}
pub fn parse_line(self: *Tree, line: []const u8) !void {
var last_node : ?*TreeElement = null;
var disjointed_nodes = std.ArrayList(*TreeElement).init(self.allocator);
defer disjointed_nodes.deinit();
var buf = std.mem.zeroes([16]u8);
var buf_pos : usize = 0;
for (line) |c, k| {
if (c == ' ') {
// Check buffer length, if not zero add the necessary tree node
if (buf_pos == 0) {
continue;
}
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Reset buffer
std.mem.set(u8, buf[0..], 0);
buf_pos = 0;
continue;
}
if (std.ascii.isDigit(c)) {
buf[buf_pos] = c;
buf_pos += 1;
// If we're at the end of the string, we need to run the stuff
// for adding a number node
if (k == line.len-1) {
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Buffer reset unneccesary here
}
continue;
}
switch (c) {
'+' => {
std.debug.assert(last_node != null);
// If we have a last node, we should check up for
// an unknown parent. If an unknown parent exists,
// we should set the operation on that node, and
// set that node to the last_node.
// If we ourselves are unknown
if (@as(TreeValueTag, last_node.?.value) == .operation) {
if (last_node.?.value.operation == .unknown) {
last_node.?.value = TreeValue { .operation = .addition };
continue;
}
}
else if (last_node.?.nearest_unknown_parent()) |unknown_parent| {
unknown_parent.value = TreeValue { .operation = .addition };
last_node = unknown_parent;
continue;
}
// If there is no unknown parent, our last node could
// be an operation node or value node.
// When it's an operation node, this is probably an error?
var root = last_node.?.get_root_node();
var t = try self.create_node();
t.* = .{
.value = TreeValue{ .operation = .addition},
};
root.parent = t;
t.add_child(root);
last_node = t;
continue;
},
'*' => {
std.debug.assert(last_node != null);
// Same as '+'
if (@as(TreeValueTag, last_node.?.value) == .operation) {
if (last_node.?.value.operation == .unknown) {
last_node.?.value = TreeValue { .operation = .multiplication };
continue;
}
}
else if (last_node.?.nearest_unknown_parent()) |unknown_parent| {
unknown_parent.value = TreeValue { .operation = .multiplication };
last_node = unknown_parent;
continue;
}
var root = last_node.?.get_root_node();
var t = try self.create_node();
t.* = .{
.value = TreeValue{ .operation = .multiplication},
};
root.parent = t;
t.add_child(root);
last_node = t;
continue;
},
'(' => {
// We need to start a new disjointed tree.
// Create an operation node of an unknown type,
// and set that as the parent of the current last node, if
// there is one.
if (last_node) |l| {
try disjointed_nodes.append(l);
}
else {
var t = try self.create_node();
t.* = .{
.value = TreeValue { .operation = .unknown },
};
if (last_node) |l| {
l.parent = t;
t.add_child(l);
}
try disjointed_nodes.append(t);
}
last_node = null;
},
')' => {
std.debug.assert(last_node != null);
// Close out any number that's in progress
if (buf_pos != 0) {
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Reset buffer
std.mem.set(u8, buf[0..], 0);
buf_pos = 0;
}
var dj = disjointed_nodes.pop();
if (last_node) |l| {
l.parent = dj;
dj.add_child(l);
last_node = dj;
}
},
else => unreachable,
}
}
}
// Addition hash priority over multiplication
pub fn parse_line_part2(self: *Tree, line: []const u8) !void {
var last_node : ?*TreeElement = null;
var disjointed_nodes = std.ArrayList(*TreeElement).init(self.allocator);
defer disjointed_nodes.deinit();
var buf = std.mem.zeroes([16]u8);
var buf_pos : usize = 0;
for (line) |c, k| {
if (c == ' ') {
// Check buffer length, if not zero add the necessary tree node
if (buf_pos == 0) {
continue;
}
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Reset buffer
std.mem.set(u8, buf[0..], 0);
buf_pos = 0;
continue;
}
if (std.ascii.isDigit(c)) {
buf[buf_pos] = c;
buf_pos += 1;
// If we're at the end of the string, we need to run the stuff
// for adding a number node
if (k == line.len-1) {
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Buffer reset unneccesary here
}
continue;
}
switch (c) {
'+' => {
std.debug.assert(last_node != null);
// If we have a last node, we should check up for
// an unknown parent. If an unknown parent exists,
// we should set the operation on that node, and
// set that node to the last_node.
// If we ourselves are unknown
if (@as(TreeValueTag, last_node.?.value) == .operation) {
if (last_node.?.value.operation == .unknown) {
last_node.?.value = TreeValue { .operation = .addition };
continue;
}
}
else if (last_node.?.nearest_unknown_parent()) |unknown_parent| {
unknown_parent.value = TreeValue { .operation = .addition };
last_node = unknown_parent;
continue;
}
// If there is no unknown parent, our last node could
// be an operation node or value node.
// If last_node has a parent which is an multiplication node,
// we want to insert ourselves between, otherwise we go to the top
// like in part one.
// If the last-node is itself a multiplication node, then we
// want to do the swap as well.
var t = try self.create_node();
var nearest_op = last_node.?.nearest_operation();
if (nearest_op) |p| {
var new_child : *TreeElement = undefined;
if (p.children[1] != null) {
new_child = p.children[1].?;
}
else if (p.children[0] != null) {
new_child = p.children[0].?;
}
else {
// maybe?
unreachable;
}
p.swap_child(new_child, t);
new_child.parent = t;
t.add_child(new_child);
t.parent = p;
last_node = t;
}
else {
if (@as(TreeValueTag, last_node.?.value) == TreeValueTag.operation and
last_node.?.value.operation == .multiplication) {
std.debug.assert(last_node.?.children[1] != null);
var mult_child = last_node.?.children[1].?;
last_node.?.swap_child(mult_child, t);
mult_child.parent = t;
t.add_child(mult_child);
t.parent = last_node.?;
last_node = t;
}
else {
var root = last_node.?.get_root_node();
root.parent = t;
t.add_child(root);
last_node = t;
}
}
t.value = TreeValue{ .operation = .addition};
continue;
},
'*' => {
std.debug.assert(last_node != null);
// Same as '+'
if (@as(TreeValueTag, last_node.?.value) == .operation) {
if (last_node.?.value.operation == .unknown) {
last_node.?.value = TreeValue { .operation = .multiplication };
continue;
}
}
else if (last_node.?.nearest_unknown_parent()) |unknown_parent| {
unknown_parent.value = TreeValue { .operation = .multiplication };
last_node = unknown_parent;
continue;
}
var root = last_node.?.get_root_node();
var t = try self.create_node();
t.* = .{
.value = TreeValue{ .operation = .multiplication},
};
root.parent = t;
t.add_child(root);
last_node = t;
continue;
},
'(' => {
// We need to start a new disjointed tree.
// Create an operation node of an unknown type,
// and set that as the parent of the current last node, if
// there is one.
if (last_node) |l| {
try disjointed_nodes.append(l);
}
else {
// This assumption that the new disjointed node will
// be the new root is not always true since there is
// operator precedence now?
// We also sometimes loose nodes because of the swapping?
var t = try self.create_node();
t.value = TreeValue { .operation = .unknown };
if (last_node) |l| {
l.parent = t;
t.add_child(l);
}
try disjointed_nodes.append(t);
}
last_node = null;
},
')' => {
std.debug.assert(last_node != null);
// Close out any number that's in progress
if (buf_pos != 0) {
last_node = try self.create_number_node(buf[0..buf_pos], last_node);
// Reset buffer
std.mem.set(u8, buf[0..], 0);
buf_pos = 0;
}
var dj = disjointed_nodes.pop();
if (last_node) |l| {
var root = l.get_root_node();
root.parent = dj;
dj.add_child(root);
last_node = dj.get_root_node();
}
},
else => unreachable,
}
}
}
fn create_node(self: *Tree) !*TreeElement {
var t = try self.allocator.create(TreeElement);
// Having some non-zero initialization problems, but
// can't use std.mem.zeroes since TreeValue doesn't
// have a "zero" value.
t.children = [_]?*TreeElement {null, null};
t.parent = null;
try self.children.append(t);
return t;
}
fn print_tree(self: *Tree) !void {
var stdout = std.io.getStdOut().writer();
if (self.children.items.len == 0) {
try stdout.print("Tree {} has no children", .{self});
return;
}
var root = self.children.items[0].get_root_node();
try root.print(0);
}
};
test "no_parentheses" {
var line = "1 + 2 * 3 + 4 * 5 + 6";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 71), v);
}
test "ex2" {
var line = "1 + (2 * 3) + (4 * (5 + 6))";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 51), v);
}
test "ex3" {
var line = "2 * 3 + (4 * 5)";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 26), v);
}
test "ex4" {
var line = "5 + (8 * 3 + 9 + 3 * 4 * 3)";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 437), v);
}
test "ex5" {
var line = "5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 12240), v);
}
test "double_open_brackets" {
var line = "((2 * 3) + 4) * 2";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 20), v);
}
test "ex6" {
var line = "((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2";
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line(line);
std.debug.warn("\n", .{});
try tree.print_tree();
var v = tree.resolve();
std.testing.expectEqual(@as(i64, 13632), v);
}
fn test_part2(line: []const u8) !i64 {
var tree = try Tree.init(std.testing.allocator);
defer tree.deinit();
try tree.parse_line_part2(line);
std.debug.warn("\n", .{});
try tree.print_tree();
return tree.resolve();
}
test "part2_no_parentheses" {
var line = "1 + 2 * 3 + 4 * 5 + 6";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 231), v);
}
test "part2_ex2" {
var line = "1 + (2 * 3) + (4 * (5 + 6))";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 51), v);
}
test "part2_ex3" {
var line = "2 * 3 + (4 * 5)";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 46), v);
}
test "part2_ex4" {
var line = "5 + (8 * 3 + 9 + 3 * 4 * 3)";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 1445), v);
}
test "part2_ex5_sub" {
var line = "5 * (2 * 3 + (4 * 5))";
var v= try test_part2(line);
std.testing.expectEqual(@as(i64, 230), v);
}
test "part2_ex5" {
var line = "5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 669060), v);
}
test "part2_ex6_sub" {
}
test "part2_ex6" {
var line = "((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2";
var v = try test_part2(line);
std.testing.expectEqual(@as(i64, 23340), v);
}

1000
day2/input Normal file

File diff suppressed because it is too large Load Diff

129
day2/main.zig Normal file
View File

@ -0,0 +1,129 @@
const std = @import("std");
pub const Policy = struct {
min: u32 = 0,
max: u32 = 0,
value: u8,
password: []u8,
pub fn matches_policy_one(self: *Policy, s: []u8) bool {
var c : u32 = 0;
for(s) | v | {
if (@as(u8, v) == self.value) {
c += 1;
}
}
var valid = (c >= self.min and c <= self.max);
//std.log.debug("{} is {} for Policy {}-{} of {c} [{} found]",
// .{s, valid, self.min, self.max, self.value, c});
return valid;
}
pub fn matches_policy_two(self: *Policy, s: []u8) bool {
var n_matches : u32 = 0;
if (s[self.min-1] == self.value) {
n_matches += 1;
}
if (s[self.max-1] == self.value) {
n_matches += 1;
}
return n_matches == 1;
}
};
pub fn main() !void {
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
var f = std.fs.File { .handle = try std.os.open("input", std.os.O_RDONLY, 0) };
var buffer : [1024]u8 = undefined;
var byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
defer byte_buffer.deinit();
const stdout = std.io.getStdOut().writer();
var n_valid : u32 = 0;
var read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
while (read != 0) {
for (buffer) | v, k | {
// We're through the read part of the buffer
if (k >= read) {
break;
}
if (v == '\n') {
var p = parse_policy(byte_buffer.items[0..]);
if (p.matches_policy_two(p.password)) {
n_valid += 1;
}
try stdout.print("{}-{} {c}: {}\n", .{p.min, p.max, p.value, p.password});
//std.log.debug("{}", .{x});
// Set the position back to zero, without freeing existing memory
byte_buffer.deinit();
byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
continue;
}
try byte_buffer.append(v);
}
read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
}
std.log.info("{} valid items", .{n_valid});
//part1(expenses.items[0..]);
//part2(expenses.items[0..]);
}
fn parse_policy(line: []u8) Policy {
var min : u32 = 0;
var max : u32 = 0;
var char : u8 = 0;
var pass : []u8 = undefined;
var start : usize = 0;
var got_min = false;
var got_max = false;
for (line) | v, k | {
if (v == '-') {
min = atoi(line[start..k]);
start = k + 1;
got_min = true;
}
if (v == ' ' and !got_max) {
max = atoi(line[start..k]);
start = k + 1;
got_max = true;
}
if (v == ':') {
char = line[start..k][0];
start = k + 2;
}
if (k == line.len-1) {
pass = line[start..];
}
}
return Policy {
.min = min,
.max = max,
.value = char,
.password = pass,
};
}
fn part2() void {
}
fn part1() void {
}
fn atoi(a: []u8) u32 {
var i : u32 = 0;
for(a) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, (v - 48) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i;
}

323
day3/input Normal file
View File

@ -0,0 +1,323 @@
..#...##...###.........#..#..#.
#.###........#..##.#......#...#
#.#.###..#.#..#.#............#.
.##............#......#...#.#..
..#..#.....##..##..##..........
...#...........###.#.##........
....#.#...#..#..##............#
....#....##...##..##........#..
.#..#..#....#...#..##.....##...
.#.###..#......####........##..
..#...###....#......#.....##.##
..#...#.......#......#..##....#
#...##....#.#..#.......#....#..
.#......#..#...........#....##.
.##.#......#.#.#.....##........
.....#.................#.#..#.#
....#..#........##......#..#.#.
..#...#..##.......#..##...#..#.
..#.......#.............#.#....
.#.................#.........#.
..#..#.#.#.#............##.#..#
.#.#.##.#.....#.....#..#......#
..#.#..#.#..........##........#
.........#...#.....#.#...#####.
##..#.....##.##........#...##..
.#.....#....##.#..#....##...##.
.##.....#.#....#.#.....#......#
.....#..#.##.....#.#....#.#..##
#......##..##....##...###..#...
.......#..#...........#......#.
#...#......#........#..#.......
##..#.....##.....#...#...#....#
.###..##..#.#........#..#.#....
#.#...#...#......##........#.#.
......#....#.#........##...#..#
.#.....#..#.#.....#......##....
.....#.....#.#.#....###.....#..
#.......##.#......#.#.#....###.
.......#..#..#...#.#.##........
.#......##..#.........###..#...
....#..##.......##.###...###...
.##............#..#.##.....#.##
..##.#.......##....#.......##.#
#..###............#.#...#...#.#
...##.#.#.#..#.##........#.#...
.#.....#...##.#..###..##.##...#
..............#.#.#.........#..
.....#...........#.#...#....#..
.....#...##.##.#....#.###..#...
#..###.........#......#.#.#....
.....#..#...##...###.#....#....
#..........#.#.#....#..#......#
###...................#......#.
........####......#.#..........
.......#.....#...#.......#...#.
.....#.....................#...
...#.#...#...#...........#.....
..#.........#...#....###..#....
.....#.#..##......##........##.
..#.............#............#.
.#....##.......#..#............
.#............#.#..#.##....#...
.####...##.#....#.....#...#....
##..#....#.#.#...........#..#.#
...#..#...........#...#..#....#
.....##.....#..#...#.........#.
...##........#....##........#..
.##.#...#...#..#.....#....##.#.
#.#...#.#.#.#.#..#....#....#...
#..#.#...#..#........#....#.#..
....#.#.....#......##...#....#.
.###.##...#....##.#...###..#..#
###..#...##..#......#.........#
..#.#......##.......#.....#...#
..#...#........#.........#.#...
#....#..#.........###.#......##
...#..#....#...#.......##.#.#..
....#.......#....###...##.#....
..#.....#.#.....###..#####....#
##......#....#.....##..#..#...#
#...........#..#..#....#....#..
.#...#.##.#.#.#....#......#..#.
.......#.#....#....#...#.#..#..
..#.#..#.##..##...##..#..#.....
...##.##.................#.#...
.....#...#......##.#....#.....#
......#..##.#..#.#.........#...
.............##.#......#.......
..#.#.....#...#.#.....#..#.....
.........#..#.#......#..#......
#..#.#.##..........#.##......##
......#.......#.....#..#.#...#.
.#....#....#.#.....#.......#...
#..#..##..................#....
............#...........##.#...
####...#..##.#....#.##..#......
#...#...#.....#.#...#.#........
.......##.........#.....#.....#
.....#...........##......#.####
.##....#.#.##......###.#.##....
........#.####.......#.#...#...
.#.#...##.#.#.#.........##.....
....#............###.##....#...
...##........##.#...#....#..###
..#.#.........#....##.#........
..#..##..#...##..#.##...#.....#
.#......#..#..#.........#......
..#........##.#......#.....#...
.##.......#....#.#......#......
#........#....#.####...#.#.....
##......#.............#....###.
..#....####.#.#.#.#...##......#
#.#.#.....#...#.......#...##...
........#...#....#..#......#.#.
#..#...#.#.##.....#.#....#....#
#...#....#......#.........##.##
..##.#..##............#........
#.........####.........#.......
#.##.........#..##....#.#.#.#..
.###......##..#.#.....#.#...##.
...#.........#.#...##.##....#..
#..#......#....##..#.#...#...##
...#.......#.#.#.....#..##...#.
....................###........
#...........###......#.#...##.#
.................#.#...###....#
...#..###..#.##...#..#....##...
###..#..#.#...#.....#.#.......#
.........#..#.#.....#.........#
.##..#.........#.#.....##......
.....#..........#.#.##....#....
........#.##.....#...##...#....
#.#.#...#......##....#.###.....
.#.##.....##.....#....#.##.#.##
.#...#.....##.#.##....#.....#.#
...#.....#........#............
##...####..#....#..##...#......
#.......#...#.#...#........#..#
......#.....#....#..#..#.#.....
..............##.....#.##....##
.#..##.........###..#..........
......#......#............#..#.
#.....###...###..........#.....
...###...........#....##..#....
.....................#...#.##..
###....#.#....#...#....#.#..##.
..#.............#.#....#..#.#..
.......#..###....#...#...#...#.
.##..#....##..............##...
...#...#..#..#.##.#....##...#..
#..#....##......#....###..####.
.##...#.#....#..#..#....#....#.
.#.##..#..#.........#.#......##
#..#.................#.....#...
..#............#........#...#..
##.##.......#.#....#..#....##.#
..##...#.#.....#......#........
......#.##.........##...#......
......##.#......#.##....##.#..#
.#.#......####.#.#.#.#..#......
..#.#....#...###....#.#...###..
.#.#...#....##..###.#..#.......
..#.....##..#............#..#.#
.#...#....#.....#....#..#.#.#..
..#....#..#......##...##......#
....#.......#.##.#.........#..#
#............#...##.....#..##..
......#..#..........#.#..#.....
...........#.#..#...##.#...#..#
.........###..#......##.###.#..
.....#....#......#...#....##...
..#.......#..#.#.#......#......
.#....#.....#.#.#.##...#....##.
....#.##.##.......#..#.....#...
.#.....#......#.......#..#.....
....###.....##.....##..#.#...#.
#.......#.#....#.#.#....#......
#...#..#.#......#...##.#.......
....##.##....#..#.......#..#.#.
.#.##.#.#..#.....#.#.......##..
..#..#..#..#.###...............
#.#......##....##.#.#.....#.#..
..##...#.........#.#..#.##..#..
.........####...#.....##.#.....
..#...................#.###....
..#.....#..#....#..#...........
.....###.#.........#.#.........
#..#..#........#..#......#..#..
###..##...#.......#........#.#.
.#.#.#.###.#............##.....
#..............#......#....#.##
.#...#..###...###.#..#.#.......
.###....##.#.......#.#.....###.
.##.....#.#....................
#..#.....#.....#...#.....#..##.
#.#....##..#......##..#...##..#
...........#....#..#.##.##....#
......#.......##....#.#....#.#.
###..#.#..........#.......#.#..
..#.#..##....##............##..
..#.....#..#....###............
.#...#...##...#..#..#..#.#....#
...#....#........#.............
#.#......#.#.....##..........#.
....#..#...............#...##..
........#..#....#..#..#..##....
....#......#.#.#...#.......#.##
.#.....#.#.#........###....#...
.#..#.......#...........#...#..
#.#.#####..#......#...#.#.###..
...##...#.#.....#..#...#...#...
..#....#.....#..#....#.#.....#.
....#.......#.....#........###.
..##..........#...###.......#..
#.#.##..#........##...#.#......
....##...#......#..........#.#.
#.......#..#.##.............#..
......#..........#...#....#...#
#.#.....#.##.#.#.............##
#...#.........##.##......#.##..
.........##.....#....#...##..#.
#.#...##.#...#.....##...#..#..#
......##.#.....#.#.....#.##....
....#.............#...#.......#
.#......##...#.#...#.##........
...#..#..#...........#..#..#.#.
.#...#...........#.#.##....#...
..#...#...#.#..#....#..#..#....
..###..##..#..#.........#.#..#.
....#.##.#...#.......#...#.....
.#.#.................#.......#.
.#..#.....#.##...#.#.....#...#.
.#.......#...#....#.......#....
###....##....#..#...#.#..##....
.........#.#.#.#...###.......##
....##.......#......#......##..
......##.###.#..#...#.#.#.#....
.#.###.#.#......#.#.......##...
.#.....##..#.#.....#...#.##....
.#..##.#.....#........###...#.#
.......#.#...........#........#
..........#...##..##.......#.#.
...#..#..#...#....#.#......#.#.
....#...#..#....#....#.#.##....
...#.#...##...#...##..#........
..#........#...##.#...##.#.#.#.
...##.#..#.......###.#.#.#.....
..##......#.#.#.........###.#..
.......#.#...##...#.#.......#.#
.#....##..#..#....#..#...#.....
.#....#.#.......#..#..##.#....#
#.#..##..#.#............#....#.
##..#....#.##.#....#...#..##...
.###.#.#..#...##........###.##.
...........#..#...#..#.#..###..
.#.#.#...#....#...##.##........
.....###.........#......#####..
#.#.#.....#....#..#...#.#.#.#..
..##.....#..#..#.#.#...#....#.#
......#.##..##..#.#.#.......#..
...#.#..###.........#........#.
......#.##..####...#...#..#...#
#.......#.........#....#....###
#......#...#........#.##....###
.#.#..............#...#...###.#
.#....####...#..##.###.....#...
.......#......#..#...#..##.#...
...........#.......#...........
..............#...#.#.#.#...##.
.###.....##.#.....#..........#.
##.##......#....##..#.....###.#
#.......#...##...#....##...#...
##.#.##...#....#....#....#.....
.....####...........#.#......#.
......#...#....#..#......#.....
...#...##..........#.......##.#
.#....#..........#.####........
...##...#..#...##........##..#.
.........##....#...##..#.##.#..
##.#.....#.......#.....#.......
#..#....#.##.#........#........
#.#...#...##........#.#.....###
....#...................#.#.#..
.......#..#.#...#....#.##.#....
....##...###.#.#.##...#...#....
.#....#....#...##.#......#...#.
............##..#.#.#........#.
...#....#.....#......#........#
...#.#.....#.##.....#....#...#.
.....#..##.......#.##.......#.#
........##................#....
....#..###...##.#..#...#......#
.#.#.......#.......#....##.#..#
..#........#............#......
..##.......#..#..#....#....#..#
#...###.......#.##...#.........
.....#...#...#..##..#....#..#..
.##.#..#...##.........###.#....
..#.#..#...#...####.#...#.#.#.#
#....#..###.....#......#.##..##
##......#...##...###......#.##.
...........#.....##...#...#...#
..#..#.#.....#..#.....###...#..
.............#..........###...#
....##............#....###.##.#
..##.#..##.....#.#.........#.#.
....#.#...........####.........
.##.###.##.#.#......#.##.#.#...
.....##.........#..#.......#...
...........#.........#....###..
...#.#..#..........#.....#..#..
.#..###.......##........#.#....
.#...###.....#..#.#..#...#.##..
##...###.#.#....#......#...#..#
....#.......#..#..##..#.#......
#.#......#.##..#......#..#....#
....#..#..#.....#.#......#..#..
..#...###......##.............#
..#....####...##.#...##.#......
.....#.......###...............
.......#...#.#.......#.#.##.###
.#.#...#.....#...##.........#..
..#..........#..#.........##...

134
day3/main.zig Normal file
View File

@ -0,0 +1,134 @@
const std = @import("std");
pub fn main() !void {
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
var gpa = &allocator.allocator;
var f = std.fs.File { .handle = try std.os.open("input", std.os.O_RDONLY, 0) };
var buffer : [1024]u8 = undefined;
var byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
defer byte_buffer.deinit();
var map = std.ArrayList([]u8).init(&allocator.allocator);
defer map.deinit();
const stdout = std.io.getStdOut().writer();
var read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
while (read != 0) {
var last_pos : usize = 0;
for (buffer) | v, k | {
// We're through the read part of the buffer
if (k >= read) {
break;
}
if (v == '\n') {
try map.append(try std.mem.Allocator.dupe(gpa, u8, byte_buffer.items));
last_pos = k + 1;
// Reset buffer
byte_buffer.deinit();
byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
continue;
}
try byte_buffer.append(v);
}
read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
}
std.log.debug("Map has {} items", .{map.items.len});
//for (map.items) | v, k | {
// try stdout.print("{s}\n", .{v});
//}
var results : std.meta.Vector(5, u32) = [_]u32 {
sled(map, 1, 1),
sled(map, 3, 1),
sled(map, 5, 1),
sled(map, 7, 1),
sled(map, 1, 2),
};
std.log.info("Hit {} trees on slope 1,1", .{results[0]});
std.log.info("Hit {} trees on slope 3,1", .{results[1]});
std.log.info("Hit {} trees on slope 5,1", .{results[2]});
std.log.info("Hit {} trees on slope 7,1", .{results[3]});
std.log.info("Hit {} trees on slope 1,2", .{results[4]});
std.log.info("Multiple of each slop hits: {}", .{@reduce(.Mul, results)});
}
fn sled(map: std.ArrayList([]u8), right: usize, down: usize) u32 {
var map_height : usize = map.items.len;
var map_width : usize = map.items[0].len;
var x : usize = 0;
var y : usize = 0;
var n_trees : u32 = 0;
while (y < map_height) {
var char : u8 = map.items[y][x];
std.log.debug("{},{} : {}", .{x, y, char});
if (char == '#') {
n_trees += 1;
}
y += down;
x += right;
x %= map_width; // loop around
}
return n_trees;
}
fn parse_policy(line: []u8) Policy {
var min : u32 = 0;
var max : u32 = 0;
var char : u8 = 0;
var pass : []u8 = undefined;
var start : usize = 0;
var got_min = false;
var got_max = false;
for (line) | v, k | {
if (v == '-') {
min = atoi(line[start..k]);
start = k + 1;
got_min = true;
}
if (v == ' ' and !got_max) {
max = atoi(line[start..k]);
start = k + 1;
got_max = true;
}
if (v == ':') {
char = line[start..k][0];
start = k + 2;
}
if (k == line.len-1) {
pass = line[start..];
}
}
return Policy {
.min = min,
.max = max,
.value = char,
.password = pass,
};
}
fn part2() void {
}
fn part1() void {
}
fn atoi(a: []u8) u32 {
var i : u32 = 0;
for(a) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, (v - 48) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i;
}

27
day4/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day4", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

1138
day4/input Normal file

File diff suppressed because it is too large Load Diff

215
day4/src/main.zig Normal file
View File

@ -0,0 +1,215 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var record_indexes = std.ArrayList(usize).init(gpa);
var f = std.fs.File { .handle = try std.os.open("input", std.os.O_RDONLY, 0)};
var reader = f.reader();
var records = std.ArrayList([]u8).init(gpa);
var record = std.ArrayList(u8).init(gpa);
var n_newlines : u32 = 0;
var just_had_newline = false;
const state = enum {
AddingData,
CheckingNewline,
RecordEnd,
};
var current_state = state.AddingData;
while(true) {
var n = reader.readByte() catch |err| {
// Finalize record
try records.append(try gpa.dupe(u8, record.items[0..record.items.len]));
//std.log.debug("Found record: '{}'", .{record.items});
record.deinit();
record = std.ArrayList(u8).init(gpa);
std.mem.set(u8, record.items, 0);
break;
};
if (n == '\n') {
if (current_state == state.CheckingNewline) {
current_state = state.RecordEnd;
// Finalize record
try records.append(try gpa.dupe(u8, record.items[0..record.items.len]));
//std.log.debug("Found record: '{}'", .{record.items});
record.deinit();
record = std.ArrayList(u8).init(gpa);
std.mem.set(u8, record.items, 0);
current_state = state.AddingData;
continue;
}
else {
current_state = state.CheckingNewline;
// whitespace can always be added
try record.append(' ');
continue;
}
}
else {
if (current_state == state.CheckingNewline) {
current_state = state.AddingData;
}
try record.append(n);
}
}
std.log.debug("Found {} records", .{records.items.len});
//std.log.debug("{}", .{records.items[0]});
//const fields = comptime std.meta.fieldNames(RequiredFields);
const fields = comptime std.meta.fields(RequiredFields);
const valid_passport = RequiredFields {
.byr = true,
.iyr = true,
.eyr = true,
.hgt = true,
.hcl = true,
.ecl = true,
.pid = true,
};
var n_valid : u32 = 0;
for (records.items) | r, k | {
// Everything is separated by whitespace
var passport_info = RequiredFields{};
var iter = std.mem.tokenize(r, " ");
//std.log.debug("{}", .{r});
while (iter.next()) |aspect| {
inline for (fields) |field| {
if (std.mem.startsWith(u8, aspect, field.name)) {
@field(passport_info, field.name) = validate_field(field.name, aspect[4..]);
std.log.debug("Field {} with contents {} is {}",
.{field.name, aspect[4..], @field(passport_info, field.name)});
}
}
}
if (std.meta.eql(passport_info, valid_passport)) {
std.log.debug("'{}' is valid", .{r});
n_valid += 1;
}
else {
std.log.debug("'{}' is invalid", .{r});
}
}
std.log.info("Valid passports: {}", .{n_valid});
}
pub fn validate_field(field: []const u8, data: []const u8) bool {
if (std.mem.eql(u8, field, "byr")) {
if (data.len != 4) {
return false;
}
var i = atoi(data);
//std.log.debug("byr {} --> {}", .{data, i});
return (i >= 1920 and i <= 2002);
}
if (std.mem.eql(u8, field, "iyr")) {
if (data.len != 4) {
return false;
}
var i = atoi(data);
//std.log.debug("iyr {} --> {}", .{data, i});
return (i >= 2010 and i <= 2020);
}
if (std.mem.eql(u8, field, "eyr")) {
if (data.len != 4) {
return false;
}
var i = atoi(data);
//std.log.debug("eyr {} --> {}", .{data, i});
return (i >= 2020 and i <= 2030);
}
if (std.mem.eql(u8, field, "hgt")) {
var unit = data[data.len-2..];
var i = atoi(data[0..data.len-2]);
//std.log.debug("hgt {} --- > {} '{}'", .{data, i, unit});
if (std.mem.eql(u8, unit, "in")) {
return (i >= 59 and i <= 76);
}
else if (std.mem.eql(u8, unit, "cm")) {
return (i >= 150 and i <= 193);
}
else {
return false;
}
}
if (std.mem.eql(u8, field, "hcl")) {
if (data.len != 7) {
return false;
}
if (data[0] != '#') {
return false;
}
for (data[1..]) |d| {
// less than ascii 0
if (d < 48) return false;
// greater than ascii f
if (d > 102) return false;
// after ascii 9 but before ascii a
if (d > 57 and d < 97) return false;
}
return true;
}
if (std.mem.eql(u8, field, "ecl")) {
if (data.len != 3) {
return false;
}
for (valid_eyecolours) | colour | {
if (std.mem.eql(u8, colour, data)) {
return true;
}
}
return false;
}
if (std.mem.eql(u8, field, "pid")) {
if (data.len != 9) {
return false;
}
for (data) |d| {
if (!std.ascii.isDigit(d)) {
return false;
}
}
return true;
}
if (std.mem.eql(u8, field, "cid")) {
return true;
}
std.log.debug("Uknown field {}", .{field});
return false;
}
const valid_eyecolours = [_][]const u8 {
"amb",
"blu",
"brn",
"gry",
"grn",
"hzl",
"oth",
};
fn atoi(a: []const u8) u32 {
var i : u32 = 0;
for(a) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, (v - 48) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i;
}
pub const RequiredFields = packed struct {
byr: bool = false,
iyr: bool = false,
eyr: bool = false,
hgt: bool = false,
hcl: bool = false,
ecl: bool = false,
pid: bool = false,
};

27
day5/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day5", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

814
day5/input Normal file
View File

@ -0,0 +1,814 @@
FBFBBBFRLL
BFFFBFFRRR
BBFBFFFLLR
FBFFFBFLRR
FBFFBFBLLR
BFBBFBBRLL
BFFFFFFRLR
FBBBBFFLLR
FFBBFFFLRL
FFBFBBFLLR
FBFFFBBRRR
FBFFBFBLRR
FBBFBFFRLR
FBBBFBFRLL
FFBFFBBRLR
FBFBBBFRRL
BFFBBBFRRR
FBFBBBBLLR
FFBFFBBLLL
BFFBFBBLLR
BFFBFBBRLR
BFFBBBBLLL
FBBBBFBLLR
FFBFBBBLRR
FFBFBBFLRR
FFFBFBBRRL
FFFFFBBRLL
BFFFBFFLRR
FFFBFBBRLR
FBFFBBFLLR
BFBFFBBRRR
FBBFBBFLRL
BFBBFBFRRR
BFFFBBBLRL
BBFFFBFLLR
BFFFFBFLRR
BFFBFFBLLL
FFBBFBFRRR
BFBFFFBLLL
FBFBFFFRRR
BFBFBBBLLL
BFFFBBFLLL
BFBFFFBLLR
BFFBBBFRRL
FFFBBFFLLR
BFFBBBFLRR
FBFFBBBRLR
FBBFBBFLRR
FBBFFBFRRR
FBBFBBBRRL
FFFBFFBRRL
FBFBFFBRLL
FBFFBBFRLL
BFBFBFFRLL
FBFBFFFRLR
BFBFFBBRRL
FFBBFFBRRR
BFFBFBBLRL
FFBFBFBLLL
BBFFFBFRLL
FBFBBBFRRR
BFFBBFFLRR
BFBBFFBLRL
BFFFFFBLLL
BBFFFFFRLR
FBBFFBFRLL
FFBFBFFRRR
BFBBBBFLRR
BFFBBFFRLL
BFBBFFBLLL
BFFFFFBRRR
FBBFFFBLRL
FFFBBBFRLR
FFBBBFBRRL
BFFFBBBRRL
FFBFBFBRRR
FBBBBBFRRR
BBFBFFFRLL
FBFFFBBLRR
FBFBFFBRRR
BFBFBFBRLR
FBBBFFFRRL
BFBFFFBRLL
FBBBFFBLLL
BFBFBFFRLR
BBFFBFBLRL
BBFFBFBRLR
BBFBFFFRRR
BFBBFFFRLL
BFFBBBBRRL
FFBFFBFRLL
FBBBFBBLRR
FBFFFFFRLR
FBFFFBFLLR
BBFFBFFRRR
BFBFBFBRLL
BFFBBBBLLR
FBBBFBFLLL
FFBBFBBRLR
FFFFBBFRRR
FFFBFFFRRL
FFFFBBBLLL
FBBBBFBLLL
BFBBFBFRLL
FFBFBFFRLR
FBFBBBFLLL
BFBBBFFLLL
BBFFBFFRLL
FBFFFFFLLR
FBBBBFBLRR
BFBFFFFRRR
BFFBBBBLRL
BFFBBFFLLL
FBFFBBFLRR
BBFFFFBLRR
FBBBBFFRLL
FBFBFFBRLR
FFFFBBFRLR
FBBFFBBLLR
BFFFBBFLRL
BFFFFFFLRR
BFBFBFBRRL
FFBBFBFLLR
BFBBFBFLLR
FFBBBFBLRR
BBFFBFBRRL
BFFBBBFLRL
BFFBFFFRRR
FFFFBBFLLL
BBFFFBBRLR
FFBBBBBRLR
FFBFBBBRLR
FFFFBFBLLR
FBBBBBBLLR
FBBBFFBLRL
BFFFFFFLLL
FBBFBBFLLL
BFBBBBBLRR
FBFBBFBLLL
FBFFFBBLLL
FBFFFBBRLR
FFFBBBFRRL
FBFFFFBLLL
BBFFFFFRLL
BFBFBBFLRL
FBBBFFFLLL
BFBBFBBRLR
FFBFBBFRLL
FFBFBFBLRL
BFFBBBBRRR
FFFFBBFLRL
BBFFFFBLLR
FFFBBBFLLR
FFFBFFFLLR
FFBBBFFLRL
FBFBBBFLRL
FBBFBBFLLR
FBFBBFFLLR
BBFFBBBRRL
FBFBBFBLRR
FBBBFFFLLR
FBFBFFFRLL
FFBBFFBLLL
FBBBFBFRRR
BFBFFFBRRR
FBBBFFFRRR
BBFFBBBLLL
BFFBFFBRLR
BFFFBFBLLR
FBBBBBFLRR
FBBFBBBLRL
FFFBFFFLRR
FFFFBBBRRR
BBFFFBFLRL
FBFBBFFRRL
BBFBFFFRLR
FBFBFBBRRL
FFBFFBFLRL
FBFFBFBRLR
BFBFFFFLRL
FBFFFBFRRR
FFFFBFBRRR
BBFFFFBRLR
FBBBFFBRRL
FBBFFBBRLR
FFBBFBFLRL
BFFFBBBLLR
BFFFFFFRLL
BFFBBBBLRR
BFBFBBBRRL
FBFBBBBLLL
BBFFFBBLRR
FFFFBBFLRR
FFBBFBBLRR
FFFBBBBLLL
FFBBBBFLLL
FBBFFFFLLR
FFBFBBBRLL
FFBBFBBRRR
BFBFBBBLLR
FBBBBBFLLL
FFBBFFBRLL
BFBFFBFRLR
FBBFBFBRRL
FFBBFFFLRR
BFBFBFFLRL
FBFFBFFRRR
BBFFBFFRLR
FFBBBBBRRL
FBBBFBBLLR
FFFBBBBLLR
FFBBFBBLLR
BBFBFFBLRL
BFFFFFBLLR
FFFBFFBRLL
FFFFBFBRLR
FFBFFBBRRR
FBBBBFFLRR
BFBFFFFRLR
FFBBFFBLRL
BFBBFBBLLR
BBFBFFFLRR
FBFFFBBLLR
BFFBBBFLLR
BFFBBFFLLR
BFBBBBFRLR
FBFFBBBLLR
FFBFFFFLLR
FBBBBFFRRL
FBFBBFBRRL
FFFFBFBLRR
BBFFFFBRRR
BFBBFBFRRL
BFFBBFFRLR
FBFBFBFLLR
BBFFBFFLRL
BBFFBBBLLR
BFBBBFBLLL
BFBBBBBLLR
FBBBFFBRLL
FBFFBFBRLL
BFBFFBFLLR
BFBFFFFLLL
FBFFFFFRLL
FFBBFFFLLR
FFFBFFFRRR
FBFFFBFRLR
FFFBFBBLLL
BBFFFBBLLL
FFFBBFBLRL
FBBBFBFRRL
FFFBBFBRLR
BFBBBFFLRR
FFBBBFFLRR
FFBFBBBLLR
FBBFBFBLLR
FFBFFBBRRL
FFFBFBFLRR
FBBFBFBRLL
BBFFBBFLRL
FBBFFBFRRL
BFBFBFFRRR
BFBBBFBRRR
BFFFFBFLLR
FBBFBFBRRR
BFFFFBBLLL
FFFBFFFRLR
FBBFBFBRLR
BFFFFBFRLL
FFBFBBFRRR
BBFFBFBRRR
FFBBBFFRLR
BFBFBFFRRL
BFFFBFBLRR
BFBBFBBRRR
FFBFFBFRLR
BFFFBFFRRL
BFBFBBBLRR
FFBBBBBRLL
BFBBFFBRLR
FBFFFFFLRL
FFBBBBBRRR
FFBFFFBLLL
FFBBBBBLLR
BBFFBFBRLL
BFBFBBBLRL
FBBFFFFLRR
BBFFBFBLLR
FFBBBFBLLR
BFBFFFBRLR
FBFBBBFLRR
FBFBBBBRLL
BFFFFBFLRL
BFFFBFBRLR
FBBFFFFLRL
FFFBBBBRLL
FFFBFFFRLL
FFFFBBBLRL
BFFFBFBRLL
FBFBBBBLRR
BFBBBFFLLR
FFFBFFBRLR
FBFFBFFLRR
FFFFBFFLLL
BFFBBBFLLL
BFFFBBBRLL
FBFFFFBLRL
BBFFBBFRLL
BFBBBFBLRL
FBBFFBBRLL
BFBBBBBLLL
BFBFBFBLRL
BFFBBFBLRL
BFFBFFBRRR
FFBBBBFLRR
FBBBBFBRRR
FBBBFBFLLR
FFBFBBFLLL
BBFFBBFLRR
FFFBBFFRLR
FBBBFFFRLL
FBBBBFFRRR
FFFBFBFLLL
BBFBFFFLLL
FBFFBFBRRR
BFFFBFFLRL
FFBBBFBLLL
FBBBBFBRLR
BFBFFBFLLL
BFBFBBFLLL
FBFBFFBLLL
FBBBBFFRLR
FBFFBFFRLR
BFBFBBFLRR
FBFBBBBLRL
FFFFBBFRLL
FFBFBBBRRR
BFFBBFFRRL
BBFFBBFRLR
FBBFFBFLLR
FBFFBFFLLL
BBFFFBFRRL
FBFFFFBRLL
FBFBFBFRRL
FFBFFFBLLR
BFBFFBBLLL
BFBFBFFLRR
FBFFBFFRLL
BFFBFBFLLR
FBFBFFBLRL
FFBFBFFRRL
FBFBBBBRLR
FFFFBBBRLL
BFBBFBFLLL
FBFFFFFLLL
FFBBFBFLRR
FFBFBFBRRL
FBFFBFBRRL
FBFBFBFRLR
FFFBBBFLRL
BFBBBBBRLR
BBFFBBFLLL
FBBFBBBLRR
FFBBBFBRLL
FBFFBBFRRR
FFFFBFFLRL
FFBFBBFRLR
FBBFBFFLRR
FFBBFBFLLL
FFBFBBBLLL
BFFFBBBLLL
BFFBBBBRLR
BFBBFBBLLL
FFBBBFBLRL
BFFBBFFRRR
FFFBBFBRLL
BFBFBFFLLL
BFFBBBFRLR
BFBFFBBLRR
FBBFFFBRRR
FBBFFFFRRR
BFBFBFBLLR
BBFFBBFRRL
FFFFBBBRRL
FFFBFBFLRL
BFFFBFFLLR
FFBBFFFRRL
FFFBFBBRRR
BFFFFBBRRL
BFBBFFFLRR
BFBFFFFRLL
FFFFBBBRLR
FFFBBFBLLR
FBFBFBFRLL
BFBBFBFLRL
BFBBBBBRRR
FBFFFFBRRL
BFBFFFBLRL
FBFBBBFRLR
BFBFFBFLRR
FFBFBFFLRR
FFFBBBFRRR
FFBBFFBRLR
FFBFFFFLRR
FBBBFFFLRL
BFBBFFBLLR
BFFBFBBLRR
FBBFBFBLRL
BFFFBFBLLL
FFFBBFFLRR
FBFFFFFRRR
BFBFFBFLRL
FFBFFFBRRR
FBFBFBBLLR
FFFFBBBLLR
BFBFFFFRRL
FFBBFFFRRR
FBBBFBFLRL
BFBBBFFRLL
BFBFFBBLRL
BBFFFFFLLR
FFBBBFFLLL
FFBFFFBRLL
FFBBFFBLLR
BBFFBFFLLL
FBFBBFBRRR
FBBBBBFLLR
FFBFFFFLRL
FBBBBFFLLL
BFFBFBFRRR
FBFFFFFLRR
FFFFBBFLLR
FFFBFBFRRL
FBFBFBFLRR
FBFBBFFRLR
BFFFBBFRLR
FFBFFBBLRR
FFBBFFBRRL
BFBFFBFRRL
FFFBFFBLRR
BFBBFFFRRR
BFFBFBFLRL
FFBFBBFRRL
BFFFBFFLLL
FBFFBFBLLL
BFBBFFFLLR
BFFFFBBLRR
FFFBFFFLLL
BBFFBBBRLL
BFFBFBFLRR
FBBFBFFRLL
BFFBBBBRLL
BFBFBBFLLR
FBBBBBBRLR
BFBBBBFRRR
FFBFFBFLLL
BFFFFFBRRL
BFFFBFFRLL
BFFFBFBLRL
FFBBBBFRLR
FBBBFFFLRR
BFFBFBBRRL
BBFFFFFRRR
FBBBFBBLLL
FFBFFFBLRR
FFBBFBBRLL
FBFBBFFLLL
BFFFBFFRLR
BFBBBBBLRL
FFFBFFBRRR
FFFBBFFLRL
FBFBFBBRLL
FFFBFBBRLL
FFBFBFBRLL
FBFFFBFRLL
BFFBFBFRRL
FBBFFFBRLR
BFBBBFFRRR
FBBBBBFLRL
FFFFFBBRRL
FBFFBBFLLL
BFBBFBBLRL
BFFBBFBLLL
FFBFBFFLLL
FFFBBBFLLL
BFFBFBFLLL
FBFFFFBRLR
FBFBBFBLRL
BBFFFBFRLR
FFFBBFBLRR
BFFBFFBRLL
BFFBBFBRLL
FBBFFFFRLR
FBBFFFBLLL
FFBFFFFRRL
FFFFBFFLLR
FFFBBFFRLL
BFBBBFBRLR
BFBFFFBLRR
BFFFBBFLRR
BFBFFBFRLL
BFBBFFBRRL
FFFFBBBLRR
FBFFFBBLRL
FFBBBFFRLL
FBBBFBBRLR
FFBFFBFRRR
FBFBFFFRRL
BFBBBFFRLR
FFFBBBFLRR
FFFFBBFRRL
FFBFBFBLRR
FFFBFFBLLL
FBFFFBBRRL
FFFFBFFRLR
FFBBBBBLRR
FFFFBFFRLL
FBFFBBBRRL
BFFFFBBLRL
FBFFBBBRLL
BBFFFFFLRL
FBFBBFFLRR
FBBBBFBRLL
BFFBFFFLLL
FBBBFFFRLR
BFBBFFBLRR
FFBBFBBLLL
FBBFFBBRRL
BFBFBFBLRR
FFFBBFBRRL
BBFFFBFLRR
FBBBBBBLLL
BFFFBFBRRR
FBFBFFFLLL
FFBBBBBLLL
BFBFBFFLLR
FBBFFBBLLL
FBBBBBBLRL
BBFFBBBRLR
FBFFFBBRLL
BFBFBBBRLL
BBFBFFBLLR
FFFBBFFRRR
FBFBFBBRRR
FBBFBFFRRR
BFBBBFBRLL
FBFBFFBLLR
BBFFBFBLLL
BFFFBBFRLL
FBFBFFFLLR
FBFFFFBRRR
FFBFBBFLRL
BBFFFBFLLL
FBBFBBBLLL
FBBBFBBRRL
FBFBFBFLLL
FFFFBFBLRL
FFFFFBBRRR
FFBFFBBLLR
BBFFFFFRRL
FBFBBBFLLR
BFBBBFFRRL
FBFBBFBRLR
BFBBBFBLRR
FFBFBFFLLR
FBFBFFBRRL
FFBFBFBRLR
BFBFFBBRLL
FFBFFFFRRR
BFFBBFBRRR
FFBBBBFRRL
FFFBBBBLRL
FFBBBFFRRL
BFBBBBFRLL
BFBFBFBLLL
BFBBFFFRRL
BFFBFFBLLR
FFBBBFBRLR
FFBBFBFRRL
FBFFBBBLRR
FBBFBBBLLR
BFBFFBBLLR
BFFFFBFLLL
FFFBFBFLLR
FBFFFFBLRR
FBBFBFBLLL
BFFFFBFRLR
FBBBFBFRLR
FFBBFBFRLR
BFFFFFFLLR
BFFFFBFRRL
BBFFBBFRRR
FBFFBFFLRL
FBBBBBFRLR
FBBBBFBLRL
BFFFBBBRRR
FFFFBFFRRL
FFBFFFFLLL
FFFBFBFRLL
FFBFFBFLRR
FBBFFBFLRL
FBBFFBBLRR
FFBFFBFRRL
BFFFFFFRRR
BFBFBBBRLR
BFFBFBBRLL
BBFFBFFRRL
FBBFBBFRLL
BFFFFFBRLR
BFBBBBFLLL
BFBBFFBRRR
FFFFBFBLLL
FFBBFFFRLR
BFBBBFBRRL
BFFFBBFRRR
FBFFFFFRRL
BFFBFFFRLL
BFFFFBBRLR
FFBBFFBLRR
BBFFBBBLRR
FBBFFFFRRL
BFFFFBBRLL
BFFFFFBRLL
BFBFFFFLLR
FBBBBBFRRL
FBFBBBBRRR
FBBFBBFRRL
FBBBFBBRLL
FBFFBFFLLR
FFBFFFFRLR
BFFFFFFRRL
BFBBFFFRLR
FFBBBBFLRL
FFBFFBBRLL
FFBBFBBLRL
FBFBFFBLRR
BFFBFBFRLR
FBFFBBBRRR
FBBBBFFLRL
FBBFBFFRRL
FFBFBFFLRL
BFFBBFBRLR
BBFFFFFLRR
FBBFFFBRLL
BFFFBFBRRL
FFBFBFFRLL
BBFFBBBRRR
BBFFFFBLRL
BBFFFBBRRR
BBFFFFBRLL
FBBFFBFLLL
BFFFBBBLRR
FFBFFBFLLR
FBBFBFFLLR
FBFBBFFLRL
FBBBBFBRRL
BFBBFBFLRR
BBFFBFBLRR
FFFBBBBLRR
FBBBFFBRLR
FBFBFBBLRR
FBBBFBBRRR
BFBBFFFLLL
BFFFFBBLLR
FBBBBBBRLL
FBBBFBBLRL
FBBBBBBRRR
FFFBBBFRLL
BBFFFFFLLL
FBBFFBFRLR
BFBBBBFLRL
BFFFFBFRRR
FBFFBBBLRL
BFBBFBBRRL
FBFFBFBLRL
FFFBBFBRRR
BFBFBBBRRR
BFBBFFFLRL
BBFFFBBRRL
FFFBBBBRRL
FBBBFFBLLR
FBFBFFFLRR
FBFBFBBRLR
BFFFBBFRRL
FBFBFBFRRR
FBBFFFFLLL
FBBFFBBLRL
FBBBFBFLRR
FFFBBFFLLL
BFFBFFBRRL
BFFFFBBRRR
FFFFFBBRLR
BBFFBBBLRL
FBBFBBFRRR
BFBBFBBLRR
FFBFFFFRLL
BFBFFFBRRL
FBBFBBBRLL
FBFBBFBRLL
FBFFFBFRRL
BFFBFFBLRR
FBBFBFBLRR
BFBBBBFLLR
BFBBBFBLLR
FFFFBFBRRL
FFFBBBBRLR
FFBFFFBRLR
BFFBFFBLRL
FBBFBFFLLL
BFFBFBBLLL
FBFBBFBLLR
FBBFFBFLRR
FFBBBBFLLR
FBBFBFFLRL
FFFBFBBLRL
FBBFFFFRLL
BFBFBBFRRR
FBFFBBBLLL
FFBFBBBLRL
BBFFBBFLLR
FBFFFBFLLL
BFBFBFBRRR
BFBBBBBRRL
BBFBFFBLLL
BFFFFFFLRL
FBBFFFBRRL
FFBBFBFRLL
BBFFBFFLLR
BBFBFFFRRL
FFFBBFBLLL
BFFBFFFRRL
BFBBBBBRLL
FFFBFBFRLR
FBFFBBFRRL
BFFBFFFLLR
FFBBFFFLLL
BFFBBBFRLL
FFBBBBFRLL
FFFFBFFLRR
FFBBBBBLRL
FBBBBBBLRR
FBBFFFBLLR
BBFFFBBRLL
BFFBBFFLRL
FFFBFBFRRR
FBFBFBBLLL
FBBBBBFRLL
FBBBBBBRRL
FBFBBBBRRL
FBFFBFFRRL
BFFFBBFLLR
BFFBFFFLRR
BFFBBFBLRR
FFFFBFBRLL
BFFBFFFLRL
FFBFFFBLRL
FBBFFFBLRR
BFBBBFFLRL
FBFFBBFLRL
BFFFBBBRLR
BFFBFBBRRR
BFFFFFBLRL
BBFBFFFLRL
BFBFBBFRRL
BBFFBFFLRR
FBFBFBBLRL
BFBFBBFRLR
FFFBBBBRRR
FBFFFFBLLR
FBFBBFFRLL
BFBFFBFRRR
FFFBFFBLLR
FBFBFBFLRL
FBBFBBBRLR
FFFBFBBLLR
FFBBFFFRLL
BFBFFBBRLR
BBFFFFBLLL
FFBBBFFRRR
BFFBFFFRLR
FFBFFBBLRL
FBBBFFBRRR
BFBFBBFRLL
BFBBBBFRRL
BFBBFFBRLL
BBFFFBBLRL
FFBBBBFRRR
BBFFFBFRRR
BFBFFFFLRR
FFFBFBBLRR
BFFBBFBRRL
FBBFBBBRRR
FBFBFFFLRL
BFBBFBFRLR
FFFBFFFLRL
FFBBBFBRRR
FBBFFBBRRR
BBFFFBBLLR
FFFBFFBLRL
FFBFBBBRRL
FFBBBFFLLR
FBFFBBFRLR
FBFFFBFLRL
FFBBFBBRRL
FFFBBFFRRL
FBBFBBFRLR
FBFBBFFRRR
FFFFBFFRRR
BFFFFFBLRR
BBFFFFBRRL
FBBBFFBLRR
BFFBFBFRLL
FFBFFFBRRL
FFBFBFBLLR

99
day5/src/main.zig Normal file
View File

@ -0,0 +1,99 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var gpa = &arena.allocator;
defer arena.deinit();
// Read entire file
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var highest_id : u32 = 0;
var seat_ids : [814]u32 = undefined;
var it = std.mem.tokenize(contents, "\n");
var i : u32 = 0;
while (it.next()) |n| {
var s = decode_seat_id(n);
var id = s.get_id();
highest_id = std.math.max(highest_id, id);
seat_ids[i] = id;
i += 1;
}
std.log.info("Highest seat id: {}", .{highest_id});
// Part2: This works because the IDs are otherwise contiguous
std.sort.insertionSort(u32, seat_ids[0..], {}, asc_u32);
// Search for a gap of 3, we're the middle of the gap
var prev : u32 = 0;
for (seat_ids) |id| {
//std.log.debug("{} [prev: {} // delta {}]", .{id, prev, id - prev});
if (prev == 0) {
prev = id;
continue;
}
if ((id - prev) != 1) {
std.log.info("Gap of {} found between {} and {}", .{id - prev, prev, id});
std.log.info("Seat ID: {}", .{id - 1});
}
prev = id;
}
}
const asc_u32 = std.sort.asc(u32);
const Seat = struct {
row : u32 = 0,
col : u32 = 0,
pub fn get_id(self: *Seat) u32 {
return (self.row*8) + self.col;
}
};
fn decode_seat_id(code: []const u8) Seat {
//std.log.debug("{}", .{code});
return Seat {
.row = _bsp(code[0..7], 127),
.col = _bsp(code[7..], 7),
};
}
fn _bsp(code: []const u8, max_val: u32) u32 {
var min : u32 = 0;
var max : u32 = max_val;
for (code) |c| {
var half_range = (max-min)/2;
if (c == 'F' or c == 'L') {
// Low half
max = min + half_range;
}
else if (c == 'B' or c == 'R') {
min = max - half_range;
}
}
//std.log.debug("{} --> {}, {}", .{code, min, max});
std.debug.assert(max == min);
return max;
}
test "bsp" {
var s0 = decode_seat_id("FBFBBFFRLR");
std.testing.expectEqual(s0.row, 44);
std.testing.expectEqual(s0.col, 5);
std.testing.expectEqual(s0.get_id(), 357);
var s1 = decode_seat_id("BFFFBBFRRR");
std.testing.expectEqual(s1.row, 70);
std.testing.expectEqual(s1.col, 7);
std.testing.expectEqual(s1.get_id(), 567);
var s2 = decode_seat_id("FFFBBBFRRR");
std.testing.expectEqual(s2.row, 14);
std.testing.expectEqual(s2.col, 7);
std.testing.expectEqual(s2.get_id(), 119);
var s3 = decode_seat_id("BBFFBBFRLL");
std.testing.expectEqual(s3.row, 102);
std.testing.expectEqual(s3.col, 4);
std.testing.expectEqual(s3.get_id(), 820);
}

27
day6/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day6", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

2079
day6/input Normal file

File diff suppressed because it is too large Load Diff

118
day6/src/main.zig Normal file
View File

@ -0,0 +1,118 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var records = try read_records("input", gpa);
// part 1
var yes_per_group = std.ArrayList(u32).init(gpa);
var yeses : u32 = 0;
for (records.items) |r| {
var map = std.hash_map.AutoHashMap(u8, bool).init(gpa);
defer map.deinit();
try map.ensureCapacity(26);
for (r) |c| {
if (std.ascii.isAlpha(c)) {
map.putAssumeCapacity(c, true);
}
}
var count = map.count();
std.log.debug("{} yeses in group '{}'", .{count, r});
try yes_per_group.append(count);
yeses += count;
}
std.log.info("{} yeses across {} groups", .{yeses, yes_per_group.items.len});
// part 2
const one :u26 = comptime 1;
var and_yeses : u32 = 0;
for (records.items) |r| {
var it = std.mem.tokenize(r, " ");
var state : u26 = std.math.maxInt(u26);
while (it.next()) |answer| {
var person_yeses : u26 = 0;
for (answer) |c| {
if (std.ascii.isAlpha(c)) {
person_yeses |= (one << @intCast(u5, (c-97)));
}
}
//std.log.debug("{x} <-- {}", .{person_yeses, answer});
state &= person_yeses;
}
//std.log.debug("{x}", .{state});
var count = count_one_bits(state);
//std.log.debug("{} and-yeses in group '{}'", .{count, r});
and_yeses += count;
}
std.log.info("{} and-yeses across {} groups", .{and_yeses, yes_per_group.items.len});
}
fn count_one_bits(a: u26) u32 {
var i : u5 = 0;
var one : u26 = 1;
var count : u32 = 0;
while (i < 26) : (i += 1) {
var b : u26 = one << i;
if ((a & b) == b) {
count +=1;
}
}
return count;
}
fn read_records(filename: []const u8, allocator: *std.mem.Allocator) !std.ArrayList([]u8) {
var file = try std.fs.cwd().openFile(filename, .{});
var reader = file.reader();
var records = std.ArrayList([]u8).init(allocator);
var record = std.ArrayList(u8).init(allocator);
var n_newlines : u32 = 0;
var just_had_newline = false;
const state = enum {
AddingData,
CheckingNewline,
RecordEnd,
};
var current_state = state.AddingData;
while(true) {
var n = reader.readByte() catch |err| {
// Finalize record
try records.append(try allocator.dupe(u8, record.items[0..record.items.len]));
//std.log.debug("Found record: '{}'", .{record.items});
record.deinit();
record = std.ArrayList(u8).init(allocator);
std.mem.set(u8, record.items, 0);
break;
};
if (n == '\n') {
if (current_state == state.CheckingNewline) {
current_state = state.RecordEnd;
// Finalize record
try records.append(try allocator.dupe(u8, record.items[0..record.items.len]));
//std.log.debug("Found record: '{}'", .{record.items});
record.deinit();
record = std.ArrayList(u8).init(allocator);
std.mem.set(u8, record.items, 0);
current_state = state.AddingData;
continue;
}
else {
current_state = state.CheckingNewline;
// whitespace can always be added
try record.append(' ');
continue;
}
}
else {
if (current_state == state.CheckingNewline) {
current_state = state.AddingData;
}
try record.append(n);
}
}
std.log.debug("Found {} records", .{records.items.len});
return records;
}

27
day7/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day7", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

594
day7/input Normal file
View File

@ -0,0 +1,594 @@
vibrant aqua bags contain 1 shiny magenta bag, 2 muted teal bags, 1 dim magenta bag, 1 muted chartreuse bag.
vibrant violet bags contain 4 pale maroon bags.
dark indigo bags contain 1 light maroon bag, 3 pale red bags, 1 drab brown bag, 4 dim magenta bags.
dark coral bags contain 5 dull aqua bags, 5 plaid green bags, 2 posh bronze bags.
dim lavender bags contain 2 muted violet bags, 5 wavy gold bags, 3 vibrant plum bags, 5 bright teal bags.
mirrored turquoise bags contain 5 muted olive bags, 5 bright gold bags, 2 vibrant violet bags.
faded brown bags contain 5 faded tomato bags.
muted orange bags contain 5 dull aqua bags, 2 light salmon bags, 1 striped black bag, 1 pale gray bag.
posh black bags contain 4 faded silver bags.
muted coral bags contain 3 mirrored turquoise bags.
clear silver bags contain 5 dark cyan bags.
clear crimson bags contain 2 dim blue bags, 4 bright indigo bags.
clear salmon bags contain 4 striped cyan bags, 1 muted maroon bag, 1 light bronze bag, 1 vibrant tan bag.
light olive bags contain 1 faded white bag, 2 dull chartreuse bags, 5 faded gray bags.
muted maroon bags contain 5 dark fuchsia bags, 5 drab violet bags.
posh plum bags contain 2 striped gray bags, 5 dim violet bags.
light orange bags contain 1 light purple bag.
drab white bags contain 4 plaid lime bags, 1 drab gold bag.
plaid indigo bags contain 5 clear lime bags, 1 dark fuchsia bag.
muted red bags contain 1 dull bronze bag.
mirrored magenta bags contain 5 plaid white bags, 1 faded plum bag, 5 wavy purple bags.
dotted lavender bags contain 5 shiny olive bags, 3 plaid blue bags, 1 shiny gold bag.
drab bronze bags contain 3 wavy silver bags, 4 light turquoise bags, 1 vibrant lavender bag, 5 light magenta bags.
plaid maroon bags contain 2 dim salmon bags, 5 muted violet bags.
dull salmon bags contain 5 striped beige bags, 2 muted plum bags, 1 posh teal bag.
dotted turquoise bags contain 5 striped orange bags.
bright yellow bags contain 2 shiny olive bags, 3 wavy teal bags, 1 pale plum bag, 3 mirrored coral bags.
dark black bags contain 5 pale gray bags.
shiny yellow bags contain 4 dark aqua bags, 2 drab lime bags, 2 bright gold bags, 4 dark cyan bags.
shiny red bags contain 2 posh blue bags.
posh olive bags contain 3 dim aqua bags.
muted chartreuse bags contain 4 posh brown bags, 5 shiny magenta bags.
mirrored orange bags contain 5 dotted salmon bags, 1 posh green bag.
muted plum bags contain 1 dull red bag, 4 posh green bags.
light green bags contain 2 wavy plum bags.
light cyan bags contain 2 dotted crimson bags, 4 faded salmon bags, 3 muted coral bags, 3 plaid blue bags.
dull lavender bags contain 3 drab gold bags, 5 plaid crimson bags.
posh red bags contain 3 dotted salmon bags, 2 pale beige bags, 2 mirrored coral bags, 5 muted teal bags.
vibrant beige bags contain 2 faded lime bags.
plaid blue bags contain 5 dull red bags, 3 light maroon bags, 4 muted gold bags, 2 drab orange bags.
dotted white bags contain 3 muted white bags.
drab fuchsia bags contain 2 shiny fuchsia bags.
drab crimson bags contain 1 posh beige bag, 4 drab violet bags.
drab beige bags contain 3 mirrored orange bags, 1 wavy silver bag, 2 pale magenta bags, 1 drab lime bag.
posh teal bags contain 2 clear brown bags.
mirrored brown bags contain 2 faded tan bags.
clear coral bags contain 1 muted chartreuse bag, 2 muted violet bags, 2 faded purple bags.
pale lime bags contain 5 vibrant aqua bags, 3 wavy purple bags, 1 drab violet bag.
vibrant red bags contain 5 shiny gold bags.
shiny fuchsia bags contain 1 dark salmon bag, 1 posh white bag.
bright gray bags contain 2 dim red bags.
drab lavender bags contain 2 clear tomato bags, 1 faded red bag, 1 pale chartreuse bag.
clear red bags contain 3 light salmon bags, 1 bright red bag, 5 dark indigo bags.
bright aqua bags contain 3 faded brown bags, 1 shiny yellow bag.
faded red bags contain 3 posh turquoise bags, 5 dark fuchsia bags.
faded turquoise bags contain 3 drab fuchsia bags.
dim aqua bags contain 1 faded white bag, 5 faded violet bags.
muted white bags contain 5 pale red bags, 4 dull red bags, 3 dotted maroon bags.
dull gold bags contain 3 posh green bags, 2 mirrored yellow bags, 2 dull olive bags, 2 bright purple bags.
faded blue bags contain 3 wavy crimson bags, 1 plaid beige bag, 3 dotted orange bags, 1 vibrant purple bag.
faded gray bags contain 1 bright gold bag.
dim bronze bags contain 2 bright gold bags, 4 light brown bags, 5 muted chartreuse bags.
light teal bags contain 5 striped tomato bags, 5 drab teal bags, 5 shiny lavender bags.
striped white bags contain 1 plaid silver bag, 2 wavy plum bags, 3 dull maroon bags, 2 muted green bags.
vibrant salmon bags contain 2 shiny violet bags, 4 light salmon bags.
dim plum bags contain 1 dull blue bag, 5 vibrant bronze bags.
dotted fuchsia bags contain 4 plaid green bags.
plaid crimson bags contain 3 clear teal bags, 5 dark gray bags, 2 mirrored tan bags, 5 shiny fuchsia bags.
pale white bags contain 2 muted silver bags, 1 muted lime bag.
bright violet bags contain 2 clear chartreuse bags, 2 dull gray bags, 2 muted cyan bags.
drab red bags contain 1 dotted white bag, 1 light plum bag, 5 muted indigo bags, 1 dull lime bag.
muted indigo bags contain 3 mirrored blue bags, 5 light fuchsia bags.
vibrant cyan bags contain 2 pale blue bags, 3 mirrored chartreuse bags.
mirrored gray bags contain 1 shiny red bag, 2 pale blue bags, 4 dotted lime bags, 1 faded violet bag.
posh lavender bags contain 3 vibrant aqua bags, 5 mirrored chartreuse bags.
dotted silver bags contain 3 dark beige bags, 5 dotted teal bags, 3 mirrored indigo bags, 2 dim yellow bags.
wavy magenta bags contain 4 wavy beige bags.
faded tomato bags contain 3 plaid black bags, 5 bright orange bags, 2 vibrant blue bags.
mirrored maroon bags contain 3 plaid gray bags.
pale bronze bags contain 4 vibrant violet bags, 2 muted white bags.
plaid turquoise bags contain 2 dotted lime bags, 3 striped beige bags, 1 pale crimson bag, 2 pale purple bags.
posh turquoise bags contain 5 clear yellow bags, 1 dotted turquoise bag, 3 dim cyan bags, 5 pale maroon bags.
wavy white bags contain 2 mirrored gray bags, 3 pale yellow bags.
vibrant tan bags contain 1 wavy lavender bag.
pale turquoise bags contain 2 dark gray bags, 4 faded green bags, 1 light maroon bag, 5 posh white bags.
faded beige bags contain 1 striped brown bag, 1 dull gray bag, 5 mirrored blue bags.
bright maroon bags contain 1 light blue bag, 5 dim bronze bags, 4 dotted beige bags.
shiny lavender bags contain 3 dim gray bags, 4 pale gray bags.
dull beige bags contain 3 dark crimson bags.
striped coral bags contain 3 dark lavender bags, 2 mirrored turquoise bags, 5 posh maroon bags, 1 striped yellow bag.
shiny magenta bags contain 1 plaid black bag.
muted magenta bags contain 2 plaid beige bags.
light salmon bags contain 5 striped black bags, 1 pale lavender bag.
shiny white bags contain 2 bright gold bags, 3 mirrored olive bags.
dark tomato bags contain 2 dark gold bags, 2 clear teal bags, 5 dull fuchsia bags, 4 dotted gold bags.
dotted violet bags contain 3 plaid teal bags, 5 mirrored aqua bags.
plaid purple bags contain 4 mirrored olive bags.
drab lime bags contain 5 bright beige bags, 4 mirrored tan bags, 5 striped black bags, 4 faded green bags.
dull blue bags contain 4 light red bags, 2 pale turquoise bags, 1 posh maroon bag.
muted tan bags contain 1 pale magenta bag, 3 mirrored turquoise bags, 3 shiny blue bags, 4 dotted salmon bags.
dim teal bags contain 1 posh turquoise bag, 3 dull red bags.
muted fuchsia bags contain 4 pale salmon bags, 1 pale silver bag, 3 pale maroon bags, 2 bright purple bags.
bright gold bags contain 2 shiny magenta bags, 4 pale red bags, 4 posh brown bags.
faded lime bags contain 5 vibrant bronze bags, 2 pale violet bags, 2 plaid coral bags.
posh tan bags contain 3 bright lavender bags, 2 striped blue bags, 5 shiny gold bags.
posh bronze bags contain 3 plaid olive bags, 3 dotted salmon bags.
shiny lime bags contain 1 bright salmon bag, 3 faded green bags, 2 wavy aqua bags.
faded lavender bags contain 2 bright silver bags.
muted black bags contain 5 mirrored coral bags.
plaid chartreuse bags contain 3 dull coral bags, 2 light tomato bags.
mirrored aqua bags contain 2 dark cyan bags, 2 dark indigo bags.
dark yellow bags contain 5 dotted lime bags, 1 dim cyan bag.
bright plum bags contain 5 dim salmon bags.
striped gray bags contain 3 plaid black bags, 1 wavy crimson bag, 5 bright orange bags.
faded salmon bags contain 3 clear lime bags, 4 drab purple bags.
pale olive bags contain 2 light magenta bags, 4 dim salmon bags, 5 light olive bags, 2 pale salmon bags.
faded crimson bags contain 2 wavy beige bags, 4 dim aqua bags, 5 light lavender bags.
posh chartreuse bags contain 5 pale lavender bags, 5 mirrored turquoise bags, 2 dark maroon bags.
posh aqua bags contain 5 faded crimson bags, 2 mirrored tan bags.
faded coral bags contain 2 dotted lime bags, 2 faded white bags.
striped bronze bags contain 4 plaid blue bags, 1 plaid coral bag.
wavy orange bags contain 5 pale tomato bags.
dim crimson bags contain 4 posh tan bags, 1 muted gold bag.
clear gray bags contain 3 striped lime bags, 4 vibrant fuchsia bags.
light gold bags contain 4 bright tan bags, 5 faded lime bags, 4 faded plum bags, 5 clear brown bags.
wavy red bags contain 4 pale red bags, 4 dotted maroon bags, 4 mirrored violet bags.
dull silver bags contain 1 striped turquoise bag, 2 striped orange bags, 1 dotted plum bag, 3 muted coral bags.
striped magenta bags contain 1 mirrored tan bag.
plaid plum bags contain 4 wavy tan bags, 5 wavy brown bags, 5 shiny olive bags, 5 clear yellow bags.
faded chartreuse bags contain 1 shiny teal bag.
clear chartreuse bags contain 2 drab tan bags, 3 plaid maroon bags, 2 drab orange bags, 2 plaid salmon bags.
wavy olive bags contain 5 dark lavender bags.
dull orange bags contain 1 dull gray bag, 2 light magenta bags.
wavy gold bags contain 5 vibrant yellow bags, 4 pale black bags, 2 light olive bags.
muted salmon bags contain 5 dotted turquoise bags, 5 dotted violet bags.
wavy tan bags contain 2 plaid green bags.
dotted cyan bags contain 4 drab gold bags, 1 dark crimson bag, 3 pale lavender bags.
wavy coral bags contain 3 mirrored blue bags, 5 wavy white bags, 1 striped indigo bag.
clear olive bags contain 4 wavy silver bags, 2 pale orange bags, 2 bright tan bags.
light indigo bags contain 1 pale purple bag, 4 clear teal bags, 1 plaid indigo bag, 4 dim blue bags.
dotted tomato bags contain 4 dim cyan bags.
pale indigo bags contain 2 muted chartreuse bags, 4 faded salmon bags, 3 dull brown bags.
bright magenta bags contain 1 vibrant salmon bag, 1 pale teal bag, 4 faded orange bags.
faded gold bags contain 4 striped cyan bags.
shiny orange bags contain 5 vibrant turquoise bags, 3 pale purple bags.
posh salmon bags contain 1 dotted crimson bag, 3 dark maroon bags.
dull violet bags contain 2 clear indigo bags.
posh gray bags contain 1 shiny fuchsia bag, 1 faded plum bag, 5 pale turquoise bags.
dull chartreuse bags contain 4 dull red bags, 1 striped black bag, 3 dark tan bags, 3 muted maroon bags.
dotted chartreuse bags contain 5 striped aqua bags.
dim magenta bags contain no other bags.
light lime bags contain 2 shiny magenta bags, 3 striped black bags.
drab maroon bags contain 2 vibrant bronze bags, 1 clear white bag, 2 dim gray bags.
drab salmon bags contain 2 wavy crimson bags, 3 dim gold bags, 5 drab chartreuse bags.
dotted crimson bags contain 4 pale purple bags, 3 plaid coral bags.
dull red bags contain 3 dark indigo bags, 2 posh white bags, 4 light maroon bags.
drab turquoise bags contain 2 striped tomato bags, 1 bright gold bag, 5 mirrored tan bags, 1 drab chartreuse bag.
shiny teal bags contain 4 bright lime bags, 2 pale red bags.
dark purple bags contain 5 mirrored beige bags, 1 posh purple bag, 5 dotted beige bags.
drab aqua bags contain 4 plaid blue bags, 3 dark salmon bags, 4 striped lime bags, 4 striped blue bags.
dull magenta bags contain 2 clear white bags, 5 muted bronze bags.
pale tan bags contain 1 pale lime bag.
dark fuchsia bags contain 3 dim coral bags, 1 muted white bag, 2 plaid blue bags.
mirrored beige bags contain 5 dotted magenta bags, 1 wavy olive bag, 1 dark tan bag.
drab tomato bags contain 4 dim cyan bags.
shiny tomato bags contain 2 shiny maroon bags, 2 dark lavender bags, 1 posh red bag, 3 vibrant green bags.
dim turquoise bags contain 4 muted salmon bags, 2 bright purple bags, 4 plaid maroon bags, 3 bright beige bags.
mirrored salmon bags contain 2 drab violet bags, 3 faded red bags.
pale crimson bags contain 3 bright white bags, 5 plaid beige bags.
shiny cyan bags contain 4 light blue bags.
clear lavender bags contain 5 bright turquoise bags.
vibrant purple bags contain 5 pale turquoise bags, 2 posh orange bags.
striped purple bags contain 5 muted orange bags, 5 dark aqua bags.
pale gray bags contain 5 dark indigo bags, 1 vibrant violet bag, 3 pale maroon bags, 4 bright gold bags.
posh brown bags contain 3 drab brown bags, 4 pale red bags, 2 posh white bags, 4 muted gold bags.
muted bronze bags contain 2 clear magenta bags, 5 shiny green bags, 2 mirrored tan bags, 4 posh gray bags.
pale brown bags contain 5 muted white bags, 3 plaid beige bags, 3 wavy lavender bags, 3 clear indigo bags.
dull yellow bags contain 5 clear lime bags, 4 plaid blue bags, 4 dotted lime bags.
light tan bags contain 5 dull blue bags, 2 drab yellow bags, 5 mirrored red bags.
posh gold bags contain 4 dull chartreuse bags, 2 dim magenta bags.
pale silver bags contain 4 dull aqua bags, 4 bright gold bags.
light beige bags contain 3 posh orange bags, 3 mirrored gray bags, 2 bright red bags.
striped turquoise bags contain 2 posh blue bags, 1 striped orange bag, 2 shiny tan bags, 5 vibrant aqua bags.
vibrant plum bags contain 4 pale gray bags.
dotted teal bags contain 2 dim magenta bags.
dull purple bags contain 5 drab brown bags, 4 dotted maroon bags, 1 muted white bag.
mirrored fuchsia bags contain 2 dark tomato bags, 4 faded tan bags, 2 faded white bags, 4 dotted orange bags.
dotted plum bags contain 2 dull aqua bags, 4 faded green bags.
bright fuchsia bags contain 2 wavy blue bags, 5 clear brown bags.
dim beige bags contain 2 pale orange bags.
dotted orange bags contain 2 faded brown bags, 1 clear tomato bag, 1 clear indigo bag.
plaid gold bags contain 1 striped turquoise bag, 3 vibrant magenta bags, 5 shiny gray bags, 5 shiny red bags.
clear plum bags contain 3 dim turquoise bags, 3 faded magenta bags, 2 dull coral bags.
muted green bags contain 3 dim crimson bags.
bright black bags contain 3 pale purple bags, 3 plaid white bags, 1 clear teal bag, 3 pale magenta bags.
dim gray bags contain 3 dull coral bags, 1 pale turquoise bag, 5 wavy cyan bags, 5 striped lime bags.
dotted beige bags contain 5 dull aqua bags, 3 dark fuchsia bags, 1 pale violet bag, 4 dim gold bags.
mirrored lime bags contain 4 plaid tomato bags, 1 pale lavender bag, 5 shiny blue bags, 1 light gray bag.
bright chartreuse bags contain 1 dotted teal bag, 3 shiny lavender bags.
vibrant tomato bags contain 1 vibrant coral bag.
mirrored purple bags contain 4 dark tan bags, 4 faded coral bags.
pale tomato bags contain 1 dull maroon bag, 2 striped tan bags, 5 muted cyan bags, 2 dark maroon bags.
vibrant brown bags contain 1 vibrant bronze bag, 2 pale yellow bags, 4 wavy coral bags.
dim green bags contain 2 striped coral bags.
muted lavender bags contain 3 clear purple bags, 4 dark red bags, 1 light silver bag, 1 dull blue bag.
wavy crimson bags contain 5 muted teal bags, 1 drab brown bag, 3 posh brown bags.
wavy tomato bags contain 4 striped blue bags, 3 mirrored lime bags, 1 shiny gray bag, 1 dark plum bag.
muted aqua bags contain 3 clear silver bags, 3 bright chartreuse bags, 4 striped teal bags, 2 clear indigo bags.
posh blue bags contain 2 posh teal bags, 4 dark maroon bags, 2 drab brown bags, 5 faded coral bags.
vibrant silver bags contain 5 drab yellow bags, 3 faded silver bags, 2 bright silver bags.
dim chartreuse bags contain 4 pale beige bags.
shiny gray bags contain 3 dotted magenta bags, 4 plaid crimson bags.
dim salmon bags contain 4 clear lime bags, 3 muted tomato bags, 2 shiny olive bags.
clear orange bags contain 4 posh beige bags, 5 dotted gray bags, 5 dotted turquoise bags.
plaid salmon bags contain 4 bright indigo bags.
posh beige bags contain 3 pale red bags.
clear lime bags contain 1 bright gold bag.
faded magenta bags contain 5 dim salmon bags, 3 dull aqua bags, 5 drab crimson bags.
drab blue bags contain 5 dark maroon bags, 4 wavy plum bags.
plaid aqua bags contain 5 mirrored orange bags, 3 dull violet bags, 3 bright salmon bags.
muted teal bags contain 4 dull red bags, 1 light maroon bag, 4 dark cyan bags.
posh green bags contain 1 mirrored chartreuse bag, 4 muted chartreuse bags, 5 plaid olive bags, 4 dark salmon bags.
posh fuchsia bags contain 3 bright cyan bags, 1 bright salmon bag, 4 dim salmon bags, 1 light black bag.
muted yellow bags contain 2 muted teal bags, 5 pale orange bags.
clear cyan bags contain 3 clear teal bags, 5 drab aqua bags, 2 drab brown bags.
wavy salmon bags contain 5 dark fuchsia bags, 2 dull gray bags, 4 pale tan bags.
dull crimson bags contain 5 faded indigo bags, 2 plaid black bags.
mirrored white bags contain 2 dotted plum bags, 2 dark coral bags, 3 faded gray bags.
striped violet bags contain 4 mirrored tan bags.
striped tan bags contain 2 posh coral bags.
striped tomato bags contain 1 muted teal bag, 1 faded tan bag.
faded aqua bags contain 5 faded red bags, 2 mirrored coral bags, 5 light red bags, 2 mirrored purple bags.
drab olive bags contain 2 drab gold bags.
bright lavender bags contain 1 dark salmon bag, 1 striped olive bag.
plaid green bags contain 2 bright gold bags.
dim purple bags contain 1 plaid yellow bag, 3 muted plum bags, 2 vibrant magenta bags.
faded violet bags contain 3 mirrored violet bags.
posh tomato bags contain 1 dark indigo bag, 2 pale yellow bags, 5 dull orange bags.
dim silver bags contain 1 dotted white bag, 5 faded white bags.
dotted red bags contain 2 dull yellow bags, 4 dim lavender bags, 1 light gold bag.
bright indigo bags contain 5 pale gray bags, 3 posh white bags.
faded fuchsia bags contain 4 muted green bags, 3 posh magenta bags.
wavy silver bags contain 1 dotted violet bag, 3 drab tomato bags, 4 dark fuchsia bags.
dim white bags contain 2 bright magenta bags.
pale beige bags contain 5 dim orange bags, 5 vibrant red bags.
vibrant orange bags contain 4 dull violet bags, 2 mirrored salmon bags, 1 drab lavender bag.
clear fuchsia bags contain 1 mirrored olive bag, 4 mirrored chartreuse bags, 1 posh beige bag.
vibrant indigo bags contain 5 dim lavender bags, 4 drab blue bags, 1 muted beige bag.
dim brown bags contain 2 posh brown bags.
plaid beige bags contain 1 dark tan bag, 5 clear teal bags, 2 light gray bags, 4 wavy lime bags.
bright crimson bags contain 4 drab chartreuse bags, 4 vibrant blue bags, 5 mirrored lime bags, 2 muted plum bags.
shiny purple bags contain 1 muted crimson bag.
wavy bronze bags contain 1 dim brown bag, 3 light salmon bags, 1 muted teal bag, 3 plaid olive bags.
faded bronze bags contain 2 striped blue bags, 2 posh white bags, 2 posh orange bags.
dark orange bags contain 2 vibrant aqua bags, 5 dark maroon bags, 1 mirrored aqua bag.
drab green bags contain 2 faded aqua bags, 5 posh crimson bags.
clear white bags contain 3 plaid black bags, 2 posh white bags, 5 posh lavender bags, 1 dull purple bag.
wavy black bags contain 4 bright magenta bags.
posh crimson bags contain 3 dark yellow bags, 1 mirrored purple bag, 2 dark maroon bags, 5 shiny olive bags.
dotted gray bags contain 4 posh maroon bags, 2 mirrored chartreuse bags, 5 wavy fuchsia bags.
vibrant lavender bags contain 2 plaid coral bags, 4 posh brown bags, 4 dim tan bags.
drab violet bags contain 4 muted gold bags.
striped maroon bags contain 4 dotted lavender bags, 2 dark fuchsia bags, 3 bright olive bags.
plaid white bags contain 2 wavy olive bags, 2 pale blue bags, 4 pale aqua bags.
pale gold bags contain 4 bright teal bags, 2 posh bronze bags, 3 shiny maroon bags, 1 pale brown bag.
vibrant olive bags contain 3 plaid green bags, 2 light maroon bags, 3 dotted salmon bags, 4 faded tomato bags.
dotted maroon bags contain no other bags.
light blue bags contain 2 dim violet bags, 1 vibrant beige bag.
mirrored tan bags contain 4 drab brown bags, 1 striped orange bag, 5 light maroon bags, 2 dotted maroon bags.
dark beige bags contain 1 drab maroon bag.
light silver bags contain 1 shiny chartreuse bag, 2 dim turquoise bags.
dull green bags contain 2 striped chartreuse bags, 2 mirrored gold bags, 4 dim fuchsia bags.
faded silver bags contain 3 drab violet bags.
bright beige bags contain 5 bright teal bags, 5 mirrored violet bags.
striped gold bags contain 2 wavy beige bags, 4 dim black bags.
wavy fuchsia bags contain 4 posh green bags.
shiny blue bags contain 3 posh maroon bags.
mirrored indigo bags contain 3 striped cyan bags, 2 vibrant blue bags, 5 wavy violet bags.
dim tomato bags contain 4 dull orange bags, 5 shiny green bags, 1 plaid olive bag.
plaid violet bags contain 1 dull violet bag, 4 plaid fuchsia bags.
dark white bags contain 3 drab orange bags.
drab indigo bags contain 3 dark red bags, 2 plaid tomato bags, 5 clear white bags.
shiny beige bags contain 2 posh tomato bags.
striped indigo bags contain 5 clear lavender bags, 5 dotted indigo bags, 1 muted cyan bag, 5 dark olive bags.
drab cyan bags contain 1 drab orange bag, 4 posh gold bags.
light red bags contain 4 dark indigo bags, 1 vibrant violet bag, 4 shiny magenta bags.
muted gold bags contain 3 light maroon bags, 1 striped orange bag, 4 pale maroon bags.
clear indigo bags contain 4 faded green bags, 3 clear crimson bags, 2 vibrant cyan bags.
faded tan bags contain 5 bright gold bags.
shiny salmon bags contain 1 bright lavender bag, 1 posh blue bag, 4 shiny coral bags.
dull turquoise bags contain 5 drab yellow bags, 5 dotted plum bags, 5 plaid magenta bags.
posh lime bags contain 4 wavy tan bags, 4 shiny tomato bags, 4 dim violet bags, 5 bright tan bags.
pale green bags contain 1 wavy gray bag, 2 faded lavender bags, 1 vibrant yellow bag.
mirrored gold bags contain 2 light gray bags, 5 wavy tan bags.
mirrored green bags contain 1 faded violet bag.
dark red bags contain 3 faded bronze bags, 4 dark green bags, 4 wavy crimson bags.
bright tomato bags contain 4 faded bronze bags.
mirrored crimson bags contain 5 faded red bags, 1 drab crimson bag.
faded orange bags contain 2 muted teal bags, 5 pale maroon bags, 1 dark yellow bag.
striped silver bags contain 4 mirrored lime bags, 1 dull tan bag, 1 pale fuchsia bag, 1 wavy purple bag.
wavy aqua bags contain 4 vibrant aqua bags, 4 shiny fuchsia bags, 4 dotted turquoise bags, 4 striped olive bags.
striped lavender bags contain 5 shiny lavender bags, 3 pale lime bags.
vibrant white bags contain 2 dim bronze bags, 2 light red bags, 5 shiny gold bags.
vibrant yellow bags contain 1 shiny turquoise bag, 5 dull beige bags, 4 dark gold bags, 5 dull tomato bags.
striped green bags contain 5 striped tomato bags.
muted silver bags contain 5 striped maroon bags, 5 light salmon bags, 4 clear maroon bags.
light plum bags contain 5 mirrored blue bags, 2 vibrant coral bags, 5 dim brown bags, 2 striped yellow bags.
posh yellow bags contain 1 mirrored salmon bag, 5 light plum bags.
plaid magenta bags contain 3 dull plum bags, 2 mirrored tan bags.
plaid tan bags contain 4 light turquoise bags, 4 faded purple bags, 3 mirrored crimson bags.
shiny black bags contain 3 striped violet bags, 1 dim cyan bag, 2 dim white bags.
wavy brown bags contain 2 plaid lavender bags.
vibrant gold bags contain 1 clear tomato bag, 1 wavy olive bag, 2 faded magenta bags.
clear brown bags contain 2 dim blue bags.
dim fuchsia bags contain 2 bright gold bags, 5 wavy purple bags, 3 posh orange bags.
muted turquoise bags contain 1 light turquoise bag, 3 vibrant plum bags, 5 posh maroon bags, 1 muted maroon bag.
shiny coral bags contain 3 striped yellow bags.
dotted coral bags contain 1 dark orange bag, 4 striped violet bags.
shiny bronze bags contain 5 mirrored yellow bags, 4 light violet bags, 4 light crimson bags.
dull cyan bags contain 2 dim cyan bags, 5 pale red bags.
bright tan bags contain 4 pale gray bags, 4 posh brown bags, 3 shiny fuchsia bags.
pale purple bags contain 5 wavy cyan bags, 5 dark salmon bags, 2 dark indigo bags, 1 plaid black bag.
shiny gold bags contain 2 pale maroon bags, 5 pale purple bags, 4 posh brown bags, 1 dotted turquoise bag.
dim tan bags contain 4 dark violet bags, 3 shiny blue bags.
wavy green bags contain 3 plaid gray bags.
pale orange bags contain 3 dim lime bags, 2 dark coral bags.
faded maroon bags contain 5 clear black bags, 3 light lavender bags, 3 light black bags, 2 muted orange bags.
drab teal bags contain 2 dotted crimson bags, 3 dim teal bags, 5 pale turquoise bags, 4 dark plum bags.
bright orange bags contain 3 pale maroon bags, 1 pale bronze bag, 3 dotted maroon bags.
posh coral bags contain 3 dim gold bags, 1 bright indigo bag, 3 clear black bags.
mirrored bronze bags contain 5 dull violet bags, 3 vibrant red bags.
pale lavender bags contain 2 pale purple bags, 1 pale red bag, 4 vibrant blue bags, 3 muted chartreuse bags.
wavy lavender bags contain 3 drab chartreuse bags, 1 posh teal bag.
pale blue bags contain 1 dark tan bag, 4 faded violet bags, 3 dim coral bags.
striped yellow bags contain 2 pale red bags.
shiny aqua bags contain 3 pale magenta bags.
faded olive bags contain 1 vibrant white bag, 4 muted cyan bags.
dark chartreuse bags contain 3 dim magenta bags, 3 dull plum bags, 2 pale lime bags.
dim lime bags contain 3 muted white bags, 4 striped blue bags.
wavy cyan bags contain 4 light maroon bags.
light bronze bags contain 1 dull lime bag.
muted beige bags contain 4 wavy blue bags, 2 dotted violet bags, 4 shiny orange bags.
dim coral bags contain 4 wavy crimson bags, 3 mirrored tan bags, 2 wavy cyan bags, 5 light maroon bags.
dark green bags contain 2 striped gray bags, 3 pale lavender bags, 1 striped lime bag.
pale cyan bags contain 2 vibrant green bags, 1 mirrored lime bag, 5 vibrant chartreuse bags, 1 shiny lime bag.
shiny crimson bags contain 4 dull aqua bags, 1 pale turquoise bag.
pale black bags contain 3 vibrant olive bags, 2 dull aqua bags, 1 drab turquoise bag.
striped crimson bags contain 4 dotted lavender bags, 2 clear orange bags.
clear maroon bags contain 2 muted bronze bags, 3 vibrant olive bags, 1 striped lavender bag.
dim olive bags contain 1 wavy lavender bag, 1 dotted salmon bag, 1 pale silver bag, 5 vibrant coral bags.
dotted indigo bags contain 3 dark salmon bags, 2 shiny turquoise bags, 4 plaid coral bags.
plaid orange bags contain 2 mirrored plum bags, 5 faded lime bags, 4 dotted brown bags, 2 pale tan bags.
light maroon bags contain no other bags.
light violet bags contain 5 clear yellow bags, 4 muted chartreuse bags.
light lavender bags contain 3 striped olive bags, 1 posh black bag.
muted lime bags contain 2 muted turquoise bags, 3 mirrored yellow bags, 5 clear gray bags.
faded black bags contain 1 bright crimson bag, 1 dotted beige bag, 2 shiny magenta bags.
wavy blue bags contain 5 vibrant plum bags, 5 shiny fuchsia bags, 2 posh orange bags, 1 wavy purple bag.
dark turquoise bags contain 5 shiny tan bags, 2 dull silver bags, 2 muted lime bags, 2 mirrored tan bags.
mirrored teal bags contain 4 pale brown bags, 5 drab lime bags, 5 striped beige bags.
vibrant gray bags contain 5 bright yellow bags, 1 vibrant teal bag.
clear purple bags contain 5 bright silver bags, 1 bright teal bag, 1 wavy lime bag, 4 striped blue bags.
striped lime bags contain 1 mirrored violet bag, 3 dim cyan bags, 3 vibrant turquoise bags, 2 muted white bags.
mirrored lavender bags contain 2 faded yellow bags.
posh maroon bags contain 1 dotted salmon bag, 5 drab violet bags, 5 striped lime bags, 3 dotted olive bags.
faded yellow bags contain 1 dull plum bag, 5 dim fuchsia bags.
dull aqua bags contain 2 pale maroon bags.
dark tan bags contain 4 dark salmon bags.
dim maroon bags contain 4 posh aqua bags, 3 striped yellow bags.
faded purple bags contain 5 clear teal bags, 2 dark olive bags.
clear tomato bags contain 2 pale maroon bags.
dull gray bags contain 5 light brown bags, 3 bright gold bags, 4 faded white bags, 3 vibrant coral bags.
dull maroon bags contain 4 clear indigo bags, 5 shiny magenta bags, 3 drab tomato bags, 4 dim violet bags.
pale coral bags contain 2 pale bronze bags, 2 wavy salmon bags.
drab silver bags contain 3 dark coral bags, 5 shiny violet bags, 5 faded indigo bags.
plaid black bags contain 1 dull red bag.
plaid silver bags contain 4 clear cyan bags.
dotted blue bags contain 2 plaid beige bags, 4 posh cyan bags, 4 shiny gray bags.
dotted magenta bags contain 1 drab orange bag, 5 wavy aqua bags, 2 wavy lavender bags.
clear aqua bags contain 4 striped magenta bags, 4 muted chartreuse bags.
pale red bags contain no other bags.
bright turquoise bags contain 1 wavy purple bag, 3 vibrant turquoise bags, 2 dark brown bags.
vibrant magenta bags contain 5 drab brown bags, 2 striped olive bags, 5 light plum bags.
dull brown bags contain 4 drab teal bags, 4 bright gold bags, 4 dim blue bags, 3 dotted teal bags.
dotted olive bags contain 5 striped orange bags, 1 wavy cyan bag, 3 wavy crimson bags.
bright teal bags contain 3 dim coral bags, 1 dark cyan bag, 4 bright indigo bags.
shiny chartreuse bags contain 1 drab brown bag.
bright lime bags contain 2 pale silver bags.
vibrant crimson bags contain 4 shiny white bags, 4 pale black bags, 5 clear cyan bags, 1 bright tan bag.
muted brown bags contain 5 drab purple bags.
dotted aqua bags contain 1 dim gray bag, 1 dark indigo bag, 3 posh tan bags, 5 dim lime bags.
muted tomato bags contain 1 faded orange bag, 3 vibrant aqua bags.
bright cyan bags contain 4 dotted coral bags, 2 dull lime bags, 5 clear maroon bags.
posh violet bags contain 1 light magenta bag, 4 pale maroon bags, 1 dark teal bag.
wavy turquoise bags contain 1 shiny gray bag, 4 drab tan bags, 3 pale lavender bags.
dark magenta bags contain 2 dull bronze bags.
drab gray bags contain 4 dotted turquoise bags, 5 light aqua bags.
dull coral bags contain 2 plaid black bags, 2 striped cyan bags, 3 faded bronze bags, 5 plaid crimson bags.
vibrant chartreuse bags contain 5 pale turquoise bags.
bright purple bags contain 5 vibrant salmon bags, 1 posh green bag, 4 vibrant beige bags.
mirrored tomato bags contain 4 wavy beige bags, 5 striped tan bags, 2 pale aqua bags.
shiny violet bags contain 3 shiny tan bags, 3 faded brown bags, 4 shiny green bags, 3 shiny orange bags.
plaid lavender bags contain 1 light maroon bag.
faded green bags contain 5 dark cyan bags, 2 clear teal bags, 5 muted olive bags.
dotted salmon bags contain 3 dotted olive bags, 1 dark cyan bag.
faded white bags contain 3 drab brown bags.
striped black bags contain 2 dark green bags, 5 pale bronze bags, 2 plaid olive bags.
dotted brown bags contain 1 drab salmon bag.
dark crimson bags contain 1 vibrant teal bag, 2 dim gray bags, 1 posh orange bag, 3 faded tan bags.
pale teal bags contain 5 dim violet bags.
striped cyan bags contain 3 pale purple bags, 4 dull red bags, 1 dark indigo bag, 3 dark yellow bags.
mirrored coral bags contain 2 shiny olive bags.
shiny maroon bags contain 5 vibrant coral bags, 3 plaid maroon bags, 1 striped turquoise bag, 2 wavy violet bags.
dull indigo bags contain 2 plaid magenta bags, 1 bright chartreuse bag.
drab magenta bags contain 4 striped olive bags, 3 posh white bags.
clear tan bags contain 4 light gold bags, 4 muted gold bags.
dark gray bags contain 4 plaid blue bags, 5 drab brown bags, 3 pale gray bags, 3 mirrored violet bags.
wavy teal bags contain 4 drab aqua bags, 3 pale salmon bags.
dotted tan bags contain 2 pale bronze bags, 3 faded orange bags.
bright brown bags contain 3 bright blue bags.
clear blue bags contain 5 shiny crimson bags, 1 dark cyan bag.
clear yellow bags contain 1 muted gold bag, 1 posh orange bag, 1 dull purple bag, 4 dark indigo bags.
pale aqua bags contain 3 dim coral bags, 2 mirrored aqua bags.
dull olive bags contain 1 dull yellow bag.
muted violet bags contain 3 shiny tan bags.
striped aqua bags contain 2 vibrant green bags, 2 faded coral bags, 2 dark cyan bags, 4 wavy beige bags.
pale fuchsia bags contain 5 dull green bags, 2 dotted aqua bags.
shiny brown bags contain 4 dim black bags.
plaid coral bags contain 3 faded bronze bags, 2 pale lavender bags, 3 dotted tan bags, 2 wavy lavender bags.
posh magenta bags contain 2 clear red bags, 4 dim brown bags.
wavy purple bags contain 4 dim magenta bags.
plaid fuchsia bags contain 2 striped olive bags, 3 light gray bags.
dim violet bags contain 3 dark brown bags, 4 muted plum bags.
light turquoise bags contain 5 clear brown bags, 5 muted chartreuse bags.
dull white bags contain 4 wavy salmon bags, 3 dotted crimson bags, 1 dark coral bag, 1 pale chartreuse bag.
light brown bags contain 2 plaid black bags, 3 light red bags.
dotted purple bags contain 1 posh crimson bag, 4 vibrant red bags, 2 wavy beige bags.
striped orange bags contain no other bags.
clear green bags contain 3 light plum bags, 1 wavy lavender bag, 1 shiny olive bag.
bright red bags contain 5 dotted turquoise bags, 3 dim aqua bags, 2 posh orange bags.
dark bronze bags contain 2 pale yellow bags, 1 striped brown bag, 3 striped chartreuse bags.
muted cyan bags contain 3 muted olive bags, 2 shiny red bags, 1 vibrant lavender bag, 5 drab gold bags.
light coral bags contain 3 shiny gray bags, 5 dull bronze bags, 5 muted fuchsia bags, 5 clear magenta bags.
shiny olive bags contain 4 dull cyan bags, 5 dark gray bags.
drab orange bags contain no other bags.
striped salmon bags contain 5 drab salmon bags, 5 pale plum bags.
plaid cyan bags contain 2 bright blue bags, 1 mirrored gray bag, 5 faded violet bags.
plaid teal bags contain 3 pale maroon bags, 1 clear teal bag.
faded cyan bags contain 1 dim bronze bag, 3 light olive bags, 1 muted beige bag, 1 wavy teal bag.
clear magenta bags contain 5 striped orange bags.
dull black bags contain 1 shiny purple bag, 1 mirrored red bag, 4 dotted fuchsia bags, 3 vibrant crimson bags.
mirrored blue bags contain 3 light brown bags.
mirrored black bags contain 3 dim coral bags, 3 plaid purple bags.
dim black bags contain 4 dim blue bags.
pale plum bags contain 4 muted coral bags, 2 light purple bags.
dark salmon bags contain 2 plaid blue bags, 4 vibrant turquoise bags, 3 posh white bags.
striped red bags contain 1 dim plum bag.
striped beige bags contain 1 dark tomato bag.
clear beige bags contain 2 posh orange bags, 4 muted coral bags.
bright blue bags contain 4 faded gold bags, 4 faded indigo bags.
light purple bags contain 4 muted violet bags, 1 pale red bag.
dim indigo bags contain 3 dim silver bags, 2 faded violet bags.
dotted green bags contain 5 dotted chartreuse bags, 1 pale black bag.
pale yellow bags contain 3 plaid tomato bags.
drab tan bags contain 3 dim plum bags, 2 dark fuchsia bags.
bright white bags contain 3 muted bronze bags.
shiny turquoise bags contain 4 drab brown bags.
pale maroon bags contain no other bags.
faded indigo bags contain 1 faded tomato bag, 2 light red bags, 5 vibrant bronze bags.
dotted black bags contain 1 clear brown bag, 5 mirrored olive bags, 4 dim brown bags, 2 drab red bags.
light chartreuse bags contain 5 muted black bags.
posh orange bags contain 4 light maroon bags, 1 muted white bag.
vibrant turquoise bags contain 1 dark maroon bag, 1 shiny magenta bag, 2 dotted maroon bags.
striped fuchsia bags contain 5 clear blue bags, 5 pale black bags, 1 mirrored maroon bag, 2 dotted maroon bags.
dark violet bags contain 5 clear white bags.
pale salmon bags contain 1 vibrant violet bag, 3 plaid olive bags.
pale violet bags contain 4 shiny chartreuse bags, 5 dark salmon bags, 3 bright indigo bags, 4 dark orange bags.
faded teal bags contain 2 dark gray bags, 2 posh black bags, 3 plaid maroon bags.
drab yellow bags contain 4 mirrored blue bags, 4 mirrored violet bags, 3 dim salmon bags, 1 clear yellow bag.
wavy indigo bags contain 2 shiny olive bags, 5 plaid aqua bags.
shiny tan bags contain 2 wavy purple bags, 1 dotted aqua bag, 1 light violet bag.
dull lime bags contain 1 dull coral bag.
clear turquoise bags contain 1 vibrant fuchsia bag, 5 dull beige bags.
dark blue bags contain 2 dark violet bags, 2 dotted maroon bags, 4 bright aqua bags, 4 clear black bags.
drab black bags contain 2 dim gold bags, 1 plaid crimson bag.
dotted bronze bags contain 5 dim bronze bags.
mirrored cyan bags contain 3 muted salmon bags.
light gray bags contain 1 faded gold bag, 4 faded coral bags, 4 faded silver bags, 2 faded tomato bags.
vibrant blue bags contain 2 muted gold bags.
dark maroon bags contain 3 mirrored violet bags, 3 muted gold bags, 3 drab brown bags, 4 plaid black bags.
pale chartreuse bags contain 5 dotted teal bags, 4 bright gold bags.
mirrored yellow bags contain 4 dim cyan bags.
shiny plum bags contain 3 dull green bags, 3 vibrant olive bags, 3 dim tan bags.
mirrored chartreuse bags contain 1 dark tan bag, 5 drab aqua bags.
dark gold bags contain 4 drab yellow bags, 4 pale bronze bags.
vibrant lime bags contain 3 dull salmon bags.
dim blue bags contain 2 dull cyan bags, 2 dull purple bags, 1 dark indigo bag.
dark brown bags contain 5 dull chartreuse bags.
light tomato bags contain 5 posh teal bags, 3 wavy yellow bags, 5 bright olive bags, 4 pale brown bags.
bright green bags contain 2 bright teal bags.
shiny silver bags contain 2 mirrored indigo bags, 4 faded silver bags, 2 dark lavender bags.
bright olive bags contain 5 drab turquoise bags.
striped teal bags contain 1 vibrant tan bag.
dotted yellow bags contain 1 clear tomato bag, 5 muted orange bags, 3 striped turquoise bags, 3 dim lime bags.
posh white bags contain no other bags.
plaid red bags contain 3 dotted teal bags, 2 light brown bags, 4 vibrant teal bags.
drab purple bags contain 5 pale purple bags, 1 shiny blue bag, 2 shiny orange bags.
vibrant maroon bags contain 3 shiny cyan bags, 5 striped lavender bags.
striped brown bags contain 5 faded salmon bags, 4 clear violet bags, 1 plaid salmon bag, 5 dotted tomato bags.
muted blue bags contain 1 drab chartreuse bag.
striped blue bags contain 4 dark cyan bags.
striped plum bags contain 2 wavy violet bags.
clear violet bags contain 2 dotted crimson bags, 3 plaid magenta bags.
clear teal bags contain 2 bright gold bags, 4 plaid black bags.
dim gold bags contain 5 pale gray bags, 3 drab orange bags, 3 plaid black bags.
wavy violet bags contain 3 dull beige bags.
wavy lime bags contain 2 bright lavender bags.
muted purple bags contain 3 wavy brown bags, 4 muted blue bags.
shiny indigo bags contain 1 shiny aqua bag, 4 bright aqua bags, 2 clear turquoise bags.
dim orange bags contain 5 striped lime bags.
clear bronze bags contain 4 pale black bags, 4 bright olive bags.
wavy gray bags contain 3 dotted teal bags, 2 striped lavender bags, 2 wavy aqua bags.
dull tan bags contain 5 vibrant violet bags, 2 muted maroon bags, 5 vibrant plum bags, 3 shiny red bags.
drab chartreuse bags contain 4 striped gray bags, 4 pale bronze bags, 5 dim aqua bags.
plaid gray bags contain 1 shiny blue bag, 4 clear brown bags, 4 shiny tan bags, 4 plaid beige bags.
drab plum bags contain 5 vibrant cyan bags, 3 vibrant aqua bags, 5 dim coral bags, 1 dull orange bag.
clear gold bags contain 1 drab olive bag, 5 drab orange bags, 4 shiny tan bags.
dull tomato bags contain 3 bright teal bags, 1 muted chartreuse bag.
bright silver bags contain 1 dull chartreuse bag, 5 bright gold bags, 4 faded silver bags.
clear black bags contain 5 dull orange bags, 3 dim black bags, 1 posh beige bag.
striped olive bags contain 2 pale maroon bags.
light fuchsia bags contain 5 pale silver bags, 4 dark olive bags, 1 clear magenta bag.
posh indigo bags contain 2 wavy purple bags, 3 striped beige bags, 4 vibrant white bags.
dark aqua bags contain 5 drab tomato bags, 4 faded red bags, 4 light magenta bags, 4 striped tomato bags.
plaid olive bags contain 2 posh brown bags.
wavy plum bags contain 3 shiny blue bags, 4 dark lavender bags, 5 pale violet bags.
vibrant teal bags contain 4 dull purple bags, 4 dull plum bags.
dotted gold bags contain 3 wavy maroon bags.
drab brown bags contain no other bags.
dull teal bags contain 5 wavy beige bags, 1 muted tomato bag, 1 drab aqua bag.
mirrored plum bags contain 4 muted chartreuse bags, 5 dull orange bags, 3 clear black bags.
wavy beige bags contain 4 pale violet bags, 5 dim tan bags, 3 pale fuchsia bags, 2 wavy tan bags.
plaid lime bags contain 3 pale crimson bags.
plaid brown bags contain 2 dull green bags.
light black bags contain 1 faded gold bag, 1 bright tan bag.
dim cyan bags contain 2 clear yellow bags, 3 plaid blue bags, 1 dull purple bag.
drab coral bags contain 1 bright gray bag, 1 muted magenta bag, 5 mirrored lime bags, 1 mirrored olive bag.
bright coral bags contain 3 plaid blue bags.
mirrored silver bags contain 5 clear white bags.
plaid tomato bags contain 5 dull red bags, 3 shiny green bags, 5 drab fuchsia bags, 3 dull tomato bags.
faded plum bags contain 5 dark violet bags, 3 dim brown bags.
light white bags contain 5 dotted teal bags, 2 dim tan bags.
dull bronze bags contain 3 vibrant turquoise bags.
vibrant coral bags contain 3 faded bronze bags.
posh silver bags contain 5 wavy olive bags, 3 dotted red bags, 3 faded violet bags.
dim yellow bags contain 4 pale tomato bags, 4 dim tan bags, 3 vibrant gold bags, 2 bright gold bags.
bright salmon bags contain 5 shiny orange bags, 2 dark yellow bags, 5 muted gold bags, 4 dark fuchsia bags.
light yellow bags contain 3 clear cyan bags.
dim red bags contain 3 clear lavender bags, 1 muted bronze bag, 4 vibrant salmon bags.
dark silver bags contain 1 dull brown bag, 1 wavy lavender bag, 2 shiny crimson bags, 1 clear tan bag.
dull fuchsia bags contain 5 striped cyan bags, 4 mirrored violet bags.
drab gold bags contain 5 posh lavender bags, 4 mirrored olive bags, 2 dark tan bags, 3 dotted olive bags.
muted gray bags contain 1 striped magenta bag, 2 dull tomato bags, 5 plaid olive bags, 1 faded gray bag.
bright bronze bags contain 1 clear silver bag, 4 dim lime bags.
dark cyan bags contain 5 dark maroon bags, 3 dull red bags, 1 bright gold bag.
dark plum bags contain 1 vibrant turquoise bag.
wavy maroon bags contain 5 shiny gold bags, 1 drab black bag.
light crimson bags contain 2 light plum bags, 3 plaid purple bags.
wavy chartreuse bags contain 2 pale gray bags, 5 dim purple bags, 2 drab turquoise bags.
plaid yellow bags contain 5 muted tan bags, 2 wavy cyan bags, 3 light gold bags, 1 dim gold bag.
mirrored violet bags contain no other bags.
wavy yellow bags contain 2 dim aqua bags, 1 dark fuchsia bag, 5 faded coral bags, 1 faded silver bag.
plaid bronze bags contain 1 striped bronze bag.
vibrant green bags contain 3 striped chartreuse bags, 3 pale lavender bags, 4 dotted lime bags, 4 plaid lavender bags.
muted crimson bags contain 3 dim blue bags, 1 dull lime bag, 3 plaid indigo bags, 1 pale plum bag.
posh cyan bags contain 5 drab brown bags, 5 faded blue bags.
vibrant black bags contain 3 pale silver bags.
light aqua bags contain 2 faded crimson bags, 3 dark bronze bags, 1 dim orange bag.
mirrored red bags contain 3 light violet bags.
dark lime bags contain 1 striped turquoise bag.
mirrored olive bags contain 1 faded bronze bag, 1 drab aqua bag, 1 dark indigo bag, 3 posh white bags.
striped chartreuse bags contain 2 mirrored gold bags.
dotted lime bags contain 1 vibrant turquoise bag, 2 dotted turquoise bags, 5 dull red bags.
vibrant bronze bags contain 1 posh green bag, 3 posh tan bags, 5 light salmon bags.
dark teal bags contain 4 shiny lavender bags, 5 dull orange bags.
shiny green bags contain 2 bright lavender bags, 3 shiny olive bags, 4 mirrored violet bags, 5 posh white bags.
light magenta bags contain 2 pale maroon bags.
pale magenta bags contain 5 dull aqua bags.
dull plum bags contain 2 vibrant violet bags, 5 pale red bags, 2 wavy fuchsia bags.
muted olive bags contain 5 bright teal bags.
vibrant fuchsia bags contain 3 posh brown bags.
dark olive bags contain 5 dim coral bags, 4 pale red bags, 5 drab aqua bags.
posh purple bags contain 2 bright red bags, 4 pale coral bags, 1 dotted bronze bag.
dark lavender bags contain 2 striped blue bags, 5 posh blue bags, 2 plaid green bags.

188
day7/src/main.zig Normal file
View File

@ -0,0 +1,188 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var next_id : u32 = 0;
var map = std.hash_map.StringHashMap(u32).init(gpa);
var it = std.mem.tokenize(contents, "\n");
var bag_rules = std.ArrayList(*BagType).init(gpa);
defer bag_rules.deinit();
while (it.next()) |line| {
//std.log.debug("{}", .{line});
var bag = try gpa.create(BagType);
bag.*.contains = std.ArrayList(*BagRule).init(gpa);
var need_desc = true;
var desc = std.ArrayList(u8).init(gpa);
defer desc.deinit();
var need_count = true;
var count: u32 = 0;
for (line) |a| {
if (need_desc) {
try desc.append(a);
if (desc.items.len > 5) {
if (std.mem.eql(u8, " bag", desc.items[desc.items.len-4..])) {
//std.log.debug("'{}'", .{desc.items});
if (!need_count) {
var key = try std.mem.dupe(gpa, u8, std.mem.trim(u8, desc.items[0..desc.items.len-4], " "));
var bag_id : u32 = 0;
//std.log.debug("'{} {} bags'", .{count, key});
if (map.contains(key)) {
bag_id = map.get(key).?;
//std.log.debug("Bag '{}': {}", .{key, bag_id});
}
else {
bag_id = next_id;
//std.log.debug("Assigned ID {} to '{}'", .{bag_id, key});
try map.putNoClobber(key, next_id);
next_id += 1;
}
var br = try gpa.create(BagRule);
br.count = count;
br.bag_type = bag_id;
std.log.debug("Bag {} should contain {} of {}", .{bag.desc, br.count, br.bag_type});
try bag.contains.append(br);
}
else {
var key = try std.mem.dupe(gpa, u8, desc.items[0..desc.items.len-4]);
var bag_id : u32 = 0;
bag.desc = key;
//std.log.debug("'{}'", .{bag.desc});
if (map.contains(key)) {
bag_id = map.get(key).?;
//std.log.debug("Bag '{}': {}", .{key, bag_id});
}
else {
bag_id = next_id;
//std.log.debug("Assigned ID {} to '{}'", .{bag_id, key});
try map.putNoClobber(key, next_id);
next_id += 1;
}
bag.type_id = bag_id;
}
need_desc = false;
need_count = true;
desc.deinit();
desc = std.ArrayList(u8).init(gpa);
}
}
}
else if (need_count) {
if (std.ascii.isDigit(a)) {
count = @as(u32, a - 48);
need_count = false;
need_desc = true;
}
}
}
//std.log.debug("{}", .{bag});
try bag_rules.append(bag);
}
// for (bag_rules.items) |rule| {
// std.log.debug("{} ({})", .{rule.desc.?, rule.type_id});
// for(rule.contains.items) |r| {
// std.log.debug("\t{} of {}", .{r.count, r.bag_type});
// }
// }
var shiny_gold_id = map.get("shiny gold");
std.log.debug("shiny gold: {}", .{shiny_gold_id});
//var types_that_can_contain_shiny_gold = try types_that_can_contain(gpa, &bag_rules, shiny_gold_id.?);
//std.log.info("{} bag types can contain shiny gold bags ({})", .{types_that_can_contain_shiny_gold.len, shiny_gold_id});
var shiny_gold_type = get_type_by_id(&bag_rules, shiny_gold_id.?).?;
std.log.debug("shiny gold type has {} contain rules", .{shiny_gold_type.*.contains.items.len});
//std.log.debug("{}", .{shiny_gold_rule});
var n_bags_needed = bag_type_has_how_many_bags_needed(shiny_gold_type, &bag_rules);
std.log.info("{} needs {} bags purchased, including itself", .{shiny_gold_type.*.desc, n_bags_needed});
}
fn bag_type_has_how_many_bags_needed(self: *BagType, list: *std.ArrayList(*BagType)) u32 {
var count : u32 = 1;
if (self.contains.items.len == 0) {
// We just need our self
std.log.debug("{} just has itself", .{self.type_id});
return count;
}
std.log.debug("{}", .{self.contains.items.len});
for (self.contains.items) |i| {
if (i.*.count == 0) {
continue;
}
var bagtype = get_type_by_id(list, i.*.bag_type).?;
var extra = (i.*.count * bag_type_has_how_many_bags_needed(bagtype, list));
std.log.debug("{} needs {}x {} --> adding {} bags", .{self.*.desc, i.*.count, bagtype.*.desc, extra});
count += extra;
}
return count;
}
fn get_type_by_id(list: *std.ArrayList(*BagType), id: u32) ?*BagType {
for (list.items) |r| {
if (r.*.type_id == id) {
return r;
}
}
return null;
}
// fn types_that_can_contain(allocator: *std.mem.Allocator, list: *std.ArrayList(BagType), id: u32) anyerror![]u32 {
// var search_ids = std.ArrayList(u32).init(allocator);
// defer search_ids.deinit();
// for (list.items) |r| {
// if (r.can_contain(id)) {
// //std.log.debug("{} can contain {}", .{r.type_id, id});
// try search_ids.append(r.type_id);
// }
// }
// var count : usize = search_ids.items.len;
// //std.log.debug("{} bag types can directly contain a {}",
// // .{count, id});
// var types = std.ArrayList(u32).init(allocator);
// for (search_ids.items) |i| {
// var t = try types_that_can_contain(allocator, list, i);
// //std.log.debug("Adding {} to types that can hold {}", .{i, id});
// try types.append(i);
// for (t) |tid| {
// var already_in_types = false;
// for (types.items) |asdf| {
// if (asdf == tid) {
// already_in_types = true;
// break;
// }
// }
// if (!already_in_types) {
// //std.log.debug("Adding {} to types that can hold {}", .{tid, id});
// try types.append(tid);
// }
// }
// }
// return types.items[0..];
// }
const BagRule = struct {
bag_type: u32 = 0,
count: u32 = 0,
};
const BagType = struct {
type_id: u32 = 0,
desc: ?[]u8 = null,
contains: std.ArrayList(*BagRule),
pub fn can_contain(self: *const BagType, type_id: u32) bool {
for (self.contains.items) |rule| {
if (rule.*.bag_type == type_id and rule.*.count > 0) {
return true;
}
}
return false;
}
};

27
day8/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day8", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

634
day8/input Normal file
View File

@ -0,0 +1,634 @@
acc +15
acc +2
acc -14
jmp +362
acc +22
nop +236
jmp +474
acc +10
jmp +1
acc +0
jmp +236
acc +10
acc +14
jmp +334
acc +12
acc -1
jmp +478
jmp +90
jmp +208
acc +49
jmp +94
acc +2
acc -8
jmp +375
nop +21
acc +0
acc +10
nop +25
jmp +492
nop +182
acc +49
acc -12
jmp -14
acc -16
jmp +140
acc -3
acc -18
acc +28
acc -6
jmp +558
acc +2
acc +27
nop +438
acc +41
jmp +508
acc +13
jmp +117
acc +21
acc -13
acc +34
jmp +1
jmp +1
nop +451
acc +28
acc +31
acc +31
jmp +280
acc +32
acc +35
acc -18
jmp +509
acc -15
acc -8
nop +288
acc -16
jmp +376
acc -19
acc -8
acc +11
acc +10
jmp +50
acc +19
nop -58
acc -9
jmp +43
acc +10
acc +2
nop -63
jmp +280
acc -7
jmp +175
jmp +69
acc +16
acc +9
acc -2
acc -5
jmp +276
nop +195
acc +50
acc -8
jmp -55
nop +1
nop -78
acc +31
jmp +535
acc +9
acc +33
acc +4
acc +48
jmp +8
acc +30
acc +42
acc +18
acc +37
jmp -69
nop +121
jmp +44
acc +3
acc +33
acc -6
acc +37
jmp +403
acc -6
jmp +245
jmp -93
acc +5
jmp +406
jmp -26
nop -47
jmp +239
acc +7
acc +31
acc +14
acc +0
jmp +291
acc +46
jmp +394
acc +44
acc +36
nop +45
jmp +137
acc -16
acc +10
acc -4
acc +7
jmp +76
acc +24
jmp +93
acc +17
acc +0
acc +6
acc +4
jmp +385
acc -8
acc +49
acc +28
jmp +95
nop +12
acc +33
jmp +153
nop +254
acc +18
acc -16
acc +50
jmp +299
acc +27
acc +47
acc -17
jmp -15
acc +35
acc +14
jmp +204
jmp +93
acc +46
nop -5
nop -158
jmp +221
jmp +321
acc -2
acc +49
acc +3
acc -17
jmp -52
jmp +7
nop +52
acc +25
jmp +376
acc -3
nop -133
jmp +32
jmp +328
nop +374
acc +37
acc +6
jmp +92
acc +47
nop +394
jmp -13
jmp -170
acc +9
jmp -47
acc -18
acc +27
jmp +1
acc +3
acc -5
jmp +337
acc +21
jmp +364
acc +24
acc +43
acc +50
jmp +58
jmp -18
acc +30
jmp +144
nop +5
acc +50
nop +245
nop +133
jmp +270
jmp -22
nop -76
jmp +398
acc +40
acc +30
jmp +361
acc +36
acc +30
jmp +392
acc -17
nop +71
acc -12
jmp +102
acc +17
jmp +283
acc -16
jmp +65
nop -2
jmp +149
jmp -103
jmp -179
acc +46
jmp +289
acc +48
jmp +114
acc +13
jmp +114
nop +215
nop -89
jmp +337
acc -2
acc +2
acc -7
jmp -18
jmp -51
acc +30
acc +43
acc +28
jmp -188
acc +36
acc +7
acc -5
acc +38
jmp +88
jmp +225
acc -14
acc -3
acc -15
jmp +66
acc +7
acc +43
nop -210
acc -9
jmp +109
acc -10
jmp +242
acc -5
acc +15
acc +8
jmp +310
acc +31
acc -2
acc +11
acc -15
jmp +103
acc +32
jmp -92
acc -10
acc +6
acc -1
jmp -131
acc +43
acc +30
acc +13
acc +33
jmp +25
acc +9
acc -14
acc +19
acc +44
jmp -50
acc -8
acc +9
jmp +312
jmp -96
acc -3
acc -3
acc +24
jmp +94
acc -15
jmp +61
acc +19
nop -89
acc +24
nop -94
jmp +5
acc -13
acc +25
acc +42
jmp +1
jmp +137
acc +44
acc +44
acc +41
jmp +152
jmp +144
acc -1
nop +293
jmp -120
acc -17
nop -171
acc +27
jmp -173
jmp +231
acc +3
jmp +109
acc +18
acc +32
acc -14
acc -8
jmp +177
acc +28
jmp -134
nop +277
jmp -124
jmp +167
nop +274
acc +6
acc +43
acc +10
jmp -320
acc +28
acc -9
acc +22
jmp -90
jmp -203
jmp -133
jmp -6
jmp -181
jmp +170
acc +40
acc +5
jmp -274
acc +36
acc +24
nop +6
jmp -339
jmp -251
acc +10
acc +10
jmp -347
jmp +263
acc +37
jmp -201
acc -11
acc +42
jmp +153
nop -179
acc -9
jmp +8
jmp -289
jmp -25
acc +45
jmp -142
acc +42
acc -10
jmp +83
acc +43
acc +3
acc -6
jmp -222
acc +41
acc +14
acc +7
acc +2
jmp -35
jmp +168
acc +11
acc +18
acc +8
acc -4
jmp -203
acc +44
jmp +10
nop -184
acc +0
jmp +91
acc -5
nop +226
acc +46
acc -10
jmp -15
jmp -321
acc +0
acc +33
jmp +82
jmp +1
acc -12
acc +30
jmp +152
acc +6
jmp -208
acc +43
jmp +39
acc +23
acc +23
acc +24
acc +26
jmp -390
acc +15
acc +3
acc +14
acc +46
jmp -239
acc -10
acc +19
jmp +167
acc +46
acc +0
jmp -280
acc -7
jmp -107
acc +13
jmp -76
acc +48
jmp -65
nop +23
nop -89
acc +47
jmp -304
acc -5
jmp +1
acc +50
acc +37
jmp -129
acc +27
jmp +1
jmp -212
acc +18
acc +29
acc +1
jmp -74
acc +24
acc -12
jmp -173
acc -18
acc -6
nop -156
jmp -309
acc +46
acc -13
acc +41
acc +11
jmp -188
acc +32
jmp -190
acc +31
acc +30
jmp -122
acc -7
jmp +37
acc +2
acc +16
acc +45
acc +44
jmp -376
acc +47
jmp +1
jmp -147
acc +47
acc -18
acc -1
acc +2
jmp -152
acc +12
acc -8
jmp +90
nop +67
acc +9
jmp +1
jmp -377
jmp +1
jmp -238
jmp +1
acc +47
acc +7
acc +31
jmp -427
acc +10
acc +13
nop +13
jmp -8
nop -292
acc +11
nop -203
jmp -164
jmp -19
acc +31
jmp -289
acc -7
acc -16
acc +35
jmp -333
jmp -500
acc +32
acc +29
acc +18
acc +14
jmp -161
jmp -60
jmp +6
acc +4
nop -108
acc +27
jmp +2
jmp -133
acc +2
jmp -103
acc +40
nop -512
acc +48
jmp -196
acc +47
acc +40
nop -346
acc -2
jmp -530
acc +17
nop -31
acc +1
jmp -74
acc -15
acc +4
nop -330
acc +32
jmp -115
acc -3
jmp +1
acc +14
acc +31
jmp -352
jmp -10
acc +18
jmp -322
acc +41
jmp +59
acc -16
nop -359
acc +29
acc +26
jmp -418
acc +10
acc +47
jmp -519
acc -5
nop +40
acc +30
jmp -195
acc +31
acc +3
acc +8
jmp -10
acc -12
acc +21
acc -1
jmp +30
jmp -341
acc -5
jmp -405
acc -13
jmp -170
acc +24
acc -16
acc +20
acc +17
jmp -145
acc +42
acc +33
jmp -395
nop -142
acc +45
acc +15
jmp -399
nop -223
jmp -299
jmp -453
acc -6
nop -498
acc +42
jmp -112
acc +39
acc +46
acc +4
acc +27
jmp -234
jmp +1
acc +45
acc +47
jmp -307
jmp -378
jmp -431
acc +13
acc +29
jmp -282
acc +4
acc -3
acc +37
acc +40
jmp -32
nop -148
acc +38
acc +40
acc +18
jmp -171
nop -546
jmp -490
acc +36
jmp -514
acc +27
acc -10
nop -560
acc +44
jmp +1

222
day8/src/main.zig Normal file
View File

@ -0,0 +1,222 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var program = try Program.init(gpa);
defer program.*.deinit();
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
var s = try Statement.from_string(line);
try program.code.append(s);
}
std.log.debug("Loaded program with {} statements", .{program.code.items.len});
_ = try program.run();
// Part 2
// Exactly one nop should be a jmp or a jmp a noop
var i : usize = 0;
while (i < program.code.items.len) : (i += 1) {
if (program.code.items[i].op == .acc) {
continue;
}
// Mutate
program.code.items[i].op = switch(program.code.items[i].op) {
.acc => Operation.acc,
.jmp => Operation.nop,
.nop => Operation.jmp,
};
// Test
var run_ok = program.run() catch false;
// Undo mutation
program.code.items[i].op = switch(program.code.items[i].op) {
.acc => Operation.acc,
.jmp => Operation.nop,
.nop => Operation.jmp,
};
if (run_ok) {
std.log.info("By changing statement {}, the program exited okay", .{i});
break;
}
}
}
pub const Operation = enum {
nop,
acc,
jmp
};
pub const ParseError = error {
UnknownStatement,
};
pub const Statement = struct {
op: Operation,
arg: i32,
/// Modifies acc and returns the offset for the next operation
pub fn execute(self: *Statement, acc: *i32) i32 {
var delta : i32 = switch (self.op) {
.nop => 1,
.jmp => self.arg,
.acc => 1,
};
if (self.op == .acc) {
acc.* += self.arg;
}
return delta;
}
pub fn from_string(line: []const u8) !Statement {
var arg : i32 = 0;
var op : Operation = undefined;
var it = std.mem.tokenize(line, " ");
if (it.next()) |l| {
if (std.mem.eql(u8, l, "nop")) {
op = Operation.nop;
}
else if (std.mem.eql(u8, l, "acc")) {
op = Operation.acc;
}
else if (std.mem.eql(u8, l, "jmp")) {
op = Operation.jmp;
}
else {
std.log.err("Unknown statement: '{}'", .{l});
return ParseError.UnknownStatement;
}
}
else {
// Error, and operator is required
unreachable;
}
if (it.next()) |l| {
arg = atoi(l);
}
else {
// Error, we need an arg
unreachable;
}
while(it.next()) |l| {
// Error, there shouldn't be anything else on the line
unreachable;
}
return Statement {
.op = op,
.arg = arg,
};
}
};
pub const Program = struct {
code: std.ArrayList(Statement),
allocator: *std.mem.Allocator,
accumulator: i32 = 0,
pub fn init(a: *std.mem.Allocator) !*Program {
const self = try a.create(Program);
errdefer a.destroy(self);
self.* = Program {
.code = std.ArrayList(Statement).init(a),
.allocator = a,
};
return self;
}
pub fn deinit(self: *Program) void {
self.code.deinit();
self.allocator.destroy(self);
}
pub fn run(self: *Program) !bool {
self.accumulator = 0;
var next_statement_index : usize = 0;
// Statement counter
var map = std.hash_map.AutoHashMap(usize, u32).init(self.allocator);
defer map.deinit();
var ended_ok = false;
while (true) {
// Check if we have already exectured this index
var n_accumulator : i32 = self.accumulator;
if (map.contains(next_statement_index)) {
std.log.warn("Infinite loop detected. Statement {} would have run twice",
.{next_statement_index});
std.log.warn("Acc value at break: {}", .{self.accumulator});
break;
}
else {
try map.put(next_statement_index, 1);
}
var delta = self.code.items[next_statement_index].execute(&n_accumulator);
//std.log.debug("Before {}, After {} [statement {} new offset {}] {}",
// .{self.accumulator, n_accumulator, next_statement_index,
// delta, self.code.items[next_statement_index]});
if (delta < 0) {
next_statement_index -= @intCast(usize, try std.math.absInt(delta));
}
else {
next_statement_index += @intCast(usize, delta);
}
std.debug.assert(next_statement_index >= 0);
if (next_statement_index >= self.code.items.len) {
std.log.warn("Reached end of code, or jumping past end ({}, {} statements).",
.{next_statement_index, self.code.items.len});
std.log.warn("Acc value at end: {}", .{self.accumulator});
ended_ok = true; // maybe...
break;
}
self.accumulator = n_accumulator;
}
return ended_ok;
}
};
fn atoi(a: []const u8) i32 {
var i : i32 = 0;
var mul : i32 = 1;
var start : usize = 0;
if (a[0] == '-' or a[0] == '+') {
start = 1;
if (a[0] == '-') {
mul *= -1;
}
}
for(a[start..]) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(i32, @as(i32, (v - 48)) * std.math.pow(i32, 10, @intCast(i32, a.len - k - 1 - start)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i * mul;
}
test "atoi_regular" {
var i = atoi("1234");
std.testing.expectEqual(i, 1234);
}
test "atoi_pos" {
var i = atoi("+1234");
std.testing.expectEqual(i, 1234);
}
test "atoi_neg" {
var i = atoi("-1234");
std.testing.expectEqual(i, -1234);
}

27
day9/build.zig Normal file
View File

@ -0,0 +1,27 @@
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("day9", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

1000
day9/input Normal file

File diff suppressed because it is too large Load Diff

163
day9/src/main.zig Normal file
View File

@ -0,0 +1,163 @@
const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
var gpa = &arena.allocator;
var stream = std.ArrayList(u64).init(gpa);
var f = try std.fs.cwd().openFile("input", .{});
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u32));
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |line| {
//std.log.debug("{}", .{atoi(line)});
try stream.append(atoi(line));
}
var first_not_matching = find_first_with_no_sum_property(stream.items[0..], 25);
std.log.info("First with no sum property: {} (at index {})",
.{stream.items[first_not_matching.?], first_not_matching.?});
// Part 2
// 22406676
var ranges = std.ArrayList(Range).init(gpa);
try find_contiguous_sets_matching(stream.items[0..], 22406676, &ranges);
std.log.debug("Found {} ranges summing to {}", .{ranges.items.len, 22406676});
for (ranges.items) |r| {
std.log.info("Range: {}, len {}. Sum of edge indices: {}",
.{r, r.y - r.x + 1, stream.items[r.x] + stream.items[r.y-1]});
var s : u64 = 0;
var min: u64 = std.math.maxInt(u64);
var max: u64 = 0;
for (stream.items[r.x..r.y]) |v| {
std.log.debug("{}", .{v});
s += v;
min = std.math.min(v, min);
max = std.math.max(v, max);
}
std.log.debug("Sum of items in range: {}, min: {}, max: {}; sum min+max {}",
.{s, min, max, min+max});
}
}
const Range = struct {
x : usize = 0,
y : usize = 0,
};
pub fn find_contiguous_sets_matching(stream: []u64, match: u64, ranges: *std.ArrayList(Range)) !void {
var i : usize = 0;
// start create a window from 0 ... end of list breaking when
// the sum is greater than the match value
// then go on 1 ... end of list
while (i < stream.len) : (i += 1) {
var j : usize = i+1;
while (j < stream.len) : (j += 1) {
std.log.debug("Checking range {}..{}", .{i, j});
var sum : u64 = 0;
for (stream[i..j]) |v| {
sum += v;
}
if (sum > match) {
break;
}
if (sum == match) {
try ranges.append(Range{.x = i, .y = j});
break;
}
}
}
}
/// returns the INDEX of the first non-matching
pub fn find_first_with_no_sum_property(stream: []u64, preamble: u64) ?u64 {
var i : u64 = preamble;
while (i < stream.len) : (i += 1) {
//std.log.debug("Searching for match for {} in indicess {} to {}: {}",
// .{stream[i], i-preamble, i, stream[i-preamble..i]});
if (!has_sum_property(stream[i], stream[i-preamble..i])) {
return i;
}
}
return null;
}
pub fn has_sum_property(value: u64, preceding_values: []u64) bool {
for (preceding_values) |v, k| {
for (preceding_values) |w, k2| {
if (k == k2) {
continue; // don't sum against our selves
}
//std.log.debug("[{}, {}] -> {} + {} => {} (searching for {})",
// .{k, k2, v, w, v+w, value});
if ((v+w) == value) {
return true;
}
}
}
return false;
}
test "first not having a sum of 5 preamble" {
const preamble : u64 = 5;
var stream = [_]u64 {
35,
20,
15,
25,
47,
40,
62,
55,
65,
95,
102,
117,
150,
182,
127,
219,
299,
277,
309,
576,
};
var idx_not_matching = find_first_with_no_sum_property(stream[0..], preamble);
var i = stream[idx_not_matching.?];
std.testing.expectEqual(i, 127);
}
fn atoi(a: []const u8) u64 {
var i : u64 = 0;
var mul : u64 = 1;
var start : usize = 0;
if (a[0] == '-' or a[0] == '+') {
start = 1;
if (a[0] == '-') {
//mul *= -1;
unreachable;
}
}
for(a[start..]) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u64, @as(u64, (v - 48)) * std.math.pow(u64, 10, @intCast(u64, a.len - k - 1 - start)));
}
//std.log.debug("0x{x} --> {}", .{a, i});
return i * mul;
}
test "atoi_regular" {
var i = atoi("1234");
std.testing.expectEqual(i, 1234);
}
test "atoi_pos" {
var i = atoi("+1234");
std.testing.expectEqual(i, 1234);
}