2024 Day 17 Part 1
This commit is contained in:
parent
c1021ae897
commit
0d3f4b7a93
1 changed files with 254 additions and 0 deletions
254
2024/src/day17.zig
Normal file
254
2024/src/day17.zig
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
const std = @import("std");
|
||||
const aoc = @import("aoc.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const List = std.ArrayList;
|
||||
const Map = std.AutoHashMap;
|
||||
const Set = aoc.AutoHashSet;
|
||||
const PriorityQueue = std.PriorityQueue;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
const text = try aoc.readAll(allocator, "input/day17.txt");
|
||||
defer allocator.free(text);
|
||||
|
||||
var device = try Device.parse(allocator, text);
|
||||
defer device.deinit();
|
||||
|
||||
var output = try device.run();
|
||||
defer output.deinit();
|
||||
|
||||
var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
|
||||
const stdout = bw.writer();
|
||||
|
||||
const out = try joinOutput(allocator, output.items);
|
||||
defer out.deinit();
|
||||
|
||||
try stdout.print("{s}\n", .{out.items});
|
||||
try bw.flush();
|
||||
}
|
||||
|
||||
fn joinOutput(allocator: Allocator, nums: []u64) !List(u8) {
|
||||
var buf = List(u8).init(allocator);
|
||||
var w = buf.writer();
|
||||
|
||||
if (nums.len > 0) {
|
||||
try w.print("{d}", .{nums[0]});
|
||||
}
|
||||
|
||||
if (nums.len > 1) {
|
||||
for (nums[1..]) |n| {
|
||||
try w.print(",{d}", .{n});
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const Device = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
|
||||
program: List(u3),
|
||||
ip: usize,
|
||||
|
||||
allocator: Allocator,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
fn parse(allocator: Allocator, text: []const u8) !Self {
|
||||
var blocks = std.mem.splitSequence(u8, text, "\n\n");
|
||||
const a, const b, const c = v: {
|
||||
const block = blocks.next().?;
|
||||
var lines = std.mem.tokenizeScalar(u8, block, '\n');
|
||||
|
||||
var line = lines.next().?;
|
||||
line = takeLiteral(line, "Register A: ").?;
|
||||
line, const a = takeInt(line).?;
|
||||
if (line.len != 0) unreachable;
|
||||
|
||||
line = lines.next().?;
|
||||
line = takeLiteral(line, "Register B: ").?;
|
||||
line, const b = takeInt(line).?;
|
||||
if (line.len != 0) unreachable;
|
||||
|
||||
line = lines.next().?;
|
||||
line = takeLiteral(line, "Register C: ").?;
|
||||
line, const c = takeInt(line).?;
|
||||
if (line.len != 0) unreachable;
|
||||
|
||||
break :v .{ a, b, c };
|
||||
};
|
||||
|
||||
var program = List(u3).init(allocator);
|
||||
errdefer program.deinit();
|
||||
{
|
||||
var line = blocks.next().?;
|
||||
|
||||
line = std.mem.trim(u8, line, " \n");
|
||||
line = takeLiteral(line, "Program: ").?;
|
||||
|
||||
var nums = std.mem.tokenizeScalar(u8, line, ',');
|
||||
while (nums.next()) |num| {
|
||||
const n = try std.fmt.parseInt(u3, num, 10);
|
||||
try program.append(n);
|
||||
}
|
||||
}
|
||||
|
||||
return Self{
|
||||
.a = a,
|
||||
.b = b,
|
||||
.c = c,
|
||||
|
||||
.ip = 0,
|
||||
.program = program,
|
||||
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: *Self) void {
|
||||
self.program.deinit();
|
||||
}
|
||||
|
||||
fn run(self: *Self) !List(u64) {
|
||||
var output = List(u64).init(self.allocator);
|
||||
while (self.ip < self.program.items.len) {
|
||||
// self.dbg();
|
||||
self.ip, const out = self.tick();
|
||||
|
||||
if (out) |n| {
|
||||
try output.append(n);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
fn dbg(self: Self) void {
|
||||
std.debug.print("ip: {}\nA: {}\nB: {}\nC: {}\n", .{ self.ip, self.a, self.b, self.c });
|
||||
std.debug.print("op: {} {}\n", .{
|
||||
self.program.items[self.ip],
|
||||
self.program.items[self.ip + 1],
|
||||
});
|
||||
const stdin = std.io.getStdIn();
|
||||
var buf: [1]u8 = undefined;
|
||||
_ = stdin.reader().readUntilDelimiterOrEof(&buf, '\n') catch return orelse return;
|
||||
}
|
||||
|
||||
fn tick(self: *Self) struct { usize, ?u64 } {
|
||||
const opcode: Opcode = @enumFromInt(self.program.items[self.ip]);
|
||||
const operand = self.program.items[self.ip + 1];
|
||||
|
||||
const pow = std.math.pow;
|
||||
|
||||
switch (opcode) {
|
||||
.adv => {
|
||||
const num = self.a;
|
||||
const denom = pow(u64, 2, self.combo(operand));
|
||||
self.a = @divTrunc(num, denom);
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
.bxl => {
|
||||
self.b = self.b ^ operand;
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
.bst => {
|
||||
const n = self.combo(operand);
|
||||
self.b = n % 8;
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
.jnz => {
|
||||
if (self.a == 0) {
|
||||
return .{ self.ip + 2, null };
|
||||
} else {
|
||||
return .{ operand, null };
|
||||
}
|
||||
},
|
||||
.bxc => {
|
||||
self.b = self.b ^ self.c;
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
.out => {
|
||||
const n = self.combo(operand);
|
||||
const out = n % 8;
|
||||
|
||||
return .{ self.ip + 2, out };
|
||||
},
|
||||
.bdv => {
|
||||
const num = self.a;
|
||||
const denom = pow(u64, 2, self.combo(operand));
|
||||
self.b = @divTrunc(num, denom);
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
.cdv => {
|
||||
const num = self.a;
|
||||
const denom = pow(u64, 2, self.combo(operand));
|
||||
self.c = @divTrunc(num, denom);
|
||||
|
||||
return .{ self.ip + 2, null };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn combo(self: *Self, operand: u3) u64 {
|
||||
return switch (operand) {
|
||||
0 => 0,
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
3 => 3,
|
||||
4 => self.a,
|
||||
5 => self.b,
|
||||
6 => self.c,
|
||||
7 => unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const Instruction = struct {
|
||||
opcode: u3,
|
||||
operand: u3,
|
||||
};
|
||||
|
||||
const Opcode = enum(u3) {
|
||||
adv = 0,
|
||||
bxl = 1,
|
||||
bst = 2,
|
||||
jnz = 3,
|
||||
bxc = 4,
|
||||
out = 5,
|
||||
bdv = 6,
|
||||
cdv = 7,
|
||||
};
|
||||
|
||||
fn takeLiteral(input: []const u8, want: []const u8) ?[]const u8 {
|
||||
if (std.mem.startsWith(u8, input, want)) {
|
||||
return input[want.len..];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn takeInt(input: []const u8) ?struct { []const u8, u64 } {
|
||||
var i: usize = 0;
|
||||
var n: u64 = 0;
|
||||
|
||||
while (i < input.len and std.ascii.isDigit(input[i])) : (i += 1) {
|
||||
n *= 10;
|
||||
n += input[i] - '0';
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
// Nothing consumed
|
||||
return null;
|
||||
}
|
||||
|
||||
return .{ input[i..], n };
|
||||
}
|
||||
Loading…
Reference in a new issue