const std = @import("std");
const PATH = "input/day10.txt";
pub fn first(allocator: std.mem.Allocator) !isize {
_ = allocator;
var cycle: isize = 1;
var x: isize = 1;
var sum: isize = 0;
var lines = std.mem.tokenize(u8, @embedFile(PATH), "\n");
while (lines.next()) |line| : ({
cycle += 1;
sum += checkCycle(cycle, x);
}) {
switch (line[0]) {
'n' => {},
'a' => {
cycle += 1;
sum += checkCycle(cycle, x);
x += try std.fmt.parseInt(isize, line[5..], 10);
},
else => unreachable,
}
if (cycle >= 220) break;
}
return sum;
}
pub fn second(allocator: std.mem.Allocator) !Screen {
_ = allocator;
var s: Screen = undefined;
s.pixels = [_][COLS]State{[_]State{.off} ** COLS} ** ROWS;
var cycle: isize = 1;
var x: isize = 1;
var lines = std.mem.tokenize(u8, @embedFile(PATH), "\n");
while (lines.next()) |line| : (cycle += 1) {
std.debug.assert(cycle <= COLS * ROWS);
s.checkSprite(cycle, x);
switch (line[0]) {
'n' => {},
'a' => {
cycle += 1;
s.checkSprite(cycle, x);
x += try std.fmt.parseInt(isize, line[5..], 10);
},
else => unreachable,
}
}
return s;
}
test "day10a" {
try std.testing.expectEqual(@as(isize, 13680), try first(std.testing.allocator));
}
test "day10b" {
const expected =
\\###..####..##..###..#..#.###..####.###..
\\#..#....#.#..#.#..#.#.#..#..#.#....#..#.
\\#..#...#..#....#..#.##...#..#.###..###..
\\###...#...#.##.###..#.#..###..#....#..#.
\\#....#....#..#.#....#.#..#....#....#..#.
\\#....####..###.#....#..#.#....####.###..
;
const got = try second(std.testing.allocator);
for (got.pixels) |line, row| {
for (line) |ch, col| {
switch (ch) {
// add row*1 to skip '\n' at line ends
.on => if (expected[row * COLS + col + row * 1] != '#') return error.BAD,
.off => if (expected[row * COLS + col + row * 1] != '.') return error.BAD,
}
}
}
}
fn checkCycle(cycle: isize, x: isize) isize {
switch (cycle) {
20, 60, 100, 140, 180, 220 => {
return x * cycle;
},
else => return 0,
}
}
const ROWS = 6;
const COLS = 40;
const State = enum {
on,
off,
};
const Screen = struct {
pixels: [ROWS][COLS]State,
fn show(self: @This()) void {
std.debug.print("\n", .{});
for (self.pixels) |line| {
for (line) |ch| {
switch (ch) {
.on => std.debug.print("#", .{}),
.off => std.debug.print(".", .{}),
}
}
std.debug.print("\n", .{});
}
}
fn checkSprite(self: *@This(), cycle: isize, sprite: isize) void {
const pos = @intCast(usize, cycle - 1);
if (pos % COLS == sprite - 1 or pos % COLS == sprite or pos % COLS == sprite + 1) {
self.pixels[pos / COLS][pos % COLS] = .on;
}
}
};
const test_input =
\\addx 15
\\addx -11
\\addx 6
\\addx -3
\\addx 5
\\addx -1
\\addx -8
\\addx 13
\\addx 4
\\noop
\\addx -1
\\addx 5
\\addx -1
\\addx 5
\\addx -1
\\addx 5
\\addx -1
\\addx 5
\\addx -1
\\addx -35
\\addx 1
\\addx 24
\\addx -19
\\addx 1
\\addx 16
\\addx -11
\\noop
\\noop
\\addx 21
\\addx -15
\\noop
\\noop
\\addx -3
\\addx 9
\\addx 1
\\addx -3
\\addx 8
\\addx 1
\\addx 5
\\noop
\\noop
\\noop
\\noop
\\noop
\\addx -36
\\noop
\\addx 1
\\addx 7
\\noop
\\noop
\\noop
\\addx 2
\\addx 6
\\noop
\\noop
\\noop
\\noop
\\noop
\\addx 1
\\noop
\\noop
\\addx 7
\\addx 1
\\noop
\\addx -13
\\addx 13
\\addx 7
\\noop
\\addx 1
\\addx -33
\\noop
\\noop
\\noop
\\addx 2
\\noop
\\noop
\\noop
\\addx 8
\\noop
\\addx -1
\\addx 2
\\addx 1
\\noop
\\addx 17
\\addx -9
\\addx 1
\\addx 1
\\addx -3
\\addx 11
\\noop
\\noop
\\addx 1
\\noop
\\addx 1
\\noop
\\noop
\\addx -13
\\addx -19
\\addx 1
\\addx 3
\\addx 26
\\addx -30
\\addx 12
\\addx -1
\\addx 3
\\addx 1
\\noop
\\noop
\\noop
\\addx -9
\\addx 18
\\addx 1
\\addx 2
\\noop
\\noop
\\addx 9
\\noop
\\noop
\\noop
\\addx -1
\\addx 2
\\addx -37
\\addx 1
\\addx 3
\\noop
\\addx 15
\\addx -21
\\addx 22
\\addx -6
\\addx 1
\\noop
\\addx 2
\\addx 1
\\noop
\\addx -10
\\noop
\\noop
\\addx 20
\\addx 1
\\addx 2
\\addx 2
\\addx -6
\\addx -11
\\noop
\\noop
\\noop
;