1
0
Advent-of-Code/day13/part1.zig
2024-12-15 10:56:23 +01:00

90 lines
3.2 KiB
Zig

const std = @import("std");
const print = std.debug.print;
const input = @embedFile("input");
const vec2 = @Vector(2, usize);
// So I need to find out ax + by = c
// With x and y the number of time I click on a and b respectivly
// a and b as how much I advance per click
// And c as total
// And I have 2 equation, one for prize position x and one for y
// Which you can easely do, for float, not int =(
// So how do I approach this ?
// 1. Brute force: I can do all combinaison of x and y. For like 200 max click. 320 prize, 200 * 200 * 320 = 12_800_000
// 2. Pretty sure I can do something with a modulo, because the end pos can only be reach by few combinaison
const State = enum {
ReadButtonA,
ReadButtonB,
ReadPrize,
ReadJump,
};
pub fn main() !void {
var iter = std.mem.splitAny(u8, input, "\n");
var state = State.ReadButtonA;
var buttonA: vec2 = undefined;
var buttonB: vec2 = undefined;
var prize: vec2 = undefined;
var total: usize = 0;
while (iter.next()) |line| switch (state) {
.ReadButtonA => {
var iterLine = std.mem.splitAny(u8, line, " ");
_ = iterLine.next(); // Skip Button
_ = iterLine.next(); // Skip A
const buf = iterLine.next().?;
buttonA[0] = try std.fmt.parseInt(usize, buf[2 .. buf.len - 1], 10);
buttonA[1] = try std.fmt.parseInt(usize, iterLine.next().?[2..], 10);
state = .ReadButtonB;
},
.ReadButtonB => {
var iterLine = std.mem.splitAny(u8, line, " ");
_ = iterLine.next(); // Skip Button
_ = iterLine.next(); // Skip B
const buf = iterLine.next().?;
buttonB[0] = try std.fmt.parseInt(usize, buf[2 .. buf.len - 1], 10);
buttonB[1] = try std.fmt.parseInt(usize, iterLine.next().?[2..], 10);
state = .ReadPrize;
},
.ReadPrize => {
var iterLine = std.mem.splitAny(u8, line, " ");
_ = iterLine.next(); // Skip Price
const buf = iterLine.next().?;
prize[0] = try std.fmt.parseInt(usize, buf[2 .. buf.len - 1], 10);
prize[1] = try std.fmt.parseInt(usize, iterLine.next().?[2..], 10);
state = .ReadJump;
},
.ReadJump => {
state = .ReadButtonA;
const result = bruteforce(buttonA, buttonB, prize, vec2{ 0, 100 });
if (result.cost != 99999) total += result.cost;
},
};
try std.testing.expectEqual(33921, total);
}
const Result = struct {
clickA: usize = 0,
clickB: usize = 0,
cost: usize = 999999,
};
fn bruteforce(buttonA: vec2, buttonB: vec2, prize: vec2, range: vec2) Result {
var minA: usize = 99999;
var minB: usize = 99999;
var min_cost: usize = 99999;
for (range[0]..range[1]) |clickA| for (range[0]..range[1]) |clickB| {
const end_pos = buttonA * @as(vec2, @splat(clickA)) + buttonB * @as(vec2, @splat(clickB));
if (!@reduce(.And, end_pos == prize)) continue;
const cost = clickA * 3 + clickB;
if (cost < min_cost) {
minA = clickA;
minB = clickB;
min_cost = cost;
}
};
return Result{ .clickA = minA, .clickB = minB, .cost = min_cost };
}