update function naming style to match zig
This commit is contained in:
parent
976a41461b
commit
b59bb9c200
@ -11,7 +11,7 @@ day: u32,
|
||||
part: u32,
|
||||
input_file: []u8,
|
||||
|
||||
fn print_usage(program: []const u8) void {
|
||||
fn printUsage(program: []const u8) void {
|
||||
std.debug.print("Usage: {s} <day> <part> [input.txt] Run solution\n", .{program});
|
||||
std.debug.print(" {s} get-input <day> [input.txt] Get input. AOC_SESSSION environment variable needs to be defined\n", .{program});
|
||||
}
|
||||
@ -72,7 +72,7 @@ pub fn init(allocator: Allocator) !Self {
|
||||
|
||||
|
||||
if (i < 2) {
|
||||
print_usage(program);
|
||||
printUsage(program);
|
||||
return error.cli;
|
||||
}
|
||||
|
||||
|
@ -45,11 +45,11 @@ const Tile = union(TileType) {
|
||||
Start: void,
|
||||
Pipe: Pipe,
|
||||
|
||||
fn to_char(self: Tile) u8 {
|
||||
fn toChar(self: Tile) u8 {
|
||||
return switch (self) {
|
||||
.Start => 'S',
|
||||
.Ground => '.',
|
||||
.Pipe => |dirs| find_pipe_symbol(dirs[0], dirs[1]) orelse unreachable,
|
||||
.Pipe => |dirs| findPipeSymbol(dirs[0], dirs[1]) orelse unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -67,7 +67,7 @@ const Grid = struct {
|
||||
fn print(self: *Grid) void {
|
||||
for (0..self.height) |y| {
|
||||
for (0..self.width) |x| {
|
||||
const char = self.get(@intCast(x), @intCast(y)).to_char();
|
||||
const char = self.get(@intCast(x), @intCast(y)).toChar();
|
||||
const symbol = switch(char) {
|
||||
'.' => " ",
|
||||
'S' => "S",
|
||||
@ -85,28 +85,28 @@ const Grid = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_idx(self: *const Grid, x: u32, y: u32) usize {
|
||||
fn getIndex(self: *const Grid, x: u32, y: u32) usize {
|
||||
return y * self.width + x;
|
||||
}
|
||||
|
||||
fn get(self: *const Grid, x: u32, y: u32) Tile {
|
||||
return self.tiles[self.get_idx(x, y)];
|
||||
return self.tiles[self.getIndex(x, y)];
|
||||
}
|
||||
|
||||
fn set(self: *Grid, x: u32, y: u32, tile: Tile) void {
|
||||
self.tiles[self.get_idx(x, y)] = tile;
|
||||
self.tiles[self.getIndex(x, y)] = tile;
|
||||
}
|
||||
|
||||
fn in_bounds(self: *const Grid, x: i32, y: i32) bool {
|
||||
fn inBounds(self: *const Grid, x: i32, y: i32) bool {
|
||||
return x >= 0 and y >= 0 and x < self.width and y < self.height;
|
||||
}
|
||||
};
|
||||
|
||||
fn does_pipe_have_direction(pipe: Pipe, dir: Direction) bool {
|
||||
fn doesPipeHaveDirection(pipe: Pipe, dir: Direction) bool {
|
||||
return pipe[0] == dir or pipe[1] == dir;
|
||||
}
|
||||
|
||||
fn find_pipe_variant(dir1: Direction, dir2: Direction) ?Pipe {
|
||||
fn findPipeVariant(dir1: Direction, dir2: Direction) ?Pipe {
|
||||
inline for (pipe_variants) |pipe_variant| {
|
||||
const variant_dir1 = pipe_variant[1][0];
|
||||
const variant_dir2 = pipe_variant[1][1];
|
||||
@ -117,7 +117,7 @@ fn find_pipe_variant(dir1: Direction, dir2: Direction) ?Pipe {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn find_pipe_symbol(dir1: Direction, dir2: Direction) ?u8 {
|
||||
fn findPipeSymbol(dir1: Direction, dir2: Direction) ?u8 {
|
||||
inline for (pipe_variants) |pipe_variant| {
|
||||
const variant_dir1 = pipe_variant[1][0];
|
||||
const variant_dir2 = pipe_variant[1][1];
|
||||
@ -128,7 +128,7 @@ fn find_pipe_symbol(dir1: Direction, dir2: Direction) ?u8 {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn parse_tile(char: u8) !Tile {
|
||||
fn parseTile(char: u8) !Tile {
|
||||
const void_value = @as(void, undefined);
|
||||
|
||||
if (char == 'S') {
|
||||
@ -146,7 +146,7 @@ fn parse_tile(char: u8) !Tile {
|
||||
return error.UnknownTile;
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Grid {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Grid {
|
||||
const height: u32 = @intCast(lines.len);
|
||||
const width: u32 = @intCast(lines[0].len);
|
||||
|
||||
@ -156,7 +156,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Grid {
|
||||
for (0.., lines) |y, line| {
|
||||
for (0.., line) |x, char| {
|
||||
const idx = y * width + x;
|
||||
tiles[idx] = try parse_tile(char);
|
||||
tiles[idx] = try parseTile(char);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Grid {
|
||||
};
|
||||
}
|
||||
|
||||
fn find_starting_position(grid: *const Grid) ?Point {
|
||||
fn findStartingPosition(grid: *const Grid) ?Point {
|
||||
for (0..grid.height) |y| {
|
||||
for (0..grid.width) |x| {
|
||||
const tile = grid.get(@intCast(x), @intCast(y));
|
||||
@ -180,7 +180,7 @@ fn find_starting_position(grid: *const Grid) ?Point {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_neighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point, 4) {
|
||||
fn getNeighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point, 4) {
|
||||
const offsets = .{
|
||||
.{ 0, -1 },
|
||||
.{ 0, 1 },
|
||||
@ -195,17 +195,17 @@ fn get_neighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point, 4)
|
||||
|
||||
const nx: i32 = @intCast(@as(i32, @intCast(x)) + ox );
|
||||
const ny: i32 = @intCast(@as(i32, @intCast(y)) + oy );
|
||||
if (grid.in_bounds(nx, ny)) {
|
||||
if (grid.inBounds(nx, ny)) {
|
||||
neighbours.append(Point{ .x = @intCast(nx), .y = @intCast(ny) }) catch unreachable;
|
||||
}
|
||||
}
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
fn get_pipe_neighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point, 4) {
|
||||
fn getPipeNeighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point, 4) {
|
||||
var pipe_neighbours = std.BoundedArray(Point, 4).init(0) catch unreachable;
|
||||
|
||||
const neighbours = get_neighbours(grid, x, y);
|
||||
const neighbours = getNeighbours(grid, x, y);
|
||||
const current_tile = grid.get(x, y);
|
||||
assert(@as(TileType, current_tile) == TileType.Pipe);
|
||||
const current_pipe = current_tile.Pipe;
|
||||
@ -227,10 +227,10 @@ fn get_pipe_neighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point
|
||||
unreachable;
|
||||
}
|
||||
|
||||
if (!does_pipe_have_direction(current_pipe, direction)) continue;
|
||||
if (!doesPipeHaveDirection(current_pipe, direction)) continue;
|
||||
|
||||
const opposite_direction = direction.opposite();
|
||||
if (does_pipe_have_direction(tile.Pipe, opposite_direction)) {
|
||||
if (doesPipeHaveDirection(tile.Pipe, opposite_direction)) {
|
||||
pipe_neighbours.append(neighbour) catch unreachable;
|
||||
}
|
||||
}
|
||||
@ -238,7 +238,7 @@ fn get_pipe_neighbours(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Point
|
||||
return pipe_neighbours;
|
||||
}
|
||||
|
||||
fn get_connections(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Direction, 4) {
|
||||
fn getConnections(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Direction, 4) {
|
||||
const directions = .{
|
||||
.{ Direction.Up , 0, -1 },
|
||||
.{ Direction.Down , 0, 1 },
|
||||
@ -255,9 +255,9 @@ fn get_connections(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Direction
|
||||
|
||||
const nx: i32 = @intCast(@as(i32, @intCast(x)) + ox );
|
||||
const ny: i32 = @intCast(@as(i32, @intCast(y)) + oy );
|
||||
if (grid.in_bounds(nx, ny)) {
|
||||
if (grid.inBounds(nx, ny)) {
|
||||
const tile = grid.get(@intCast(nx), @intCast(ny));
|
||||
if (@as(TileType, tile) == TileType.Pipe and does_pipe_have_direction(tile.Pipe, opposite_direction)) {
|
||||
if (@as(TileType, tile) == TileType.Pipe and doesPipeHaveDirection(tile.Pipe, opposite_direction)) {
|
||||
connections.append(direction) catch unreachable;
|
||||
}
|
||||
}
|
||||
@ -265,8 +265,8 @@ fn get_connections(grid: *const Grid, x: u32, y: u32) std.BoundedArray(Direction
|
||||
return connections;
|
||||
}
|
||||
|
||||
fn get_next_pipe(grid: *const Grid, x: u32, y: u32, current_path: []Point) ?Point {
|
||||
var next_pipes = get_pipe_neighbours(grid, x, y);
|
||||
fn getNextPipe(grid: *const Grid, x: u32, y: u32, current_path: []Point) ?Point {
|
||||
var next_pipes = getPipeNeighbours(grid, x, y);
|
||||
for (next_pipes.slice()) |point| {
|
||||
if (current_path.len > 1) {
|
||||
const first_path_point = current_path[0];
|
||||
@ -280,7 +280,7 @@ fn get_next_pipe(grid: *const Grid, x: u32, y: u32, current_path: []Point) ?Poin
|
||||
return null;
|
||||
}
|
||||
|
||||
fn find_loop(allocator: Allocator, grid: *const Grid, start: Point) !std.ArrayList(Point) {
|
||||
fn findLoop(allocator: Allocator, grid: *const Grid, start: Point) !std.ArrayList(Point) {
|
||||
var loop_path = std.ArrayList(Point).init(allocator);
|
||||
errdefer loop_path.deinit();
|
||||
|
||||
@ -288,7 +288,7 @@ fn find_loop(allocator: Allocator, grid: *const Grid, start: Point) !std.ArrayLi
|
||||
|
||||
var current_point = start;
|
||||
while (true) {
|
||||
const next_point = get_next_pipe(grid, current_point.x, current_point.y, loop_path.items);
|
||||
const next_point = getNextPipe(grid, current_point.x, current_point.y, loop_path.items);
|
||||
if (next_point == null) break;
|
||||
|
||||
current_point = next_point.?;
|
||||
@ -300,17 +300,17 @@ fn find_loop(allocator: Allocator, grid: *const Grid, start: Point) !std.ArrayLi
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var grid = try parse_input(allocator, input.lines);
|
||||
var grid = try parseInput(allocator, input.lines);
|
||||
defer grid.deinit();
|
||||
|
||||
const start = find_starting_position(&grid) orelse return error.StartNotFound;
|
||||
const start_connections = get_connections(&grid, start.x, start.y);
|
||||
const start = findStartingPosition(&grid) orelse return error.StartNotFound;
|
||||
const start_connections = getConnections(&grid, start.x, start.y);
|
||||
assert(start_connections.len == 2);
|
||||
const pipe_on_start = find_pipe_variant(start_connections.buffer[0], start_connections.buffer[1]) orelse unreachable;
|
||||
const pipe_on_start = findPipeVariant(start_connections.buffer[0], start_connections.buffer[1]) orelse unreachable;
|
||||
|
||||
grid.set(start.x, start.y, Tile{ .Pipe = pipe_on_start });
|
||||
|
||||
var loop_path = try find_loop(allocator, &grid, start);
|
||||
var loop_path = try findLoop(allocator, &grid, start);
|
||||
defer loop_path.deinit();
|
||||
|
||||
const loop_length = loop_path.items.len;
|
||||
@ -320,17 +320,17 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var grid = try parse_input(allocator, input.lines);
|
||||
var grid = try parseInput(allocator, input.lines);
|
||||
defer grid.deinit();
|
||||
|
||||
const start = find_starting_position(&grid) orelse return error.StartNotFound;
|
||||
const start_connections = get_connections(&grid, start.x, start.y);
|
||||
const start = findStartingPosition(&grid) orelse return error.StartNotFound;
|
||||
const start_connections = getConnections(&grid, start.x, start.y);
|
||||
assert(start_connections.len == 2);
|
||||
const pipe_on_start = find_pipe_variant(start_connections.buffer[0], start_connections.buffer[1]) orelse unreachable;
|
||||
const pipe_on_start = findPipeVariant(start_connections.buffer[0], start_connections.buffer[1]) orelse unreachable;
|
||||
|
||||
grid.set(start.x, start.y, Tile{ .Pipe = pipe_on_start });
|
||||
|
||||
var loop_path = try find_loop(allocator, &grid, start);
|
||||
var loop_path = try findLoop(allocator, &grid, start);
|
||||
defer loop_path.deinit();
|
||||
|
||||
try loop_path.append(loop_path.items[0]);
|
||||
|
@ -8,14 +8,14 @@ const Tile = enum {
|
||||
Empty,
|
||||
Galaxy,
|
||||
|
||||
fn to_char(self: Tile) u8 {
|
||||
fn toChar(self: Tile) u8 {
|
||||
return switch (self) {
|
||||
.Empty => '.',
|
||||
.Galaxy => '#',
|
||||
};
|
||||
}
|
||||
|
||||
fn from_char(char: u8) ?Tile {
|
||||
fn fromChar(char: u8) ?Tile {
|
||||
return switch (char) {
|
||||
'.' => .Empty,
|
||||
'#' => .Galaxy,
|
||||
@ -38,14 +38,14 @@ const GalaxyMap = struct {
|
||||
for (0..self.height) |y| {
|
||||
for (0..self.width) |x| {
|
||||
const idx = y * self.width + x;
|
||||
std.debug.print("{c}", .{self.tiles[idx].to_char()});
|
||||
std.debug.print("{c}", .{self.tiles[idx].toChar()});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !GalaxyMap {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !GalaxyMap {
|
||||
const height: u32 = @intCast(lines.len);
|
||||
const width: u32 = @intCast(lines[0].len);
|
||||
var tile_map = try allocator.alloc(Tile, width * height);
|
||||
@ -54,7 +54,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !GalaxyMap {
|
||||
for (0.., lines) |y, line| {
|
||||
for (0.., line) |x, char| {
|
||||
const idx = width * y + x;
|
||||
tile_map[idx] = Tile.from_char(char) orelse .Empty;
|
||||
tile_map[idx] = Tile.fromChar(char) orelse .Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !GalaxyMap {
|
||||
};
|
||||
}
|
||||
|
||||
fn list_galaxies(allocator: Allocator, map: GalaxyMap) !ArrayList(Point) {
|
||||
fn listGalaxies(allocator: Allocator, map: GalaxyMap) !ArrayList(Point) {
|
||||
var points = ArrayList(Point).init(allocator);
|
||||
errdefer points.deinit();
|
||||
|
||||
@ -85,7 +85,7 @@ fn list_galaxies(allocator: Allocator, map: GalaxyMap) !ArrayList(Point) {
|
||||
return points;
|
||||
}
|
||||
|
||||
fn is_row_empty(map: GalaxyMap, y: u32) bool {
|
||||
fn isRowEmpty(map: GalaxyMap, y: u32) bool {
|
||||
for (0..map.width) |x| {
|
||||
const idx = map.width * y + x;
|
||||
if (map.tiles[idx] != .Empty) return false;
|
||||
@ -93,7 +93,7 @@ fn is_row_empty(map: GalaxyMap, y: u32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn is_column_empty(map: GalaxyMap, x: u32) bool {
|
||||
fn isColumnEmpty(map: GalaxyMap, x: u32) bool {
|
||||
for (0..map.height) |y| {
|
||||
const idx = map.width * y + x;
|
||||
if (map.tiles[idx] != .Empty) return false;
|
||||
@ -101,12 +101,12 @@ fn is_column_empty(map: GalaxyMap, x: u32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn list_empty_rows(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
fn listEmptyRows(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
var rows = ArrayList(u32).init(allocator);
|
||||
errdefer rows.deinit();
|
||||
|
||||
for (0..map.height) |y| {
|
||||
if (is_row_empty(map, @intCast(y))) {
|
||||
if (isRowEmpty(map, @intCast(y))) {
|
||||
try rows.append(@intCast(y));
|
||||
}
|
||||
}
|
||||
@ -114,12 +114,12 @@ fn list_empty_rows(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
fn list_empty_columns(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
fn listEmptyColumns(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
var columns = ArrayList(u32).init(allocator);
|
||||
errdefer columns.deinit();
|
||||
|
||||
for (0..map.width) |x| {
|
||||
if (is_column_empty(map, @intCast(x))) {
|
||||
if (isColumnEmpty(map, @intCast(x))) {
|
||||
try columns.append(@intCast(x));
|
||||
}
|
||||
}
|
||||
@ -127,11 +127,11 @@ fn list_empty_columns(allocator: Allocator, map: GalaxyMap) !ArrayList(u32) {
|
||||
return columns;
|
||||
}
|
||||
|
||||
fn expand_points(allocator: Allocator, points: []Point, map: GalaxyMap, amount: u32) !void {
|
||||
const empty_rows = try list_empty_rows(allocator, map);
|
||||
fn expandPoints(allocator: Allocator, points: []Point, map: GalaxyMap, amount: u32) !void {
|
||||
const empty_rows = try listEmptyRows(allocator, map);
|
||||
defer empty_rows.deinit();
|
||||
|
||||
const empty_columns = try list_empty_columns(allocator, map);
|
||||
const empty_columns = try listEmptyColumns(allocator, map);
|
||||
defer empty_columns.deinit();
|
||||
|
||||
for (points) |*p| {
|
||||
@ -155,7 +155,7 @@ fn expand_points(allocator: Allocator, points: []Point, map: GalaxyMap, amount:
|
||||
}
|
||||
}
|
||||
|
||||
fn sum_min_distances(points: []Point) u64 {
|
||||
fn sumMinDistances(points: []Point) u64 {
|
||||
var result: u64 = 0;
|
||||
for (0..(points.len-1)) |i| {
|
||||
const p1 = points[i];
|
||||
@ -171,28 +171,28 @@ fn sum_min_distances(points: []Point) u64 {
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var galaxies = try list_galaxies(allocator, parsed);
|
||||
var galaxies = try listGalaxies(allocator, parsed);
|
||||
defer galaxies.deinit();
|
||||
|
||||
try expand_points(allocator, galaxies.items, parsed, 1);
|
||||
try expandPoints(allocator, galaxies.items, parsed, 1);
|
||||
|
||||
return .{ .uint = sum_min_distances(galaxies.items) };
|
||||
return .{ .uint = sumMinDistances(galaxies.items) };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var galaxies = try list_galaxies(allocator, parsed);
|
||||
var galaxies = try listGalaxies(allocator, parsed);
|
||||
defer galaxies.deinit();
|
||||
|
||||
try expand_points(allocator, galaxies.items, parsed, 1000000 - 1);
|
||||
try expandPoints(allocator, galaxies.items, parsed, 1000000 - 1);
|
||||
|
||||
return .{ .uint = sum_min_distances(galaxies.items) };
|
||||
return .{ .uint = sumMinDistances(galaxies.items) };
|
||||
}
|
||||
|
||||
const example_input = [_][]const u8{
|
||||
|
@ -6,7 +6,7 @@ const ArrayList = std.ArrayList;
|
||||
const SpringState = enum {
|
||||
Operational, Damaged, Unknown,
|
||||
|
||||
fn from_char(char: u8) ?SpringState {
|
||||
fn fromChar(char: u8) ?SpringState {
|
||||
return switch (char) {
|
||||
'.' => .Operational,
|
||||
'#' => .Damaged,
|
||||
@ -15,7 +15,7 @@ const SpringState = enum {
|
||||
};
|
||||
}
|
||||
|
||||
fn to_char(self: SpringState) u8 {
|
||||
fn toChar(self: SpringState) u8 {
|
||||
return switch (self) {
|
||||
.Operational => '.',
|
||||
.Damaged => '#',
|
||||
@ -24,9 +24,9 @@ const SpringState = enum {
|
||||
}
|
||||
};
|
||||
|
||||
fn print_states(states: []const SpringState) void {
|
||||
fn printStates(states: []const SpringState) void {
|
||||
for (states) |state| {
|
||||
std.debug.print("{c}", .{state.to_char()});
|
||||
std.debug.print("{c}", .{state.toChar()});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
@ -37,7 +37,7 @@ const InputRow = struct {
|
||||
|
||||
fn print(self: InputRow) void {
|
||||
for (self.states) |state| {
|
||||
std.debug.print("{c}", .{state.to_char()});
|
||||
std.debug.print("{c}", .{state.toChar()});
|
||||
}
|
||||
std.debug.print(" ", .{});
|
||||
for (0.., self.damaged_groups) |i, group_size| {
|
||||
@ -75,7 +75,7 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input_row(allocator: Allocator, line: []const u8) !InputRow {
|
||||
fn parseInputRow(allocator: Allocator, line: []const u8) !InputRow {
|
||||
const space_idx = std.mem.indexOfScalar(u8, line, ' ') orelse return error.InvalidFormat;
|
||||
var states = try allocator.alloc(SpringState, space_idx);
|
||||
errdefer allocator.free(states);
|
||||
@ -85,7 +85,7 @@ fn parse_input_row(allocator: Allocator, line: []const u8) !InputRow {
|
||||
errdefer allocator.free(damaged_groups);
|
||||
|
||||
for (0.., line[0..space_idx]) |i, char| {
|
||||
states[i] = SpringState.from_char(char) orelse return error.InvalidFormat;
|
||||
states[i] = SpringState.fromChar(char) orelse return error.InvalidFormat;
|
||||
}
|
||||
|
||||
var it = std.mem.splitScalar(u8, line[(space_idx+1)..], ',');
|
||||
@ -101,18 +101,18 @@ fn parse_input_row(allocator: Allocator, line: []const u8) !InputRow {
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
|
||||
for (lines) |line| {
|
||||
try parsed.rows.append(try parse_input_row(allocator, line));
|
||||
try parsed.rows.append(try parseInputRow(allocator, line));
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
fn is_arrangement_valid(states: []const SpringState, groups: []const u32) bool {
|
||||
fn isArrangementValid(states: []const SpringState, groups: []const u32) bool {
|
||||
var it = std.mem.tokenizeScalar(SpringState, states, .Operational);
|
||||
var i: usize = 0;
|
||||
|
||||
@ -129,7 +129,7 @@ fn is_arrangement_valid(states: []const SpringState, groups: []const u32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn count_valid_arrangements(allocator: Allocator, states: []const SpringState, groups: []const u32) !u32 {
|
||||
fn countValidArrangements(allocator: Allocator, states: []const SpringState, groups: []const u32) !u32 {
|
||||
var unknown_count: u32 = 0;
|
||||
for (states) |state| {
|
||||
if (state == .Unknown) {
|
||||
@ -138,7 +138,7 @@ fn count_valid_arrangements(allocator: Allocator, states: []const SpringState, g
|
||||
}
|
||||
|
||||
if (unknown_count == 0) {
|
||||
if (is_arrangement_valid(states, groups)) {
|
||||
if (isArrangementValid(states, groups)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -170,7 +170,7 @@ fn count_valid_arrangements(allocator: Allocator, states: []const SpringState, g
|
||||
arrangement[index] = if (is_damaged) .Damaged else .Operational;
|
||||
}
|
||||
|
||||
if (is_arrangement_valid(arrangement, groups)) {
|
||||
if (isArrangementValid(arrangement, groups)) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@ -191,18 +191,18 @@ fn count_valid_arrangements(allocator: Allocator, states: []const SpringState, g
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: u32 = 0;
|
||||
for (parsed.rows.items) |row| {
|
||||
result += try count_valid_arrangements(allocator, row.states, row.damaged_groups);
|
||||
result += try countValidArrangements(allocator, row.states, row.damaged_groups);
|
||||
}
|
||||
|
||||
return .{ .uint = result };
|
||||
}
|
||||
|
||||
fn unfold_input_row(allocator: Allocator, input_row: InputRow) !InputRow {
|
||||
fn unfoldInputRow(allocator: Allocator, input_row: InputRow) !InputRow {
|
||||
const multiplier = 5;
|
||||
|
||||
const state_count = input_row.states.len;
|
||||
@ -228,12 +228,12 @@ fn unfold_input_row(allocator: Allocator, input_row: InputRow) !InputRow {
|
||||
};
|
||||
}
|
||||
|
||||
fn unfold_input(allocator: Allocator, input: Input) !Input {
|
||||
fn unfoldInput(allocator: Allocator, input: Input) !Input {
|
||||
var unfolded = Input.init(allocator);
|
||||
errdefer unfolded.deinit();
|
||||
|
||||
for (input.rows.items) |row| {
|
||||
try unfolded.rows.append(try unfold_input_row(allocator, row));
|
||||
try unfolded.rows.append(try unfoldInputRow(allocator, row));
|
||||
}
|
||||
|
||||
return unfolded;
|
||||
@ -272,7 +272,7 @@ const CacheKeyContext = struct {
|
||||
};
|
||||
const Cache = std.HashMap(CacheKey, u64, CacheKeyContext, 80);
|
||||
|
||||
fn count_valid_arrangements_dp(cache: *Cache, states: []const SpringState, groups: []const u32) !u64 {
|
||||
fn countValidArrangementsDp(cache: *Cache, states: []const SpringState, groups: []const u32) !u64 {
|
||||
if (states.len == 0) {
|
||||
if (groups.len == 0) {
|
||||
// If there are no springs left AND expect no more groups,
|
||||
@ -304,7 +304,7 @@ fn count_valid_arrangements_dp(cache: *Cache, states: []const SpringState, group
|
||||
|
||||
var result: u64 = 0;
|
||||
if (states[0] == .Operational or states[0] == .Unknown) {
|
||||
result += try count_valid_arrangements_dp(cache, states[1..], groups);
|
||||
result += try countValidArrangementsDp(cache, states[1..], groups);
|
||||
}
|
||||
|
||||
const group_size = groups[0];
|
||||
@ -315,9 +315,9 @@ fn count_valid_arrangements_dp(cache: *Cache, states: []const SpringState, group
|
||||
) {
|
||||
// If the damaged group ends with an operational spring
|
||||
if (group_size == states.len) {
|
||||
result += try count_valid_arrangements_dp(cache, states[group_size..], groups[1..]);
|
||||
result += try countValidArrangementsDp(cache, states[group_size..], groups[1..]);
|
||||
} else if (states[group_size] != .Damaged) {
|
||||
result += try count_valid_arrangements_dp(cache, states[(group_size+1)..], groups[1..]);
|
||||
result += try countValidArrangementsDp(cache, states[(group_size+1)..], groups[1..]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,10 +327,10 @@ fn count_valid_arrangements_dp(cache: *Cache, states: []const SpringState, group
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
const unfolded = try unfold_input(allocator, parsed);
|
||||
const unfolded = try unfoldInput(allocator, parsed);
|
||||
defer unfolded.deinit();
|
||||
|
||||
var cache = Cache.init(allocator);
|
||||
@ -338,7 +338,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
var result: u64 = 0;
|
||||
for (unfolded.rows.items) |row| {
|
||||
result += try count_valid_arrangements_dp(&cache, row.states, row.damaged_groups);
|
||||
result += try countValidArrangementsDp(&cache, row.states, row.damaged_groups);
|
||||
}
|
||||
|
||||
return .{ .uint = result };
|
||||
|
@ -50,7 +50,7 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_map(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
fn parseMap(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
const width: u32 = @intCast(lines[0].len);
|
||||
const height: u32 = @intCast(lines.len);
|
||||
var tiles = try std.ArrayList(bool).initCapacity(allocator, width*height);
|
||||
@ -69,7 +69,7 @@ fn parse_map(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
|
||||
@ -77,20 +77,20 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
for (0.., lines) |i, line| {
|
||||
if (line.len == 0) {
|
||||
const map_lines = lines[first_map_line..i];
|
||||
try parsed.maps.append(try parse_map(allocator, map_lines));
|
||||
try parsed.maps.append(try parseMap(allocator, map_lines));
|
||||
first_map_line = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_map_line != lines.len) {
|
||||
const map_lines = lines[first_map_line..];
|
||||
try parsed.maps.append(try parse_map(allocator, map_lines));
|
||||
try parsed.maps.append(try parseMap(allocator, map_lines));
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
fn check_horizontal_reflection(map: Map, reflect_x: u32) bool {
|
||||
fn checkHorizontalReflection(map: Map, reflect_x: u32) bool {
|
||||
assert(reflect_x < map.width-1);
|
||||
const left_start = reflect_x;
|
||||
const right_start = reflect_x + 1;
|
||||
@ -112,11 +112,11 @@ fn check_horizontal_reflection(map: Map, reflect_x: u32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn find_horizontal_reflection(map: Map, skip_x: ?u32) ?u32 {
|
||||
fn findHorizontalReflection(map: Map, skip_x: ?u32) ?u32 {
|
||||
for (0..map.width-1) |x| {
|
||||
const x_u32: u32 = @intCast(x);
|
||||
if (x_u32 == skip_x) continue;
|
||||
if (check_horizontal_reflection(map, x_u32)) {
|
||||
if (checkHorizontalReflection(map, x_u32)) {
|
||||
return @intCast(x);
|
||||
}
|
||||
}
|
||||
@ -124,7 +124,7 @@ fn find_horizontal_reflection(map: Map, skip_x: ?u32) ?u32 {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn check_vertical_reflection(map: Map, reflect_y: u32) bool {
|
||||
fn checkVerticalReflection(map: Map, reflect_y: u32) bool {
|
||||
assert(reflect_y < map.height-1);
|
||||
const top_start = reflect_y;
|
||||
const bottom_start = reflect_y + 1;
|
||||
@ -146,11 +146,11 @@ fn check_vertical_reflection(map: Map, reflect_y: u32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn find_vertical_reflection(map: Map, skip_y: ?u32) ?u32 {
|
||||
fn findVerticalReflection(map: Map, skip_y: ?u32) ?u32 {
|
||||
for (0..map.height-1) |y| {
|
||||
const y_u32: u32 = @intCast(y);
|
||||
if (y_u32 == skip_y) continue;
|
||||
if (check_vertical_reflection(map, y_u32)) {
|
||||
if (checkVerticalReflection(map, y_u32)) {
|
||||
return @intCast(y);
|
||||
}
|
||||
}
|
||||
@ -159,15 +159,15 @@ fn find_vertical_reflection(map: Map, skip_y: ?u32) ?u32 {
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
var parsed = try parse_input(input.allocator, input.lines);
|
||||
var parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: u64 = 0;
|
||||
for (parsed.maps.items) |map| {
|
||||
if (find_horizontal_reflection(map, null)) |x| {
|
||||
if (findHorizontalReflection(map, null)) |x| {
|
||||
result += (x+1);
|
||||
}
|
||||
if (find_vertical_reflection(map, null)) |y| {
|
||||
if (findVerticalReflection(map, null)) |y| {
|
||||
result += 100 * (y+1);
|
||||
}
|
||||
}
|
||||
@ -176,21 +176,21 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var parsed = try parse_input(input.allocator, input.lines);
|
||||
var parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: u64 = 0;
|
||||
for (parsed.maps.items) |map| {
|
||||
const original_reflect_x = find_horizontal_reflection(map, null);
|
||||
const original_reflect_y = find_vertical_reflection(map, null);
|
||||
const original_reflect_x = findHorizontalReflection(map, null);
|
||||
const original_reflect_y = findVerticalReflection(map, null);
|
||||
|
||||
var reflect_x: ?u32 = null;
|
||||
var reflect_y: ?u32 = null;
|
||||
const tiles = map.tiles.items;
|
||||
for (0..tiles.len) |i| {
|
||||
tiles[i] = !tiles[i];
|
||||
reflect_x = find_horizontal_reflection(map, original_reflect_x);
|
||||
reflect_y = find_vertical_reflection(map, original_reflect_y);
|
||||
reflect_x = findHorizontalReflection(map, original_reflect_x);
|
||||
reflect_y = findVerticalReflection(map, original_reflect_y);
|
||||
tiles[i] = !tiles[i];
|
||||
|
||||
if (reflect_x != null or reflect_y != null) break;
|
||||
|
@ -26,21 +26,21 @@ const Input = struct {
|
||||
self.tiles.deinit();
|
||||
}
|
||||
|
||||
fn get_idx(self: Input, x: u32, y: u32) usize {
|
||||
fn getIndex(self: Input, x: u32, y: u32) usize {
|
||||
assert(x < self.width);
|
||||
assert(y < self.height);
|
||||
return y * self.width + x;
|
||||
}
|
||||
|
||||
fn get(self: Input, x: u32, y: u32) Tile {
|
||||
return self.tiles.items[self.get_idx(x, y)];
|
||||
return self.tiles.items[self.getIndex(x, y)];
|
||||
}
|
||||
|
||||
fn set(self: Input, x: u32, y: u32, tile: Tile) void {
|
||||
self.tiles.items[self.get_idx(x, y)] = tile;
|
||||
self.tiles.items[self.getIndex(x, y)] = tile;
|
||||
}
|
||||
|
||||
fn in_bounds(self: Input, x: i32, y: i32) bool {
|
||||
fn inBounds(self: Input, x: i32, y: i32) bool {
|
||||
return (0 <= x and x < self.width) and (0 <= y and y < self.height);
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
parsed.width = @intCast(lines[0].len);
|
||||
@ -86,7 +86,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
fn slide_rock(input: Input, x: u32, y: u32, dir_x: i32, dir_y: i32) void {
|
||||
fn slideRock(input: Input, x: u32, y: u32, dir_x: i32, dir_y: i32) void {
|
||||
assert(input.get(x, y) == .Rock);
|
||||
|
||||
var new_x = x;
|
||||
@ -94,7 +94,7 @@ fn slide_rock(input: Input, x: u32, y: u32, dir_x: i32, dir_y: i32) void {
|
||||
while (true) {
|
||||
const next_x = @as(i32, @intCast(new_x)) + dir_x;
|
||||
const next_y = @as(i32, @intCast(new_y)) + dir_y;
|
||||
if (!input.in_bounds(next_x, next_y)) break;
|
||||
if (!input.inBounds(next_x, next_y)) break;
|
||||
if (input.get(@intCast(next_x), @intCast(next_y)) != .Empty) break;
|
||||
|
||||
new_x = @intCast(next_x);
|
||||
@ -105,7 +105,7 @@ fn slide_rock(input: Input, x: u32, y: u32, dir_x: i32, dir_y: i32) void {
|
||||
input.set(new_x, new_y, .Rock);
|
||||
}
|
||||
|
||||
fn slide_rocks(input: Input, dir_x: i32, dir_y: i32) void {
|
||||
fn slideRocks(input: Input, dir_x: i32, dir_y: i32) void {
|
||||
if (dir_y != 0) {
|
||||
// Column-based
|
||||
for (0..input.height) |oy| {
|
||||
@ -113,7 +113,7 @@ fn slide_rocks(input: Input, dir_x: i32, dir_y: i32) void {
|
||||
const x: u32 = @intCast(ox);
|
||||
const y: u32 = @intCast(@as(i32, @intCast(oy)) * (-dir_y) + @divExact(dir_y + 1, 2) * @as(i32, @intCast(input.height-1)));
|
||||
if (input.get(x, y) == .Rock) {
|
||||
slide_rock(input, x, y, dir_x, dir_y);
|
||||
slideRock(input, x, y, dir_x, dir_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,14 +124,14 @@ fn slide_rocks(input: Input, dir_x: i32, dir_y: i32) void {
|
||||
const x: u32 = @intCast(@as(i32, @intCast(ox)) * (-dir_x) + @divExact(dir_x + 1, 2) * @as(i32, @intCast(input.width-1)));
|
||||
const y: u32 = @intCast(oy);
|
||||
if (input.get(x, y) == .Rock) {
|
||||
slide_rock(input, x, y, dir_x, dir_y);
|
||||
slideRock(input, x, y, dir_x, dir_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cycle_slide(input: Input) void {
|
||||
fn cycleSlide(input: Input) void {
|
||||
const dirs = &.{
|
||||
.{ .x = 0, .y = -1 }, // North
|
||||
.{ .x = -1, .y = 0 }, // West
|
||||
@ -140,11 +140,11 @@ fn cycle_slide(input: Input) void {
|
||||
};
|
||||
|
||||
inline for (dirs) |dir| {
|
||||
slide_rocks(input, dir.x, dir.y);
|
||||
slideRocks(input, dir.x, dir.y);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_load(input: Input) u64 {
|
||||
fn getTotalLoad(input: Input) u64 {
|
||||
var result: u64 = 0;
|
||||
for (0..input.height) |y| {
|
||||
var count: u32 = 0;
|
||||
@ -160,19 +160,19 @@ fn get_total_load(input: Input) u64 {
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
const parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
slide_rocks(parsed, 0, -1);
|
||||
slideRocks(parsed, 0, -1);
|
||||
|
||||
return .{ .uint = get_total_load(parsed) };
|
||||
return .{ .uint = getTotalLoad(parsed) };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const target_cycle_count = 1000000000;
|
||||
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var seen = std.ArrayList(std.ArrayList(Tile)).init(allocator);
|
||||
@ -187,7 +187,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var cycle_start: u32 = 0;
|
||||
var iteration: u32 = 0;
|
||||
outer: while (true) {
|
||||
cycle_slide(parsed);
|
||||
cycleSlide(parsed);
|
||||
|
||||
for (0.., seen.items) |i, tiles| {
|
||||
if (std.mem.eql(Tile, tiles.items, parsed.tiles.items)) {
|
||||
@ -207,7 +207,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
.height = parsed.height
|
||||
};
|
||||
|
||||
return .{ .uint = get_total_load(skipped_map) };
|
||||
return .{ .uint = getTotalLoad(skipped_map) };
|
||||
}
|
||||
|
||||
const example_input = [_][]const u8{
|
||||
|
@ -40,7 +40,7 @@ const HashMap = struct {
|
||||
}
|
||||
|
||||
fn put(self: *HashMap, key: []const u8, value: u8) !void {
|
||||
const hash = compute_hash(key);
|
||||
const hash = computeHash(key);
|
||||
var box = &self.boxes[hash];
|
||||
|
||||
for (box.items) |*item| {
|
||||
@ -54,7 +54,7 @@ const HashMap = struct {
|
||||
}
|
||||
|
||||
fn remove(self: *HashMap, key: []const u8) void {
|
||||
const hash = compute_hash(key);
|
||||
const hash = computeHash(key);
|
||||
var box = &self.boxes[hash];
|
||||
for (0.., box.items) |i, item| {
|
||||
if (std.mem.eql(u8, item.key, key)) {
|
||||
@ -77,7 +77,7 @@ const HashMap = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var result = Input.init(allocator);
|
||||
errdefer result.deinit();
|
||||
|
||||
@ -89,7 +89,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn compute_hash(text: []const u8) u8 {
|
||||
fn computeHash(text: []const u8) u8 {
|
||||
var current: u16 = 0;
|
||||
for (text) |symbol| {
|
||||
current += symbol;
|
||||
@ -100,12 +100,12 @@ fn compute_hash(text: []const u8) u8 {
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
const parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: u64 = 0;
|
||||
for (parsed.parts.items) |item| {
|
||||
result += compute_hash(item);
|
||||
result += computeHash(item);
|
||||
}
|
||||
|
||||
return .{ .uint = result };
|
||||
@ -113,7 +113,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
const parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var hash_map = HashMap.init(allocator);
|
||||
|
@ -19,7 +19,7 @@ const Tile = enum {
|
||||
LeftMirror,
|
||||
RightMirror,
|
||||
|
||||
fn from_u8(symbol: u8) ?Tile {
|
||||
fn fromU8(symbol: u8) ?Tile {
|
||||
return switch (symbol) {
|
||||
'.' => .Empty,
|
||||
'\\' => .LeftMirror,
|
||||
@ -30,7 +30,7 @@ const Tile = enum {
|
||||
};
|
||||
}
|
||||
|
||||
fn to_u8(self: Tile) u8 {
|
||||
fn toU8(self: Tile) u8 {
|
||||
return switch (self) {
|
||||
.Empty => '.',
|
||||
.LeftMirror => '\\',
|
||||
@ -59,17 +59,17 @@ const Map = struct {
|
||||
};
|
||||
}
|
||||
|
||||
fn get_idx(self: Map, x: u32, y: u32) usize {
|
||||
fn getIndex(self: Map, x: u32, y: u32) usize {
|
||||
assert(x < self.width);
|
||||
assert(y < self.height);
|
||||
return y * self.width + x;
|
||||
}
|
||||
|
||||
fn get(self: Map, x: u32, y: u32) Tile {
|
||||
return self.tiles.items[self.get_idx(x, y)];
|
||||
return self.tiles.items[self.getIndex(x, y)];
|
||||
}
|
||||
|
||||
fn in_bounds(self: Map, x: i32, y: i32) bool {
|
||||
fn inBounds(self: Map, x: i32, y: i32) bool {
|
||||
return (0 <= x and x < self.width) and (0 <= y and y < self.height);
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ const Map = struct {
|
||||
for (0..self.width) |x| {
|
||||
const tile = self.get(@intCast(x), @intCast(y));
|
||||
|
||||
std.debug.print("{c}", .{tile.to_u8()});
|
||||
std.debug.print("{c}", .{tile.toU8()});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
@ -94,15 +94,15 @@ const Beam = struct {
|
||||
dir: PointI32,
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
const width: u32 = @intCast(lines[0].len);
|
||||
const height: u32 = @intCast(lines.len);
|
||||
const map = try Map.init(allocator, width, height);
|
||||
|
||||
for (0.., lines) |y, line| {
|
||||
for (0.., line) |x, symbol| {
|
||||
const tile: Tile = Tile.from_u8(symbol) orelse return error.InvalidTile;
|
||||
const tile_idx = map.get_idx(@intCast(x), @intCast(y));
|
||||
const tile: Tile = Tile.fromU8(symbol) orelse return error.InvalidTile;
|
||||
const tile_idx = map.getIndex(@intCast(x), @intCast(y));
|
||||
map.tiles.items[tile_idx] = tile;
|
||||
}
|
||||
}
|
||||
@ -110,11 +110,11 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Map {
|
||||
return map;
|
||||
}
|
||||
|
||||
fn cast_beam(map: Map, from: PointU32, dir: PointI32) PointU32 {
|
||||
var current: PointI32 = from.to_i32();
|
||||
fn castBeam(map: Map, from: PointU32, dir: PointI32) PointU32 {
|
||||
var current: PointI32 = from.toI32();
|
||||
while (true) {
|
||||
const next_point = current.add(dir);
|
||||
if (!map.in_bounds(next_point.x, next_point.y)) break;
|
||||
if (!map.inBounds(next_point.x, next_point.y)) break;
|
||||
current = next_point;
|
||||
|
||||
const tile = map.get(@intCast(current.x), @intCast(current.y));
|
||||
@ -125,10 +125,10 @@ fn cast_beam(map: Map, from: PointU32, dir: PointI32) PointU32 {
|
||||
break;
|
||||
}
|
||||
|
||||
return current.to_u32();
|
||||
return current.toU32();
|
||||
}
|
||||
|
||||
fn contains_point(comptime T: type, list: []Point(T), point: Point(T)) bool {
|
||||
fn containsPoint(comptime T: type, list: []Point(T), point: Point(T)) bool {
|
||||
for (list) |other| {
|
||||
if (other.eql(point)) {
|
||||
return true;
|
||||
@ -137,7 +137,7 @@ fn contains_point(comptime T: type, list: []Point(T), point: Point(T)) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn count_energized_tiles(energy_map: []bool) u64 {
|
||||
fn countEnergizedTiles(energy_map: []bool) u64 {
|
||||
var result: u64 = 0;
|
||||
for (energy_map) |energy| {
|
||||
result += @intFromBool(energy);
|
||||
@ -145,7 +145,7 @@ fn count_energized_tiles(energy_map: []bool) u64 {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn simulate_beam(allocator: Allocator, map: Map, from_pos: PointU32, from_dir: PointI32) ![]bool {
|
||||
fn simulateBeam(allocator: Allocator, map: Map, from_pos: PointU32, from_dir: PointI32) ![]bool {
|
||||
var used_splits = std.ArrayList(PointU32).init(allocator);
|
||||
defer used_splits.deinit();
|
||||
|
||||
@ -163,17 +163,17 @@ fn simulate_beam(allocator: Allocator, map: Map, from_pos: PointU32, from_dir: P
|
||||
if (is_first and map.get(beam.pos.x, beam.pos.y) != .Empty) {
|
||||
destination = beam.pos;
|
||||
} else {
|
||||
destination = cast_beam(map, beam.pos, beam.dir);
|
||||
destination = castBeam(map, beam.pos, beam.dir);
|
||||
if (destination.eql(beam.pos)) continue;
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
var current: PointU32 = beam.pos;
|
||||
energy_map[map.get_idx(current.x, current.y)] = true;
|
||||
energy_map[map.getIndex(current.x, current.y)] = true;
|
||||
while (!current.eql(destination)) {
|
||||
current.x = @intCast(@as(i32, @intCast(current.x)) + beam.dir.x);
|
||||
current.y = @intCast(@as(i32, @intCast(current.y)) + beam.dir.y);
|
||||
energy_map[map.get_idx(current.x, current.y)] = true;
|
||||
energy_map[map.getIndex(current.x, current.y)] = true;
|
||||
}
|
||||
|
||||
const tile = map.get(destination.x, destination.y);
|
||||
@ -202,13 +202,13 @@ fn simulate_beam(allocator: Allocator, map: Map, from_pos: PointU32, from_dir: P
|
||||
unreachable;
|
||||
}
|
||||
} else if (tile == .VerticalSplit) {
|
||||
if (!contains_point(u32, used_splits.items, destination)) {
|
||||
if (!containsPoint(u32, used_splits.items, destination)) {
|
||||
try beams.append(Beam{ .pos = destination, .dir = UP });
|
||||
try beams.append(Beam{ .pos = destination, .dir = DOWN });
|
||||
try used_splits.append(destination);
|
||||
}
|
||||
} else if (tile == .HorizontalSplit) {
|
||||
if (!contains_point(u32, used_splits.items, destination)) {
|
||||
if (!containsPoint(u32, used_splits.items, destination)) {
|
||||
try beams.append(Beam{ .pos = destination, .dir = LEFT });
|
||||
try beams.append(Beam{ .pos = destination, .dir = RIGHT });
|
||||
try used_splits.append(destination);
|
||||
@ -219,7 +219,7 @@ fn simulate_beam(allocator: Allocator, map: Map, from_pos: PointU32, from_dir: P
|
||||
return energy_map;
|
||||
}
|
||||
|
||||
fn print_energy_map(map: Map, energy_map: []bool) void {
|
||||
fn printEnergyMap(map: Map, energy_map: []bool) void {
|
||||
for (0..map.height) |y| {
|
||||
for (0..map.width) |x| {
|
||||
const idx = y * map.width + x;
|
||||
@ -235,20 +235,20 @@ fn print_energy_map(map: Map, energy_map: []bool) void {
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const map = try parse_input(input.allocator, input.lines);
|
||||
const map = try parseInput(input.allocator, input.lines);
|
||||
defer map.deinit();
|
||||
|
||||
const energy_map = try simulate_beam(allocator, map, PointU32.zero(), RIGHT);
|
||||
const energy_map = try simulateBeam(allocator, map, PointU32.zero(), RIGHT);
|
||||
defer allocator.free(energy_map);
|
||||
|
||||
// print_energy_map(map, energy_map);
|
||||
|
||||
return .{ .uint = count_energized_tiles(energy_map) };
|
||||
return .{ .uint = countEnergizedTiles(energy_map) };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const map = try parse_input(input.allocator, input.lines);
|
||||
const map = try parseInput(input.allocator, input.lines);
|
||||
defer map.deinit();
|
||||
|
||||
var result: u64 = 0;
|
||||
@ -256,32 +256,32 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
for (0..map.height) |y| {
|
||||
{
|
||||
const from = PointU32{ .x = 0, .y = @intCast(y) };
|
||||
const energy_map = try simulate_beam(allocator, map, from, RIGHT);
|
||||
const energy_map = try simulateBeam(allocator, map, from, RIGHT);
|
||||
defer allocator.free(energy_map);
|
||||
result = @max(result, count_energized_tiles(energy_map));
|
||||
result = @max(result, countEnergizedTiles(energy_map));
|
||||
}
|
||||
|
||||
{
|
||||
const from = PointU32{ .x = map.width-1, .y = @intCast(y) };
|
||||
const energy_map = try simulate_beam(allocator, map, from, LEFT);
|
||||
const energy_map = try simulateBeam(allocator, map, from, LEFT);
|
||||
defer allocator.free(energy_map);
|
||||
result = @max(result, count_energized_tiles(energy_map));
|
||||
result = @max(result, countEnergizedTiles(energy_map));
|
||||
}
|
||||
}
|
||||
|
||||
for (0..map.width) |x| {
|
||||
{
|
||||
const from = PointU32{ .x = @intCast(x), .y = 0 };
|
||||
const energy_map = try simulate_beam(allocator, map, from, DOWN);
|
||||
const energy_map = try simulateBeam(allocator, map, from, DOWN);
|
||||
defer allocator.free(energy_map);
|
||||
result = @max(result, count_energized_tiles(energy_map));
|
||||
result = @max(result, countEnergizedTiles(energy_map));
|
||||
}
|
||||
|
||||
{
|
||||
const from = PointU32{ .x = @intCast(x), .y = map.height-1 };
|
||||
const energy_map = try simulate_beam(allocator, map, from, UP);
|
||||
const energy_map = try simulateBeam(allocator, map, from, UP);
|
||||
defer allocator.free(energy_map);
|
||||
result = @max(result, count_energized_tiles(energy_map));
|
||||
result = @max(result, countEnergizedTiles(energy_map));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ const Direction = enum {
|
||||
Left,
|
||||
Right,
|
||||
|
||||
pub fn to_offset(self: Direction) PointI8 {
|
||||
pub fn toOffset(self: Direction) PointI8 {
|
||||
return switch (self) {
|
||||
.Up => PointI8{ .x = 0, .y = -1 },
|
||||
.Down => PointI8{ .x = 0, .y = 1 },
|
||||
@ -53,26 +53,26 @@ const HeatMap = struct {
|
||||
self.tiles.deinit();
|
||||
}
|
||||
|
||||
pub fn get_idx(self: HeatMap, x: u32, y: u32) usize {
|
||||
pub fn getIndex(self: HeatMap, x: u32, y: u32) usize {
|
||||
return self.width * y + x;
|
||||
}
|
||||
|
||||
pub fn in_bounds(self: HeatMap, x: i32, y: i32) bool {
|
||||
pub fn inBounds(self: HeatMap, x: i32, y: i32) bool {
|
||||
return (0 <= x and x < self.width) and (0 <= y and y < self.height);
|
||||
}
|
||||
|
||||
pub fn set(self: HeatMap, x: u32, y: u32, value: u8) void {
|
||||
self.tiles.items[self.get_idx(x, y)] = value;
|
||||
self.tiles.items[self.getIndex(x, y)] = value;
|
||||
}
|
||||
|
||||
pub fn get(self: HeatMap, x: u32, y: u32) u8 {
|
||||
return self.tiles.items[self.get_idx(x, y)];
|
||||
return self.tiles.items[self.getIndex(x, y)];
|
||||
}
|
||||
|
||||
pub fn print(self: HeatMap) void {
|
||||
for (0..self.height) |y| {
|
||||
for (0..self.width) |x| {
|
||||
const tile_idx = self.get_idx(@intCast(x), @intCast(y));
|
||||
const tile_idx = self.getIndex(@intCast(x), @intCast(y));
|
||||
const symbol = self.tiles.items[tile_idx] + '0';
|
||||
std.debug.print("{c}", .{symbol});
|
||||
}
|
||||
@ -81,7 +81,7 @@ const HeatMap = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !HeatMap {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !HeatMap {
|
||||
const height = lines.len;
|
||||
const width = lines[0].len;
|
||||
var heat_map = try HeatMap.init(allocator, @intCast(width), @intCast(height));
|
||||
@ -111,11 +111,11 @@ fn compareQueueItem(heat_map: HeatMap, a: QueueItem, b: QueueItem) std.math.Orde
|
||||
return std.math.order(score_a, score_b);
|
||||
}
|
||||
|
||||
inline fn push_to_queue(queue: *HeatPriorityQueue, heat_map: HeatMap, state: QueueItem, dir: Direction) !void {
|
||||
const dir_offset = dir.to_offset();
|
||||
inline fn pushToQueue(queue: *HeatPriorityQueue, heat_map: HeatMap, state: QueueItem, dir: Direction) !void {
|
||||
const dir_offset = dir.toOffset();
|
||||
const neighbour_x = @as(i32, @intCast(state.pos.x)) + dir_offset.x;
|
||||
const neighbour_y = @as(i32, @intCast(state.pos.y)) + dir_offset.y;
|
||||
if (!heat_map.in_bounds(neighbour_x, neighbour_y)) return; // Skip out of bounds
|
||||
if (!heat_map.inBounds(neighbour_x, neighbour_y)) return; // Skip out of bounds
|
||||
|
||||
var consecutive_count = state.consecutive_count;
|
||||
if (state.dir == dir) {
|
||||
@ -136,7 +136,7 @@ inline fn push_to_queue(queue: *HeatPriorityQueue, heat_map: HeatMap, state: Que
|
||||
try queue.add(next_state);
|
||||
}
|
||||
|
||||
fn solve_min_heat_loss(allocator: Allocator, heat_map: HeatMap, min_steps: u32, max_steps: u32) !?u32 {
|
||||
fn solveMinHeatLoss(allocator: Allocator, heat_map: HeatMap, min_steps: u32, max_steps: u32) !?u32 {
|
||||
var queue = HeatPriorityQueue.init(allocator, heat_map);
|
||||
defer queue.deinit();
|
||||
|
||||
@ -167,7 +167,7 @@ fn solve_min_heat_loss(allocator: Allocator, heat_map: HeatMap, min_steps: u32,
|
||||
}
|
||||
|
||||
if (state.consecutive_count < min_steps) {
|
||||
try push_to_queue(&queue, heat_map, state, state.dir);
|
||||
try pushToQueue(&queue, heat_map, state, state.dir);
|
||||
} else {
|
||||
for (directions) |dir| {
|
||||
if (state.dir == dir and state.consecutive_count == max_steps) continue;
|
||||
@ -175,7 +175,7 @@ fn solve_min_heat_loss(allocator: Allocator, heat_map: HeatMap, min_steps: u32,
|
||||
// Skip direction, where it would need to turn around
|
||||
if (state.dir == dir.inv()) continue;
|
||||
|
||||
try push_to_queue(&queue, heat_map, state, dir);
|
||||
try pushToQueue(&queue, heat_map, state, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,19 +185,19 @@ fn solve_min_heat_loss(allocator: Allocator, heat_map: HeatMap, min_steps: u32,
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const heat_map = try parse_input(allocator, input.lines);
|
||||
const heat_map = try parseInput(allocator, input.lines);
|
||||
defer heat_map.deinit();
|
||||
|
||||
const answer = try solve_min_heat_loss(allocator, heat_map, 0, 3);
|
||||
const answer = try solveMinHeatLoss(allocator, heat_map, 0, 3);
|
||||
return .{ .uint = answer.? };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const heat_map = try parse_input(allocator, input.lines);
|
||||
const heat_map = try parseInput(allocator, input.lines);
|
||||
defer heat_map.deinit();
|
||||
|
||||
const answer = try solve_min_heat_loss(allocator, heat_map, 4, 10);
|
||||
const answer = try solveMinHeatLoss(allocator, heat_map, 4, 10);
|
||||
return .{ .uint = answer.? };
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ const Direction = enum {
|
||||
Left,
|
||||
Right,
|
||||
|
||||
fn from_str(str: []const u8) ?Direction {
|
||||
fn fromStr(str: []const u8) ?Direction {
|
||||
if (std.mem.eql(u8, str, "U")) {
|
||||
return .Up;
|
||||
} else if (std.mem.eql(u8, str, "D")) {
|
||||
@ -31,7 +31,7 @@ const Direction = enum {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_offset(self: Direction) PointI32 {
|
||||
fn toOffset(self: Direction) PointI32 {
|
||||
return switch (self) {
|
||||
.Up => PointI32{ .x = 0, .y = -1 },
|
||||
.Down => PointI32{ .x = 0, .y = 1 },
|
||||
@ -48,30 +48,30 @@ const DigInstruction = struct {
|
||||
|
||||
const Instructions = std.ArrayList(DigInstruction);
|
||||
|
||||
fn parse_dig_instruction1(line: []const u8) !DigInstruction {
|
||||
fn parseDigInstruction1(line: []const u8) !DigInstruction {
|
||||
var iter = std.mem.splitScalar(u8, line, ' ');
|
||||
|
||||
const dir_str = iter.next() orelse return error.MissingDirection;
|
||||
const steps_str = iter.next() orelse return error.MissingSteps;
|
||||
|
||||
return DigInstruction{
|
||||
.dir = Direction.from_str(dir_str) orelse return error.InvalidDirection,
|
||||
.dir = Direction.fromStr(dir_str) orelse return error.InvalidDirection,
|
||||
.steps = try std.fmt.parseUnsigned(u32, steps_str, 10)
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input1(allocator: Allocator, lines: []const []const u8) !Instructions {
|
||||
fn parseInput1(allocator: Allocator, lines: []const []const u8) !Instructions {
|
||||
var result = Instructions.init(allocator);
|
||||
errdefer result.deinit();
|
||||
|
||||
for (lines) |line| {
|
||||
try result.append(try parse_dig_instruction1(line));
|
||||
try result.append(try parseDigInstruction1(line));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn get_bounds(segments: []const Segment) std.meta.Tuple(&.{ PointI32, PointI32 }) {
|
||||
fn getBounds(segments: []const Segment) std.meta.Tuple(&.{ PointI32, PointI32 }) {
|
||||
var upper_left = PointI32.zero();
|
||||
var lower_right = PointI32.zero();
|
||||
|
||||
@ -87,13 +87,13 @@ fn get_bounds(segments: []const Segment) std.meta.Tuple(&.{ PointI32, PointI32 }
|
||||
return .{ upper_left, lower_right };
|
||||
}
|
||||
|
||||
fn get_segments(allocator: Allocator, insts: Instructions) !std.ArrayList(Segment) {
|
||||
fn getSegments(allocator: Allocator, insts: Instructions) !std.ArrayList(Segment) {
|
||||
var segments = std.ArrayList(Segment).init(allocator);
|
||||
errdefer segments.deinit();
|
||||
|
||||
var current = PointI32.zero();
|
||||
for (insts.items) |inst| {
|
||||
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||
const step = inst.dir.toOffset().mul(@intCast(inst.steps));
|
||||
const next = current.add(step);
|
||||
|
||||
try segments.append(Segment{ .start = current, .stop = next });
|
||||
@ -107,7 +107,7 @@ fn get_segments(allocator: Allocator, insts: Instructions) !std.ArrayList(Segmen
|
||||
// GOD DAMN IT, AGAIN WITH THIS THEOROM! I THOUGH IT WAS SCANLINES!
|
||||
// Shoelace theorum + Pick's theorum
|
||||
// Day 10 all over again :/
|
||||
fn get_lagoon_size(allocator: Allocator, instructions: Instructions) !usize {
|
||||
fn getLagoonSize(allocator: Allocator, instructions: Instructions) !usize {
|
||||
var boundry_points: u32 = 0;
|
||||
|
||||
var loop_path = std.ArrayList(PointI32).init(allocator);
|
||||
@ -116,7 +116,7 @@ fn get_lagoon_size(allocator: Allocator, instructions: Instructions) !usize {
|
||||
var current = PointI32.zero();
|
||||
try loop_path.append(current);
|
||||
for (instructions.items) |inst| {
|
||||
const step = inst.dir.to_offset().mul(@intCast(inst.steps));
|
||||
const step = inst.dir.toOffset().mul(@intCast(inst.steps));
|
||||
current = current.add(step);
|
||||
boundry_points += inst.steps;
|
||||
|
||||
@ -148,13 +148,13 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
var instructions = Instructions.init(allocator);
|
||||
defer instructions.deinit();
|
||||
for (input.lines) |line| {
|
||||
try instructions.append(try parse_dig_instruction1(line));
|
||||
try instructions.append(try parseDigInstruction1(line));
|
||||
}
|
||||
|
||||
return .{ .uint = try get_lagoon_size(allocator, instructions) };
|
||||
return .{ .uint = try getLagoonSize(allocator, instructions) };
|
||||
}
|
||||
|
||||
fn parse_dig_instruction2(line: []const u8) !DigInstruction {
|
||||
fn parseDigInstruction2(line: []const u8) !DigInstruction {
|
||||
var iter = std.mem.splitScalar(u8, line, ' ');
|
||||
|
||||
_ = iter.next();
|
||||
@ -184,10 +184,10 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var instructions = Instructions.init(allocator);
|
||||
defer instructions.deinit();
|
||||
for (input.lines) |line| {
|
||||
try instructions.append(try parse_dig_instruction2(line));
|
||||
try instructions.append(try parseDigInstruction2(line));
|
||||
}
|
||||
|
||||
return .{ .uint = try get_lagoon_size(allocator, instructions) };
|
||||
return .{ .uint = try getLagoonSize(allocator, instructions) };
|
||||
}
|
||||
|
||||
const example_input = [_][]const u8{
|
||||
|
@ -17,7 +17,7 @@ const PartProperty = enum {
|
||||
A,
|
||||
S,
|
||||
|
||||
fn from_str(text: []const u8) ?PartProperty {
|
||||
fn fromStr(text: []const u8) ?PartProperty {
|
||||
if (std.mem.eql(u8, text, "x")) {
|
||||
return .X;
|
||||
} else if (std.mem.eql(u8, text, "m")) {
|
||||
@ -31,7 +31,7 @@ const PartProperty = enum {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_str(self: PartProperty) []const u8 {
|
||||
fn toStr(self: PartProperty) []const u8 {
|
||||
return switch (self) {
|
||||
.X => "x",
|
||||
.A => "a",
|
||||
@ -61,7 +61,7 @@ const PropertyRange = struct {
|
||||
min: u16,
|
||||
max: u16,
|
||||
|
||||
fn is_empty(self: @This()) bool {
|
||||
fn isEmpty(self: @This()) bool {
|
||||
return self.min > self.max;
|
||||
}
|
||||
|
||||
@ -85,8 +85,8 @@ const MachinePartRange = struct {
|
||||
};
|
||||
}
|
||||
|
||||
fn is_empty(self: MachinePartRange) bool {
|
||||
return self.x.is_empty() or self.m.is_empty() or self.a.is_empty() or self.s.is_empty();
|
||||
fn isEmpty(self: MachinePartRange) bool {
|
||||
return self.x.isEmpty() or self.m.isEmpty() or self.a.isEmpty() or self.s.isEmpty();
|
||||
}
|
||||
|
||||
fn size(self: MachinePartRange) u64 {
|
||||
@ -115,26 +115,26 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn print_rule(rule: Rule) void {
|
||||
fn printRule(rule: Rule) void {
|
||||
switch (rule.condition) {
|
||||
.Always => std.debug.print("{s}", .{rule.next.slice()}),
|
||||
.Less => std.debug.print("{s}<{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()}),
|
||||
.More => std.debug.print("{s}>{}:{s}", .{rule.property.to_str(), rule.value, rule.next.slice()})
|
||||
.Less => std.debug.print("{s}<{}:{s}", .{rule.property.toStr(), rule.value, rule.next.slice()}),
|
||||
.More => std.debug.print("{s}>{}:{s}", .{rule.property.toStr(), rule.value, rule.next.slice()})
|
||||
}
|
||||
}
|
||||
|
||||
fn print_workflow(workflow: Workflow) void {
|
||||
fn printWorkflow(workflow: Workflow) void {
|
||||
std.debug.print("{{", .{});
|
||||
for (0.., workflow.items) |i, rule| {
|
||||
if (i > 0) {
|
||||
std.debug.print(",", .{});
|
||||
}
|
||||
print_rule(rule);
|
||||
printRule(rule);
|
||||
}
|
||||
std.debug.print("}}\n", .{});
|
||||
}
|
||||
|
||||
fn parse_workflow(allocator: Allocator, line: []const u8) !std.meta.Tuple(&.{ NameString, Workflow }) {
|
||||
fn parseWorkflow(allocator: Allocator, line: []const u8) !std.meta.Tuple(&.{ NameString, Workflow }) {
|
||||
var parsed = Workflow.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
|
||||
@ -159,7 +159,7 @@ fn parse_workflow(allocator: Allocator, line: []const u8) !std.meta.Tuple(&.{ Na
|
||||
|
||||
try parsed.append(Rule{
|
||||
.condition = condition,
|
||||
.property = PartProperty.from_str(rule_str[0..cmp_idx]) orelse return error.Invalid,
|
||||
.property = PartProperty.fromStr(rule_str[0..cmp_idx]) orelse return error.Invalid,
|
||||
.value = try std.fmt.parseUnsigned(u16, rule_str[(cmp_idx+1)..colon], 10),
|
||||
.next = try NameString.fromSlice(rule_str[(colon+1)..])
|
||||
});
|
||||
@ -174,7 +174,7 @@ fn parse_workflow(allocator: Allocator, line: []const u8) !std.meta.Tuple(&.{ Na
|
||||
return .{ name, parsed };
|
||||
}
|
||||
|
||||
fn parse_machine_part(line: []const u8) !MachinePart {
|
||||
fn parseMachinePart(line: []const u8) !MachinePart {
|
||||
if (line[0] != '{') return error.Invalid;
|
||||
if (line[line.len-1] != '}') return error.Invalid;
|
||||
|
||||
@ -203,7 +203,7 @@ fn parse_machine_part(line: []const u8) !MachinePart {
|
||||
return machine_part;
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
|
||||
@ -217,18 +217,18 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
assert(lines[section_split].len == 0);
|
||||
|
||||
for (lines[0..section_split]) |line| {
|
||||
const row = try parse_workflow(allocator, line);
|
||||
const row = try parseWorkflow(allocator, line);
|
||||
try parsed.workflows.put(row[0], row[1]);
|
||||
}
|
||||
|
||||
for (lines[(section_split+1)..]) |line| {
|
||||
try parsed.machine_parts.append(try parse_machine_part(line));
|
||||
try parsed.machine_parts.append(try parseMachinePart(line));
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
fn eval_rule(part: MachinePart, rule: Rule) ?NameString {
|
||||
fn evalRule(part: MachinePart, rule: Rule) ?NameString {
|
||||
if (rule.condition == .Always) {
|
||||
return rule.next;
|
||||
}
|
||||
@ -256,9 +256,9 @@ fn eval_rule(part: MachinePart, rule: Rule) ?NameString {
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_workflow(part: MachinePart, workflow: Workflow) NameString {
|
||||
fn evalWorkflow(part: MachinePart, workflow: Workflow) NameString {
|
||||
for (workflow.items) |rule| {
|
||||
if (eval_rule(part, rule)) |name| {
|
||||
if (evalRule(part, rule)) |name| {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@ -266,10 +266,10 @@ fn eval_workflow(part: MachinePart, workflow: Workflow) NameString {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn is_part_accepted(part: MachinePart, workflows: std.AutoHashMap(NameString, Workflow)) !bool {
|
||||
fn isPartAccepted(part: MachinePart, workflows: std.AutoHashMap(NameString, Workflow)) !bool {
|
||||
var current = workflows.get(try NameString.fromSlice("in")) orelse return error.MissingInWorkflow;
|
||||
while (true) {
|
||||
const next_name = eval_workflow(part, current);
|
||||
const next_name = evalWorkflow(part, current);
|
||||
const next_name_str = next_name.slice();
|
||||
|
||||
if (std.mem.eql(u8, next_name_str, "R")) {
|
||||
@ -284,12 +284,12 @@ fn is_part_accepted(part: MachinePart, workflows: std.AutoHashMap(NameString, Wo
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var parsed = try parse_input(allocator, input.lines);
|
||||
var parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: u64 = 0;
|
||||
for (parsed.machine_parts.items) |part| {
|
||||
if (try is_part_accepted(part, parsed.workflows)) {
|
||||
if (try isPartAccepted(part, parsed.workflows)) {
|
||||
result += part.s;
|
||||
result += part.x;
|
||||
result += part.m;
|
||||
@ -302,7 +302,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var parsed = try parse_input(allocator, input.lines);
|
||||
var parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
const State = struct {
|
||||
@ -338,7 +338,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
const workflow: Workflow = parsed.workflows.get(state.name).?;
|
||||
for (workflow.items) |rule| {
|
||||
if (current.is_empty()) break;
|
||||
if (current.isEmpty()) break;
|
||||
|
||||
if (rule.condition == .Always) {
|
||||
try stack.append(State{
|
||||
|
14
src/day2.zig
14
src/day2.zig
@ -9,7 +9,7 @@ const Game = struct {
|
||||
set_count: u32,
|
||||
};
|
||||
|
||||
fn parse_cube(cube_name: []const u8) ?Cube {
|
||||
fn parseCube(cube_name: []const u8) ?Cube {
|
||||
if (std.mem.eql(u8, cube_name, "blue")) {
|
||||
return .Blue;
|
||||
} else if (std.mem.eql(u8, cube_name, "red")) {
|
||||
@ -20,7 +20,7 @@ fn parse_cube(cube_name: []const u8) ?Cube {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn parse_game(game: *Game, line: []const u8) void {
|
||||
fn parseGame(game: *Game, line: []const u8) void {
|
||||
const colon = std.mem.indexOf(u8, line, ":") orelse @panic("Invalid line, missing ':'");
|
||||
|
||||
game.set_count = 0;
|
||||
@ -35,17 +35,17 @@ fn parse_game(game: *Game, line: []const u8) void {
|
||||
while (cubes.next()) |cube_count| {
|
||||
const space = std.mem.indexOf(u8, cube_count, " ") orelse @panic("Invalid format, expected space");
|
||||
|
||||
const cube = parse_cube(cube_count[(space+1)..]) orelse @panic("Invalid cube name");
|
||||
const cube = parseCube(cube_count[(space+1)..]) orelse @panic("Invalid cube name");
|
||||
const count = std.fmt.parseInt(u32, cube_count[0..space], 10) catch @panic("Invalid format");
|
||||
cube_set.set(cube, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_games(allocator: Allocator, lines: []const []const u8) ![]Game {
|
||||
fn parseGames(allocator: Allocator, lines: []const []const u8) ![]Game {
|
||||
var games = try allocator.alloc(Game, lines.len);
|
||||
for (0.., lines) |i, line| {
|
||||
parse_game(&games[i], line);
|
||||
parseGame(&games[i], line);
|
||||
}
|
||||
return games;
|
||||
}
|
||||
@ -54,7 +54,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
|
||||
const games = try parse_games(allocator, lines);
|
||||
const games = try parseGames(allocator, lines);
|
||||
defer allocator.free(games);
|
||||
|
||||
const max_red = 12;
|
||||
@ -81,7 +81,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
const games = try parse_games(allocator, lines);
|
||||
const games = try parseGames(allocator, lines);
|
||||
defer allocator.free(games);
|
||||
|
||||
var sum: u32 = 0;
|
||||
|
@ -66,12 +66,12 @@ const InternalModule = struct {
|
||||
inputs: []ModuleId,
|
||||
outputs: []ModuleId,
|
||||
|
||||
fn flip_flop(self: *@This()) bool {
|
||||
fn flipFlop(self: *@This()) bool {
|
||||
self.state.mask = ~self.state.mask;
|
||||
return self.state.mask != 0;
|
||||
}
|
||||
|
||||
fn update_input(self: *@This(), module_index: ModuleId, is_high: bool) bool {
|
||||
fn updateInput(self: *@This(), module_index: ModuleId, is_high: bool) bool {
|
||||
const index = std.mem.indexOfScalar(ModuleId, self.inputs, module_index);
|
||||
assert(index != null);
|
||||
|
||||
@ -80,7 +80,7 @@ const InternalModule = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn append_if_new(names: *std.ArrayList(NameString), name: NameString) !void {
|
||||
fn appendIfNew(names: *std.ArrayList(NameString), name: NameString) !void {
|
||||
for (names.items) |other_name| {
|
||||
if (std.mem.eql(u8, other_name.slice(), name.slice())) {
|
||||
return;
|
||||
@ -101,9 +101,9 @@ const MachineState = struct {
|
||||
var names = std.ArrayList(NameString).init(allocator);
|
||||
defer names.deinit();
|
||||
for (modules) |module| {
|
||||
try append_if_new(&names, module.name);
|
||||
try appendIfNew(&names, module.name);
|
||||
for (module.outputs.items) |output| {
|
||||
try append_if_new(&names, output);
|
||||
try appendIfNew(&names, output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,13 +122,13 @@ const MachineState = struct {
|
||||
});
|
||||
|
||||
for (modules) |module| {
|
||||
const module_idx = self.get_name_idx(module.name).?;
|
||||
const module_idx = self.getNameIndex(module.name).?;
|
||||
var internal_module = &self.state[module_idx];
|
||||
|
||||
internal_module.module_type = module.module_type;
|
||||
internal_module.outputs = try allocator.alloc(ModuleId, module.outputs.items.len);
|
||||
for (0.., module.outputs.items) |output_idx, output_name| {
|
||||
const index = self.get_name_idx(output_name);
|
||||
const index = self.getNameIndex(output_name);
|
||||
assert(index != null);
|
||||
internal_module.outputs[output_idx] = @intCast(index.?);
|
||||
}
|
||||
@ -171,7 +171,7 @@ const MachineState = struct {
|
||||
self.allocator.free(self.names);
|
||||
}
|
||||
|
||||
fn get_name_idx(self: MachineState, name: NameString) ?ModuleId {
|
||||
fn getNameIndex(self: MachineState, name: NameString) ?ModuleId {
|
||||
for (0.., self.names) |i, other_name| {
|
||||
if (std.mem.eql(u8, other_name.slice(), name.slice())) {
|
||||
return @intCast(i);
|
||||
@ -180,7 +180,7 @@ const MachineState = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn get_name(self: MachineState, id: ModuleId) []const u8 {
|
||||
fn getName(self: MachineState, id: ModuleId) []const u8 {
|
||||
return self.names[id].constSlice();
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ const MachineState = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_module(allocator: Allocator, line: []const u8) !Module {
|
||||
fn parseModule(allocator: Allocator, line: []const u8) !Module {
|
||||
var arrow_split_iter = std.mem.splitSequence(u8, line, "->");
|
||||
|
||||
const name_with_type = arrow_split_iter.next() orelse return error.NoName;
|
||||
@ -222,12 +222,12 @@ fn parse_module(allocator: Allocator, line: []const u8) !Module {
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
|
||||
for (lines) |line| {
|
||||
try parsed.modules.append(try parse_module(allocator, line));
|
||||
try parsed.modules.append(try parseModule(allocator, line));
|
||||
}
|
||||
|
||||
return parsed;
|
||||
@ -243,7 +243,7 @@ const PulseCount = struct {
|
||||
high: u64
|
||||
};
|
||||
|
||||
fn simulate_pulse(pulse_queue: *std.ArrayList(Pulse), machine_state: *MachineState, pulse: Pulse) !void {
|
||||
fn simulatePulse(pulse_queue: *std.ArrayList(Pulse), machine_state: *MachineState, pulse: Pulse) !void {
|
||||
var to_module = &machine_state.state[pulse.to];
|
||||
|
||||
var output_is_high = false;
|
||||
@ -251,9 +251,9 @@ fn simulate_pulse(pulse_queue: *std.ArrayList(Pulse), machine_state: *MachineSta
|
||||
output_is_high = pulse.is_high;
|
||||
} else if (to_module.module_type == .FlipFlop) {
|
||||
if (pulse.is_high) return;
|
||||
output_is_high = to_module.flip_flop();
|
||||
output_is_high = to_module.flipFlop();
|
||||
} else if (to_module.module_type == .Conjunction) {
|
||||
output_is_high = to_module.update_input(pulse.from, pulse.is_high);
|
||||
output_is_high = to_module.updateInput(pulse.from, pulse.is_high);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
@ -267,7 +267,7 @@ fn simulate_pulse(pulse_queue: *std.ArrayList(Pulse), machine_state: *MachineSta
|
||||
}
|
||||
}
|
||||
|
||||
fn simulate_button_press(allocator: Allocator, machine_state: *MachineState, broadcaster: ModuleId) !PulseCount {
|
||||
fn simulateButtonPress(allocator: Allocator, machine_state: *MachineState, broadcaster: ModuleId) !PulseCount {
|
||||
var pulses = std.ArrayList(Pulse).init(allocator);
|
||||
defer pulses.deinit();
|
||||
|
||||
@ -289,7 +289,7 @@ fn simulate_button_press(allocator: Allocator, machine_state: *MachineState, bro
|
||||
low_pulse_count += 1;
|
||||
}
|
||||
|
||||
try simulate_pulse(&pulses, machine_state, pulse);
|
||||
try simulatePulse(&pulses, machine_state, pulse);
|
||||
}
|
||||
|
||||
return .{ .low = low_pulse_count, .high = high_pulse_count };
|
||||
@ -297,18 +297,18 @@ fn simulate_button_press(allocator: Allocator, machine_state: *MachineState, bro
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var machine_state = try MachineState.init(allocator, parsed.modules.items);
|
||||
defer machine_state.deinit();
|
||||
|
||||
const broadcaster_idx = machine_state.get_name_idx(try NameString.fromSlice("broadcaster")).?;
|
||||
const broadcaster_idx = machine_state.getNameIndex(try NameString.fromSlice("broadcaster")).?;
|
||||
|
||||
var low_count: u64 = 0;
|
||||
var high_count: u64 = 0;
|
||||
for (0..1000) |_| {
|
||||
const high_low_count = try simulate_button_press(allocator, &machine_state, broadcaster_idx);
|
||||
const high_low_count = try simulateButtonPress(allocator, &machine_state, broadcaster_idx);
|
||||
low_count += high_low_count.low;
|
||||
high_count += high_low_count.high;
|
||||
}
|
||||
@ -337,7 +337,7 @@ const MachineAnalysis = struct {
|
||||
|
||||
const ModuleIdHashSet = std.AutoHashMap(ModuleId, void);
|
||||
|
||||
fn find_coverage(allocator: Allocator, machine_state: MachineState, from: ModuleId) !ModuleIdHashSet {
|
||||
fn findCoverage(allocator: Allocator, machine_state: MachineState, from: ModuleId) !ModuleIdHashSet {
|
||||
var seen = ModuleIdHashSet.init(allocator);
|
||||
errdefer seen.deinit();
|
||||
|
||||
@ -359,7 +359,7 @@ fn find_coverage(allocator: Allocator, machine_state: MachineState, from: Module
|
||||
return seen;
|
||||
}
|
||||
|
||||
fn analyze_machine(allocator: Allocator, machine_state: MachineState, input_module: ModuleId, output_module: ModuleId) !MachineAnalysis {
|
||||
fn analyzeMachine(allocator: Allocator, machine_state: MachineState, input_module: ModuleId, output_module: ModuleId) !MachineAnalysis {
|
||||
const counters = try allocator.alloc(MachineCounter, machine_state.state[input_module].outputs.len);
|
||||
errdefer allocator.free(counters);
|
||||
|
||||
@ -368,7 +368,7 @@ fn analyze_machine(allocator: Allocator, machine_state: MachineState, input_modu
|
||||
@memset(coverage_counts, 0);
|
||||
|
||||
for (0.., machine_state.state[input_module].outputs) |i, counter_input| {
|
||||
var coverage = try find_coverage(allocator, machine_state, counter_input);
|
||||
var coverage = try findCoverage(allocator, machine_state, counter_input);
|
||||
defer coverage.deinit();
|
||||
|
||||
{
|
||||
@ -441,7 +441,7 @@ fn analyze_machine(allocator: Allocator, machine_state: MachineState, input_modu
|
||||
};
|
||||
}
|
||||
|
||||
fn find_counter_cycle_size(allocator: Allocator, machine_state: *MachineState, counter: MachineCounter, input_module: ModuleId) !u64 {
|
||||
fn findCounterCycleSize(allocator: Allocator, machine_state: *MachineState, counter: MachineCounter, input_module: ModuleId) !u64 {
|
||||
machine_state.reset();
|
||||
|
||||
var pulses = std.ArrayList(Pulse).init(allocator);
|
||||
@ -463,7 +463,7 @@ fn find_counter_cycle_size(allocator: Allocator, machine_state: *MachineState, c
|
||||
if (pulse.to == counter.output) {
|
||||
if (!pulse.is_high) break :pulse_loop;
|
||||
} else {
|
||||
try simulate_pulse(&pulses, machine_state, pulse);
|
||||
try simulatePulse(&pulses, machine_state, pulse);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -477,21 +477,21 @@ fn lcm(a: u64, b: u64) u64 {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var machine_state = try MachineState.init(allocator, parsed.modules.items);
|
||||
defer machine_state.deinit();
|
||||
|
||||
const broadcaster_idx = machine_state.get_name_idx(try NameString.fromSlice("broadcaster")).?;
|
||||
const rx_idx = machine_state.get_name_idx(try NameString.fromSlice("rx")).?;
|
||||
const broadcaster_idx = machine_state.getNameIndex(try NameString.fromSlice("broadcaster")).?;
|
||||
const rx_idx = machine_state.getNameIndex(try NameString.fromSlice("rx")).?;
|
||||
|
||||
const analysis = try analyze_machine(allocator, machine_state, broadcaster_idx, rx_idx);
|
||||
const analysis = try analyzeMachine(allocator, machine_state, broadcaster_idx, rx_idx);
|
||||
defer analysis.deinit();
|
||||
|
||||
var answer: u64 = 1;
|
||||
for (analysis.counters) |counter| {
|
||||
const cycle_size = try find_counter_cycle_size(allocator, &machine_state, counter, broadcaster_idx);
|
||||
const cycle_size = try findCounterCycleSize(allocator, &machine_state, counter, broadcaster_idx);
|
||||
answer = lcm(answer, cycle_size);
|
||||
}
|
||||
|
||||
|
20
src/day3.zig
20
src/day3.zig
@ -5,7 +5,7 @@ const Point = @import("./point.zig").Point;
|
||||
const PointU32 = Point(u32);
|
||||
const PointList = std.ArrayList(PointU32);
|
||||
|
||||
fn find_number_start(line: []const u8, from: u32) u32 {
|
||||
fn findNumberStart(line: []const u8, from: u32) u32 {
|
||||
var i = from;
|
||||
while (i > 0) : (i -= 1) {
|
||||
if (!std.ascii.isDigit(line[i-1])) { break; }
|
||||
@ -13,7 +13,7 @@ fn find_number_start(line: []const u8, from: u32) u32 {
|
||||
return i;
|
||||
}
|
||||
|
||||
fn find_number_end(line: []const u8, from: u32) u32 {
|
||||
fn findNumberEnd(line: []const u8, from: u32) u32 {
|
||||
var i = from;
|
||||
while (i < line.len-1) : (i += 1) {
|
||||
if (!std.ascii.isDigit(line[i+1])) { break; }
|
||||
@ -21,14 +21,14 @@ fn find_number_end(line: []const u8, from: u32) u32 {
|
||||
return i+1;
|
||||
}
|
||||
|
||||
fn append_unique(list: *PointList, point: PointU32) !void {
|
||||
fn appendUnique(list: *PointList, point: PointU32) !void {
|
||||
for (list.items) |item| {
|
||||
if (item.eql(point)) { return; }
|
||||
}
|
||||
try list.append(point);
|
||||
}
|
||||
|
||||
fn find_neighbouring_numbers(found_list: *PointList, lines: []const []const u8, x: usize, y: usize) !void {
|
||||
fn findNeighbouringNumbers(found_list: *PointList, lines: []const []const u8, x: usize, y: usize) !void {
|
||||
const neighbours = .{
|
||||
.{ -1, -1 }, .{ 0, -1 }, .{ 1, -1 },
|
||||
.{ -1, 0 }, .{ 1, 0 },
|
||||
@ -42,8 +42,8 @@ fn find_neighbouring_numbers(found_list: *PointList, lines: []const []const u8,
|
||||
const nx_u32: u32 = @intCast(nx);
|
||||
const ny_u32: u32 = @intCast(ny);
|
||||
if (std.ascii.isDigit(lines[ny_u32][nx_u32])) {
|
||||
const number_start = find_number_start(lines[ny_u32], nx_u32);
|
||||
try append_unique(found_list, .{ .x = number_start, .y = ny_u32 });
|
||||
const number_start = findNumberStart(lines[ny_u32], nx_u32);
|
||||
try appendUnique(found_list, .{ .x = number_start, .y = ny_u32 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,14 +60,14 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
for (line, 0..) |c, x| {
|
||||
if (std.ascii.isDigit(c) or c == '.') { continue; }
|
||||
|
||||
try find_neighbouring_numbers(&numbers, lines, x, y);
|
||||
try findNeighbouringNumbers(&numbers, lines, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
var sum: u32 = 0;
|
||||
for (numbers.items) |number_pos| {
|
||||
const line = lines[number_pos.y];
|
||||
const number_end = find_number_end(line, number_pos.x);
|
||||
const number_end = findNumberEnd(line, number_pos.x);
|
||||
const number_str = line[number_pos.x..number_end];
|
||||
sum += try std.fmt.parseInt(u32, number_str, 10);
|
||||
}
|
||||
@ -87,14 +87,14 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var numbers = PointList.init(allocator);
|
||||
defer numbers.deinit();
|
||||
|
||||
try find_neighbouring_numbers(&numbers, lines, x, y);
|
||||
try findNeighbouringNumbers(&numbers, lines, x, y);
|
||||
|
||||
if (numbers.items.len != 2) continue;
|
||||
|
||||
var gear_ratio: u32 = 1;
|
||||
for (numbers.items) |number_pos| {
|
||||
const number_line = lines[number_pos.y];
|
||||
const number_end = find_number_end(number_line, number_pos.x);
|
||||
const number_end = findNumberEnd(number_line, number_pos.x);
|
||||
const number_str = number_line[number_pos.x..number_end];
|
||||
const number = try std.fmt.parseInt(u32, number_str, 10);
|
||||
gear_ratio *= number;
|
||||
|
12
src/day4.zig
12
src/day4.zig
@ -12,7 +12,7 @@ const Card = struct {
|
||||
|
||||
const CardArray = std.ArrayList(Card);
|
||||
|
||||
fn parse_numbers(result: *BoundedUintArray, text: []const u8) !void {
|
||||
fn parseNumbers(result: *BoundedUintArray, text: []const u8) !void {
|
||||
var i: usize = 0;
|
||||
var tokens = std.mem.tokenizeScalar(u8, text, ' ');
|
||||
while (tokens.next()) |token| : (i += 1) {
|
||||
@ -21,7 +21,7 @@ fn parse_numbers(result: *BoundedUintArray, text: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !CardArray {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !CardArray {
|
||||
var cards = CardArray.init(allocator);
|
||||
for (lines) |line| {
|
||||
var card = Card{
|
||||
@ -32,10 +32,10 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !CardArray {
|
||||
const bar = std.mem.indexOfScalar(u8, line, '|') orelse @panic("Invalid format");
|
||||
|
||||
const winning_str = line[(colon+2)..(bar-1)];
|
||||
try parse_numbers(&card.winning, winning_str);
|
||||
try parseNumbers(&card.winning, winning_str);
|
||||
|
||||
const mine_str = line[(bar+2)..];
|
||||
try parse_numbers(&card.mine, mine_str);
|
||||
try parseNumbers(&card.mine, mine_str);
|
||||
|
||||
try cards.append(card);
|
||||
}
|
||||
@ -45,7 +45,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !CardArray {
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const cards = try parse_input(allocator, input.lines);
|
||||
const cards = try parseInput(allocator, input.lines);
|
||||
defer cards.deinit();
|
||||
|
||||
var result: u32 = 0;
|
||||
@ -67,7 +67,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const cards = try parse_input(allocator, input.lines);
|
||||
const cards = try parseInput(allocator, input.lines);
|
||||
defer cards.deinit();
|
||||
|
||||
var multipliers = try allocator.alloc(u32, cards.items.len);
|
||||
|
40
src/day5.zig
40
src/day5.zig
@ -21,7 +21,7 @@ const Input = struct {
|
||||
temperature_to_humidity: MappingSet,
|
||||
humidity_to_location : MappingSet,
|
||||
|
||||
fn get_mappings(self: *const Input) [7]*const MappingSet {
|
||||
fn getMappings(self: *const Input) [7]*const MappingSet {
|
||||
return [_]*const MappingSet{
|
||||
&self.seed_to_soil,
|
||||
&self.soil_to_fertilizer,
|
||||
@ -34,7 +34,7 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_seeds(result: *SeedsArray, text: []const u8) !void {
|
||||
fn parseSeeds(result: *SeedsArray, text: []const u8) !void {
|
||||
var i: usize = 0;
|
||||
var tokens = std.mem.tokenizeScalar(u8, text, ' ');
|
||||
while (tokens.next()) |token| : (i += 1) {
|
||||
@ -43,7 +43,7 @@ fn parse_seeds(result: *SeedsArray, text: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_mapping_range(line: []const u8) !MappingRange {
|
||||
fn parseMappingRange(line: []const u8) !MappingRange {
|
||||
const first_space = std.mem.indexOfScalar(u8, line, ' ') orelse @panic("invalid format");
|
||||
const last_space = std.mem.lastIndexOfScalar(u8, line, ' ') orelse @panic("invalid format");
|
||||
|
||||
@ -54,7 +54,7 @@ fn parse_mapping_range(line: []const u8) !MappingRange {
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input(lines: []const []const u8) !Input {
|
||||
fn parseInput(lines: []const []const u8) !Input {
|
||||
var seeds = try SeedsArray.init(0);
|
||||
var mapping_sets: [7]MappingSet = undefined;
|
||||
for (&mapping_sets) |*set| {
|
||||
@ -62,7 +62,7 @@ fn parse_input(lines: []const []const u8) !Input {
|
||||
}
|
||||
|
||||
const seeds_colon = std.mem.indexOfScalar(u8, lines[0], ':') orelse @panic("invalid format");
|
||||
try parse_seeds(&seeds, lines[0][(seeds_colon+1)..]);
|
||||
try parseSeeds(&seeds, lines[0][(seeds_colon+1)..]);
|
||||
|
||||
var mappign_set_idx: u32 = 0;
|
||||
for (lines[2..]) |line| {
|
||||
@ -72,7 +72,7 @@ fn parse_input(lines: []const []const u8) !Input {
|
||||
continue;
|
||||
}
|
||||
|
||||
try mapping_sets[mappign_set_idx].append(try parse_mapping_range(line));
|
||||
try mapping_sets[mappign_set_idx].append(try parseMappingRange(line));
|
||||
}
|
||||
|
||||
return Input{
|
||||
@ -87,35 +87,35 @@ fn parse_input(lines: []const []const u8) !Input {
|
||||
};
|
||||
}
|
||||
|
||||
fn is_in_range(x: u64, range_start: u64, range_size: u64) bool {
|
||||
fn isInRange(x: u64, range_start: u64, range_size: u64) bool {
|
||||
return range_start <= x and x < (range_start + range_size);
|
||||
}
|
||||
|
||||
fn apply_mapping(src: u64, mapping_set: *const MappingSet) u64 {
|
||||
fn applyMapping(src: u64, mapping_set: *const MappingSet) u64 {
|
||||
for (mapping_set.slice()) |mapping| {
|
||||
if (is_in_range(src, mapping.src_start, mapping.size)) {
|
||||
if (isInRange(src, mapping.src_start, mapping.size)) {
|
||||
return mapping.dest_start + (src - mapping.src_start);
|
||||
}
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
fn apply_seed_to_location(seed: u64, input: *const Input) u64 {
|
||||
const mapping_sequence = input.get_mappings();
|
||||
fn applySeedToLocation(seed: u64, input: *const Input) u64 {
|
||||
const mapping_sequence = input.getMappings();
|
||||
|
||||
var value = seed;
|
||||
inline for (mapping_sequence) |mapping_set| {
|
||||
value = apply_mapping(value, mapping_set);
|
||||
value = applyMapping(value, mapping_set);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.lines);
|
||||
const parsed = try parseInput(input.lines);
|
||||
|
||||
var lowest_location: ?u64 = null;
|
||||
for (parsed.seeds.slice()) |seed| {
|
||||
const value = apply_seed_to_location(seed, &parsed);
|
||||
const value = applySeedToLocation(seed, &parsed);
|
||||
|
||||
if (lowest_location) |location| {
|
||||
lowest_location = @min(location, value);
|
||||
@ -127,7 +127,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
return .{ .uint = @intCast(lowest_location.?) };
|
||||
}
|
||||
|
||||
fn remove_range(mapping_set: *MappingSet, from: u64, to: u64) !void {
|
||||
fn removeRange(mapping_set: *MappingSet, from: u64, to: u64) !void {
|
||||
for (0.., mapping_set.slice()) |i, *range| {
|
||||
const range_start = range.src_start;
|
||||
const range_end = range.src_start + range.size-1;
|
||||
@ -155,7 +155,7 @@ fn remove_range(mapping_set: *MappingSet, from: u64, to: u64) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_mapping_to_range_set(src_set: *MappingSet, mapping_set: *const MappingSet) !void {
|
||||
fn applyMappingToRangeSet(src_set: *MappingSet, mapping_set: *const MappingSet) !void {
|
||||
var new_src_set = try MappingSet.init(0);
|
||||
var unmapped_ranges = try MappingSet.init(0);
|
||||
try unmapped_ranges.appendSlice(src_set.slice());
|
||||
@ -169,7 +169,7 @@ fn apply_mapping_to_range_set(src_set: *MappingSet, mapping_set: *const MappingS
|
||||
|
||||
const src_start = src.src_start + (overlap_start - src.dest_start);
|
||||
const overlap_size = (overlap_end - overlap_start) + 1;
|
||||
try remove_range(&unmapped_ranges, src_start, src_start+overlap_size-1);
|
||||
try removeRange(&unmapped_ranges, src_start, src_start+overlap_size-1);
|
||||
|
||||
try new_src_set.append(MappingRange{
|
||||
.src_start = src_start,
|
||||
@ -184,7 +184,7 @@ fn apply_mapping_to_range_set(src_set: *MappingSet, mapping_set: *const MappingS
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.lines);
|
||||
const parsed = try parseInput(input.lines);
|
||||
|
||||
var seed_to_location = try MappingSet.init(0);
|
||||
for (0..(parsed.seeds.len/2)) |i| {
|
||||
@ -197,8 +197,8 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
});
|
||||
}
|
||||
|
||||
inline for (parsed.get_mappings()) |mapping_set| {
|
||||
try apply_mapping_to_range_set(&seed_to_location, mapping_set);
|
||||
inline for (parsed.getMappings()) |mapping_set| {
|
||||
try applyMappingToRangeSet(&seed_to_location, mapping_set);
|
||||
}
|
||||
var lowest_location: ?u64 = null;
|
||||
for (seed_to_location.slice()) |range| {
|
||||
|
12
src/day6.zig
12
src/day6.zig
@ -9,7 +9,7 @@ const Input = struct {
|
||||
distance: BoundedU32,
|
||||
};
|
||||
|
||||
fn parse_numbers(result: *BoundedU32, text: []const u8) !void {
|
||||
fn parseNumbers(result: *BoundedU32, text: []const u8) !void {
|
||||
var i: usize = 0;
|
||||
var tokens = std.mem.tokenizeScalar(u8, text, ' ');
|
||||
while (tokens.next()) |token| : (i += 1) {
|
||||
@ -18,17 +18,17 @@ fn parse_numbers(result: *BoundedU32, text: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_input(lines: []const []const u8) !Input {
|
||||
fn parseInput(lines: []const []const u8) !Input {
|
||||
var time = try BoundedU32.init(0);
|
||||
var distance = try BoundedU32.init(0);
|
||||
try parse_numbers(&time, lines[0][9..]);
|
||||
try parse_numbers(&distance, lines[1][9..]);
|
||||
try parseNumbers(&time, lines[0][9..]);
|
||||
try parseNumbers(&distance, lines[1][9..]);
|
||||
assert(time.len == distance.len);
|
||||
return Input{ .time = time, .distance = distance };
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
var parsed = try parse_input(input.lines);
|
||||
var parsed = try parseInput(input.lines);
|
||||
|
||||
var answer: u32 = 1;
|
||||
for (0..parsed.time.len) |i| {
|
||||
@ -58,7 +58,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
var parsed = try parse_input(input.lines);
|
||||
var parsed = try parseInput(input.lines);
|
||||
|
||||
var allowed_time: u64 = 0;
|
||||
var required_distance: u64 = 0;
|
||||
|
42
src/day7.zig
42
src/day7.zig
@ -28,7 +28,7 @@ const CardCounts = [CARD_VARIANTS]CardIndex;
|
||||
const IndexArray = std.ArrayList(usize);
|
||||
const HandBids = std.ArrayList(HandBid);
|
||||
|
||||
fn hand_to_str(hand: Hand) [5]u8 {
|
||||
fn handToStr(hand: Hand) [5]u8 {
|
||||
var str = [1]u8{0} ** 5;
|
||||
for (0..hand.len) |i| {
|
||||
str[i] = switch (hand[i]) {
|
||||
@ -51,7 +51,7 @@ fn hand_to_str(hand: Hand) [5]u8 {
|
||||
return str;
|
||||
}
|
||||
|
||||
fn get_card_index(char: u8) CardIndex {
|
||||
fn getCardIndex(char: u8) CardIndex {
|
||||
return switch (char) {
|
||||
'A' => 12,
|
||||
'K' => 11,
|
||||
@ -70,7 +70,7 @@ fn get_card_index(char: u8) CardIndex {
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !HandBids {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !HandBids {
|
||||
var hand_bids = HandBids.init(allocator);
|
||||
|
||||
for (lines) |line| {
|
||||
@ -82,7 +82,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !HandBids {
|
||||
|
||||
var hand_bid = HandBid{ .bid = bid };
|
||||
for (0..5) |i| {
|
||||
hand_bid.hand[i] = get_card_index(hand_str[i]);
|
||||
hand_bid.hand[i] = getCardIndex(hand_str[i]);
|
||||
}
|
||||
|
||||
try hand_bids.append(hand_bid);
|
||||
@ -91,7 +91,7 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !HandBids {
|
||||
return hand_bids;
|
||||
}
|
||||
|
||||
fn count_cards(hand: Hand) CardCounts {
|
||||
fn countCards(hand: Hand) CardCounts {
|
||||
var counts = [1]CardIndex{0} ** CARD_VARIANTS;
|
||||
for (hand) |card| {
|
||||
counts[card] += 1;
|
||||
@ -99,8 +99,8 @@ fn count_cards(hand: Hand) CardCounts {
|
||||
return counts;
|
||||
}
|
||||
|
||||
fn determine_card_strength(hand: Hand) HandStrength {
|
||||
const counts = count_cards(hand);
|
||||
fn determineCardStrength(hand: Hand) HandStrength {
|
||||
const counts = countCards(hand);
|
||||
|
||||
var ones_count: u4 = 0;
|
||||
var two_count: u4 = 0;
|
||||
@ -135,8 +135,8 @@ fn determine_card_strength(hand: Hand) HandStrength {
|
||||
return .Nothing;
|
||||
}
|
||||
|
||||
fn determine_card_strength_joker(hand: Hand) HandStrength {
|
||||
const joker_card = comptime get_card_index('J');
|
||||
fn determineCardStrengthJoker(hand: Hand) HandStrength {
|
||||
const joker_card = comptime getCardIndex('J');
|
||||
|
||||
var jokers = std.BoundedArray(usize, 5).init(0) catch unreachable;
|
||||
var card_types = std.BoundedArray(CardIndex, 5).init(0) catch unreachable;
|
||||
@ -150,7 +150,7 @@ fn determine_card_strength_joker(hand: Hand) HandStrength {
|
||||
}
|
||||
|
||||
if (jokers.len == 0) {
|
||||
return determine_card_strength(hand);
|
||||
return determineCardStrength(hand);
|
||||
}
|
||||
|
||||
var joker_choices_container = [1]usize{0} ** 5;
|
||||
@ -166,7 +166,7 @@ fn determine_card_strength_joker(hand: Hand) HandStrength {
|
||||
modified_hand[jokers.get(i)] = card_types.get(joker_choices[i]);
|
||||
}
|
||||
|
||||
const strength = determine_card_strength(modified_hand);
|
||||
const strength = determineCardStrength(modified_hand);
|
||||
|
||||
best_strength = @enumFromInt(@max(@intFromEnum(best_strength), @intFromEnum(strength)));
|
||||
|
||||
@ -182,7 +182,7 @@ fn determine_card_strength_joker(hand: Hand) HandStrength {
|
||||
return best_strength;
|
||||
}
|
||||
|
||||
fn compare_hands(a: *Hand, b: *Hand) bool {
|
||||
fn compareHands(a: *Hand, b: *Hand) bool {
|
||||
inline for (0..a.len) |i| {
|
||||
if (a[i] != b[i]) {
|
||||
return a[i] > b[i];
|
||||
@ -191,8 +191,8 @@ fn compare_hands(a: *Hand, b: *Hand) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn compare_hands_joker(a: *Hand, b: *Hand) bool {
|
||||
const joker_card = comptime get_card_index('J');
|
||||
fn compareHandsJoker(a: *Hand, b: *Hand) bool {
|
||||
const joker_card = comptime getCardIndex('J');
|
||||
|
||||
inline for (0..a.len) |i| {
|
||||
if (a[i] != b[i]) {
|
||||
@ -204,7 +204,7 @@ fn compare_hands_joker(a: *Hand, b: *Hand) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn sort_same_strength(hands: []Hand, indexes: []usize, cmp: *const fn(*Hand, *Hand) bool) void {
|
||||
fn sortSameStrength(hands: []Hand, indexes: []usize, cmp: *const fn(*Hand, *Hand) bool) void {
|
||||
for (0..(indexes.len-1)) |i| {
|
||||
for ((i+1)..indexes.len) |j| {
|
||||
const hand_a = &hands[indexes[i]];
|
||||
@ -218,7 +218,7 @@ fn sort_same_strength(hands: []Hand, indexes: []usize, cmp: *const fn(*Hand, *Ha
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const hand_bids = try parse_input(allocator, input.lines);
|
||||
const hand_bids = try parseInput(allocator, input.lines);
|
||||
defer hand_bids.deinit();
|
||||
|
||||
var hand_strengths = try allocator.alloc(HandStrength, hand_bids.items.len);
|
||||
@ -229,7 +229,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
for (0..hand_bids.items.len) |i| {
|
||||
hands[i] = hand_bids.items[i].hand;
|
||||
hand_strengths[i] = determine_card_strength(hand_bids.items[i].hand);
|
||||
hand_strengths[i] = determineCardStrength(hand_bids.items[i].hand);
|
||||
}
|
||||
|
||||
var order = try IndexArray.initCapacity(allocator, hand_bids.items.len);
|
||||
@ -249,7 +249,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
}
|
||||
|
||||
if (sub_order.items.len != 0) {
|
||||
sort_same_strength(hands, sub_order.items, compare_hands);
|
||||
sortSameStrength(hands, sub_order.items, compareHands);
|
||||
order.appendSliceAssumeCapacity(sub_order.items);
|
||||
}
|
||||
}
|
||||
@ -264,7 +264,7 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const hand_bids = try parse_input(allocator, input.lines);
|
||||
const hand_bids = try parseInput(allocator, input.lines);
|
||||
defer hand_bids.deinit();
|
||||
|
||||
var hand_strengths = try allocator.alloc(HandStrength, hand_bids.items.len);
|
||||
@ -275,7 +275,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
for (0..hand_bids.items.len) |i| {
|
||||
hands[i] = hand_bids.items[i].hand;
|
||||
hand_strengths[i] = determine_card_strength_joker(hand_bids.items[i].hand);
|
||||
hand_strengths[i] = determineCardStrengthJoker(hand_bids.items[i].hand);
|
||||
}
|
||||
|
||||
var order = try IndexArray.initCapacity(allocator, hand_bids.items.len);
|
||||
@ -295,7 +295,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
}
|
||||
|
||||
if (sub_order.items.len != 0) {
|
||||
sort_same_strength(hands, sub_order.items, compare_hands_joker);
|
||||
sortSameStrength(hands, sub_order.items, compareHandsJoker);
|
||||
order.appendSliceAssumeCapacity(sub_order.items);
|
||||
}
|
||||
}
|
||||
|
74
src/day8.zig
74
src/day8.zig
@ -39,7 +39,7 @@ const NodeMapLeaf = struct {
|
||||
nodes: std.ArrayList(NodeSplit)
|
||||
};
|
||||
|
||||
fn parse_instructions(allocator: Allocator, line: []const u8) !DirectionList {
|
||||
fn parseInstructions(allocator: Allocator, line: []const u8) !DirectionList {
|
||||
var instructions = DirectionList.init(allocator);
|
||||
errdefer instructions.deinit();
|
||||
for (line) |c| {
|
||||
@ -53,7 +53,7 @@ fn parse_instructions(allocator: Allocator, line: []const u8) !DirectionList {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
fn parse_char_to_node_part(c: u8) NodePart {
|
||||
fn parseCharToNodePart(c: u8) NodePart {
|
||||
if (std.ascii.isAlphabetic(c)) {
|
||||
assert(std.ascii.isUpper(c));
|
||||
return @intCast(c - 'A' + 10);
|
||||
@ -64,17 +64,17 @@ fn parse_char_to_node_part(c: u8) NodePart {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_node_label(text: []const u8) NodeLabel {
|
||||
fn parseNodeLabel(text: []const u8) NodeLabel {
|
||||
assert(text.len == 3);
|
||||
|
||||
var label: NodeLabel = undefined;
|
||||
inline for (0..3) |i| {
|
||||
label[i] = parse_char_to_node_part(text[i]);
|
||||
label[i] = parseCharToNodePart(text[i]);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
fn parse_nodes(allocator: Allocator, lines: []const []const u8) !NodeJunctionList {
|
||||
fn parseNodes(allocator: Allocator, lines: []const []const u8) !NodeJunctionList {
|
||||
var nodes = try NodeJunctionList.initCapacity(allocator, lines.len);
|
||||
errdefer nodes.deinit();
|
||||
|
||||
@ -83,26 +83,26 @@ fn parse_nodes(allocator: Allocator, lines: []const []const u8) !NodeJunctionLis
|
||||
const left_str = line[7..10];
|
||||
const right_str = line[12..15];
|
||||
nodes.appendAssumeCapacity(NodeJunction{
|
||||
.from = parse_node_label(from_str),
|
||||
.left = parse_node_label(left_str),
|
||||
.right = parse_node_label(right_str),
|
||||
.from = parseNodeLabel(from_str),
|
||||
.left = parseNodeLabel(left_str),
|
||||
.right = parseNodeLabel(right_str),
|
||||
});
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
const instructions = try parse_instructions(allocator, lines[0]);
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
const instructions = try parseInstructions(allocator, lines[0]);
|
||||
errdefer instructions.deinit();
|
||||
|
||||
const nodes = try parse_nodes(allocator, lines[2..]);
|
||||
const nodes = try parseNodes(allocator, lines[2..]);
|
||||
errdefer nodes.deinit();
|
||||
|
||||
return Input{ .instructions = instructions, .nodes = nodes };
|
||||
}
|
||||
|
||||
fn node_map_find_branch(node_map: *NodeMap, branch_name: NodePart) ?*NodeMapBranch {
|
||||
fn nodeMapFindBranch(node_map: *NodeMap, branch_name: NodePart) ?*NodeMapBranch {
|
||||
for (node_map.items) |*branch| {
|
||||
if (branch.name == branch_name) {
|
||||
return branch;
|
||||
@ -111,7 +111,7 @@ fn node_map_find_branch(node_map: *NodeMap, branch_name: NodePart) ?*NodeMapBran
|
||||
return null;
|
||||
}
|
||||
|
||||
fn node_leaf_find_split(node_leaf: *NodeMapLeaf, name: NodePart) ?*NodeSplit {
|
||||
fn nodeLeafFindSplit(node_leaf: *NodeMapLeaf, name: NodePart) ?*NodeSplit {
|
||||
for (node_leaf.nodes.items) |*split| {
|
||||
if (split.name == name) {
|
||||
return split;
|
||||
@ -120,7 +120,7 @@ fn node_leaf_find_split(node_leaf: *NodeMapLeaf, name: NodePart) ?*NodeSplit {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn node_branch_find_leaf(node_branch: *NodeMapBranch, leaf_name: NodePart) ?*NodeMapLeaf {
|
||||
fn nodeBranchFindLeaf(node_branch: *NodeMapBranch, leaf_name: NodePart) ?*NodeMapLeaf {
|
||||
for (node_branch.nodes.items) |*leaf| {
|
||||
if (leaf.name == leaf_name) {
|
||||
return leaf;
|
||||
@ -129,13 +129,13 @@ fn node_branch_find_leaf(node_branch: *NodeMapBranch, leaf_name: NodePart) ?*Nod
|
||||
return null;
|
||||
}
|
||||
|
||||
fn create_node_map(allocator: Allocator, nodes: NodeJunctionList) !NodeMap {
|
||||
fn createNodeMap(allocator: Allocator, nodes: NodeJunctionList) !NodeMap {
|
||||
var node_map = NodeMap.init(allocator);
|
||||
errdefer free_node_map(node_map);
|
||||
errdefer freeNodeMap(node_map);
|
||||
|
||||
for (nodes.items) |node_junction| {
|
||||
const from = node_junction.from;
|
||||
var node_branch_opt = node_map_find_branch(&node_map, from[0]);
|
||||
var node_branch_opt = nodeMapFindBranch(&node_map, from[0]);
|
||||
if (node_branch_opt == null) {
|
||||
try node_map.append(NodeMapBranch{
|
||||
.name = from[0],
|
||||
@ -145,7 +145,7 @@ fn create_node_map(allocator: Allocator, nodes: NodeJunctionList) !NodeMap {
|
||||
}
|
||||
var node_branch = node_branch_opt.?;
|
||||
|
||||
var node_leaf_opt = node_branch_find_leaf(node_branch, from[1]);
|
||||
var node_leaf_opt = nodeBranchFindLeaf(node_branch, from[1]);
|
||||
if (node_leaf_opt == null) {
|
||||
try node_branch.nodes.append(NodeMapLeaf{
|
||||
.name = from[1],
|
||||
@ -165,7 +165,7 @@ fn create_node_map(allocator: Allocator, nodes: NodeJunctionList) !NodeMap {
|
||||
return node_map;
|
||||
}
|
||||
|
||||
fn free_node_map(node_map: NodeMap) void {
|
||||
fn freeNodeMap(node_map: NodeMap) void {
|
||||
for (node_map.items) |branch| {
|
||||
for (branch.nodes.items) |leaf| {
|
||||
leaf.nodes.deinit();
|
||||
@ -175,16 +175,16 @@ fn free_node_map(node_map: NodeMap) void {
|
||||
node_map.deinit();
|
||||
}
|
||||
|
||||
fn node_map_lookup(node_map: *NodeMap, from: NodeLabel, direction: Direction) ?NodeLabel {
|
||||
const branch_opt = node_map_find_branch(node_map, from[0]);
|
||||
fn nodeMapLookup(node_map: *NodeMap, from: NodeLabel, direction: Direction) ?NodeLabel {
|
||||
const branch_opt = nodeMapFindBranch(node_map, from[0]);
|
||||
if (branch_opt == null) return null;
|
||||
const branch = branch_opt.?;
|
||||
|
||||
const leaf_opt = node_branch_find_leaf(branch, from[1]);
|
||||
const leaf_opt = nodeBranchFindLeaf(branch, from[1]);
|
||||
if (leaf_opt == null) return null;
|
||||
const leaf = leaf_opt.?;
|
||||
|
||||
const split_opt = node_leaf_find_split(leaf, from[2]);
|
||||
const split_opt = nodeLeafFindSplit(leaf, from[2]);
|
||||
if (split_opt == null) return null;
|
||||
const split = split_opt.?;
|
||||
|
||||
@ -196,33 +196,33 @@ fn node_map_lookup(node_map: *NodeMap, from: NodeLabel, direction: Direction) ?N
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var node_map = try create_node_map(arena.allocator(), parsed.nodes);
|
||||
defer free_node_map(node_map);
|
||||
var node_map = try createNodeMap(arena.allocator(), parsed.nodes);
|
||||
defer freeNodeMap(node_map);
|
||||
|
||||
var steps: u32 = 0;
|
||||
var goal = comptime parse_node_label("ZZZ");
|
||||
var current = comptime parse_node_label("AAA");
|
||||
var goal = comptime parseNodeLabel("ZZZ");
|
||||
var current = comptime parseNodeLabel("AAA");
|
||||
while (!std.mem.eql(NodePart, ¤t, &goal)) {
|
||||
const instruction = parsed.instructions.items[steps % parsed.instructions.items.len];
|
||||
current = node_map_lookup(&node_map, current, instruction) orelse @panic("dead end");
|
||||
current = nodeMapLookup(&node_map, current, instruction) orelse @panic("dead end");
|
||||
steps += 1;
|
||||
}
|
||||
|
||||
return .{ .uint = steps };
|
||||
}
|
||||
|
||||
fn find_steps_needed(node_map: *NodeMap, instructions: []const Direction, start: NodeLabel) u32 {
|
||||
fn findStepsNeeded(node_map: *NodeMap, instructions: []const Direction, start: NodeLabel) u32 {
|
||||
var steps: u32 = 0;
|
||||
var current = start;
|
||||
while (current[2] != comptime parse_char_to_node_part('Z')) {
|
||||
while (current[2] != comptime parseCharToNodePart('Z')) {
|
||||
const instruction = instructions[steps % instructions.len];
|
||||
current = node_map_lookup(node_map, current, instruction) orelse @panic("dead end");
|
||||
current = nodeMapLookup(node_map, current, instruction) orelse @panic("dead end");
|
||||
steps += 1;
|
||||
}
|
||||
return steps;
|
||||
@ -234,21 +234,21 @@ fn lcm(a: u64, b: u64) u64 {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
const parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var node_map = try create_node_map(arena.allocator(), parsed.nodes);
|
||||
defer free_node_map(node_map);
|
||||
var node_map = try createNodeMap(arena.allocator(), parsed.nodes);
|
||||
defer freeNodeMap(node_map);
|
||||
|
||||
var all_steps = std.ArrayList(u32).init(allocator);
|
||||
defer all_steps.deinit();
|
||||
|
||||
for (parsed.nodes.items) |node_junction| {
|
||||
if (node_junction.from[2] == comptime parse_char_to_node_part('A')) {
|
||||
const steps = find_steps_needed(&node_map, parsed.instructions.items, node_junction.from);
|
||||
if (node_junction.from[2] == comptime parseCharToNodePart('A')) {
|
||||
const steps = findStepsNeeded(&node_map, parsed.instructions.items, node_junction.from);
|
||||
try all_steps.append(steps);
|
||||
}
|
||||
}
|
||||
|
34
src/day9.zig
34
src/day9.zig
@ -16,7 +16,7 @@ const Input = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_history(allocator: Allocator, line: []const u8) !History {
|
||||
fn parseHistory(allocator: Allocator, line: []const u8) !History {
|
||||
var history = History.init(allocator);
|
||||
var tokens = std.mem.tokenizeScalar(u8, line, ' ');
|
||||
while (tokens.next()) |token| {
|
||||
@ -26,19 +26,19 @@ fn parse_history(allocator: Allocator, line: []const u8) !History {
|
||||
return history;
|
||||
}
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var histories = std.ArrayList(History).init(allocator);
|
||||
errdefer histories.deinit();
|
||||
|
||||
for (lines) |line| {
|
||||
const history = try parse_history(allocator, line);
|
||||
const history = try parseHistory(allocator, line);
|
||||
try histories.append(history);
|
||||
}
|
||||
|
||||
return Input{ .histories = histories };
|
||||
}
|
||||
|
||||
fn is_all_zeros(numbers: []i32) bool {
|
||||
fn isAllZeros(numbers: []i32) bool {
|
||||
for (numbers) |num| {
|
||||
if (num != 0) {
|
||||
return false;
|
||||
@ -47,34 +47,34 @@ fn is_all_zeros(numbers: []i32) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn calc_changes(result: []i32, numbers: []i32) void {
|
||||
fn calcChanges(result: []i32, numbers: []i32) void {
|
||||
assert(result.len >= numbers.len-1);
|
||||
for (0..(numbers.len-1)) |i| {
|
||||
result[i] = numbers[i+1] - numbers[i];
|
||||
}
|
||||
}
|
||||
|
||||
fn all_changes_of_history(allocator: Allocator, history: []i32) !HistoryChanges {
|
||||
fn allChangesOfHistory(allocator: Allocator, history: []i32) !HistoryChanges {
|
||||
const max_changes_len: usize = history.len-1;
|
||||
assert(max_changes_len >= 1);
|
||||
|
||||
var changes = HistoryChanges.init(allocator);
|
||||
errdefer free_history_changes(changes);
|
||||
errdefer freeHistoryChanges(changes);
|
||||
|
||||
try changes.append(try allocator.alloc(i32, history.len-1));
|
||||
calc_changes(changes.items[0], history);
|
||||
calcChanges(changes.items[0], history);
|
||||
|
||||
for (1..max_changes_len) |i| {
|
||||
if (is_all_zeros(changes.items[i-1])) break;
|
||||
if (isAllZeros(changes.items[i-1])) break;
|
||||
|
||||
try changes.append(try allocator.alloc(i32, history.len-i-1));
|
||||
calc_changes(changes.items[i], changes.items[i-1]);
|
||||
calcChanges(changes.items[i], changes.items[i-1]);
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
fn free_history_changes(changes: HistoryChanges) void {
|
||||
fn freeHistoryChanges(changes: HistoryChanges) void {
|
||||
for (changes.items) |row| {
|
||||
changes.allocator.free(row);
|
||||
}
|
||||
@ -83,15 +83,15 @@ fn free_history_changes(changes: HistoryChanges) void {
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var parsed = try parse_input(allocator, input.lines);
|
||||
var parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: i32 = 0;
|
||||
for (parsed.histories.items) |history| {
|
||||
const numbers = history.items;
|
||||
|
||||
const changes = try all_changes_of_history(allocator, numbers);
|
||||
defer free_history_changes(changes);
|
||||
const changes = try allChangesOfHistory(allocator, numbers);
|
||||
defer freeHistoryChanges(changes);
|
||||
|
||||
var prediction: i32 = numbers[numbers.len-1];
|
||||
for (changes.items) |change_row| {
|
||||
@ -106,15 +106,15 @@ pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const allocator = input.allocator;
|
||||
var parsed = try parse_input(allocator, input.lines);
|
||||
var parsed = try parseInput(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var result: i32 = 0;
|
||||
for (parsed.histories.items) |history| {
|
||||
const numbers = history.items;
|
||||
|
||||
const changes = try all_changes_of_history(allocator, numbers);
|
||||
defer free_history_changes(changes);
|
||||
const changes = try allChangesOfHistory(allocator, numbers);
|
||||
defer freeHistoryChanges(changes);
|
||||
|
||||
var prediction: i32 = 0;
|
||||
for (0..changes.items.len) |i| {
|
||||
|
@ -8,7 +8,7 @@ const Input = struct {
|
||||
fn deinit(self: Input) void { _ = self; }
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
fn parseInput(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
const parsed = Input {
|
||||
.allocator = allocator,
|
||||
};
|
||||
@ -20,14 +20,14 @@ fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
const parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
return .{ .uint = 0 };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
const parsed = try parseInput(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
return .{ .uint = 0 };
|
||||
|
@ -41,6 +41,7 @@ const Days = [_]aoc.Day{
|
||||
create_day(@import("./day18.zig")),
|
||||
create_day(@import("./day19.zig")),
|
||||
create_day(@import("./day20.zig")),
|
||||
create_day(@import("./day21.zig")),
|
||||
};
|
||||
|
||||
fn kilobytes(count: u32) u32 {
|
||||
@ -204,4 +205,5 @@ test {
|
||||
_ = @import("./day18.zig");
|
||||
_ = @import("./day19.zig");
|
||||
_ = @import("./day20.zig");
|
||||
_ = @import("./day21.zig");
|
||||
}
|
||||
|
@ -41,14 +41,14 @@ pub fn Point(comptime T: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn to_i32(self: Self) Point(i32) {
|
||||
pub fn toI32(self: Self) Point(i32) {
|
||||
return Point(i32){
|
||||
.x = @intCast(self.x),
|
||||
.y = @intCast(self.y),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn to_u32(self: Self) Point(u32) {
|
||||
pub fn toU32(self: Self) Point(u32) {
|
||||
return Point(u32){
|
||||
.x = @intCast(self.x),
|
||||
.y = @intCast(self.y),
|
||||
|
Loading…
Reference in New Issue
Block a user