1
0

Added shitty day 13

This commit is contained in:
Adrien Bouvais 2024-12-15 10:56:23 +01:00
parent 3cd677bbaf
commit 26a517c7a3
4 changed files with 1507 additions and 0 deletions

View File

@ -24,6 +24,7 @@ const d111 = @import("day11/part1.zig");
const d112 = @import("day11/part2.zig");
const d121 = @import("day12/part1.zig");
const d122 = @import("day12/part2.zig");
const d131 = @import("day13/part1.zig");
const NUMBER_OF_RUN = 50;
@ -72,6 +73,9 @@ pub fn main() !void {
try benchmark(d121.main, 12, 1);
try benchmark(d122.main, 12, 2);
separator();
try benchmark(d131.main, 13, 1);
print("| 13 | 2 | Too long ~6h | 0 | 0 |\n", .{});
separator();
print("| Total | {d: >8} ± {d: <6.2} | {d:>8} | {d:>8} |\n", .{ total_mean, total_std_dev, total_min, total_max });
separator();
}

1279
day13/input Normal file

File diff suppressed because it is too large Load Diff

89
day13/part1.zig Normal file
View File

@ -0,0 +1,89 @@
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 };
}

135
day13/part2.zig Normal file
View File

@ -0,0 +1,135 @@
const std = @import("std");
const print = std.debug.print;
const input = @embedFile("input");
const Usize = std.atomic.Value(usize);
const vec2 = @Vector(2, usize);
// I am not proud of this solution, it take like 6h to run on 16 thread :/
// I am sure I can change the bruteForce function to use modulo to reduce the number of clickA
// But it was late, I was tired so I juste started this version and the next morning it was complete soooo
// I will no go futher, I am already 2 days behind :/
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.init(0);
var finished = Usize.init(0);
var to_wait: usize = 0;
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var thread_arena = std.heap.ThreadSafeAllocator{
.child_allocator = allocator,
};
var thread_pool: std.Thread.Pool = undefined;
thread_pool.init(std.Thread.Pool.Options{
.allocator = thread_arena.allocator(),
.n_jobs = 16,
}) catch @panic("=(");
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) + 10000000000000;
prize[1] = try std.fmt.parseInt(usize, iterLine.next().?[2..], 10) + 10000000000000;
state = .ReadJump;
},
.ReadJump => {
state = .ReadButtonA;
try thread_pool.spawn(bruteforce, .{ buttonA, buttonB, prize, &total, &finished, to_wait });
to_wait += 1;
},
};
while (to_wait > finished.load(.monotonic)) {
std.time.sleep(1000000);
printProgressOverall(finished.load(.monotonic), to_wait);
}
print("Total: {d}\n", .{total.load(.monotonic)});
}
const Result = struct {
clickA: usize = 0,
clickB: usize = 0,
cost: usize = 999999,
};
fn bruteforce(buttonA: vec2, buttonB: vec2, prize: vec2, total: *Usize, finished: *Usize, id: usize) void {
var min_cost: usize = std.math.maxInt(usize);
const max_clickA = @min(@divFloor(prize[0], buttonA[0]), @divFloor(prize[1], buttonA[1])) + 10;
var clickA: usize = 0;
while (clickA <= max_clickA) : (clickA += 1) {
if (clickA % 1000000000 == 0) printProgress(clickA, max_clickA, id);
const remaining = prize - buttonA * @as(vec2, @splat(clickA));
if (@reduce(.Or, remaining < @as(vec2, @splat(0)))) continue;
const clickB = @divFloor(remaining, buttonB);
if (clickB[0] != clickB[1]) continue;
if (@reduce(.Or, remaining % buttonB != @as(vec2, @splat(0)))) continue;
const cost = clickA * 3 + clickB[0];
if (cost < min_cost) min_cost = cost;
}
if (min_cost != std.math.maxInt(usize)) {
_ = total.fetchAdd(min_cost, .monotonic);
}
_ = finished.fetchAdd(1, .monotonic);
}
fn printProgress(value: usize, max: usize, id: usize) void {
print("Thread {d}: {d}% | {d}/{d}\n", .{ id, @divFloor(value * 100, max), value, max });
}
fn printProgressOverall(finished: usize, total: usize) void {
std.debug.print("Overall: {d}/{d} ({d}%) \r", .{ finished, total, @divFloor(finished * 100, total) });
}
fn gcd(a: u64, b: u64) u64 {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
fn isPossible(a: u64, b: u64, c: u64) bool {
return c % gcd(a, b) == 0;
}