You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
6.7 KiB
Zig

const std = @import("std");
const Point = struct { row: i32, col: i32 };
const Direction = enum(usize) { up, right, down, left };
const Instruction = struct { direction: Direction, distance: usize };
pub fn main() !void {
var content = @embedFile("test.txt");
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
var path = std.AutoHashMap(Point, void).init(allocator);
defer path.deinit();
var instructions = std.ArrayList(Instruction).init(allocator);
defer instructions.deinit();
try parseInstructions(content, &instructions);
var minCol: i32 = 0;
var maxCol: i32 = 0;
var minRow: i32 = 0;
var maxRow: i32 = 0;
var row: i32 = 0;
var col: i32 = 0;
for (instructions.items) |ins| {
for (0..ins.distance) |_| {
try path.put(Point{ .row = row, .col = col }, {});
if (row > maxRow) {
maxRow = row;
}
if (row < minRow) {
minRow = row;
}
if (col > maxCol) {
maxCol = col;
}
if (col < minCol) {
minCol = col;
}
if (ins.direction == Direction.up) {
row -= 1;
} else if (ins.direction == Direction.right) {
col += 1;
} else if (ins.direction == Direction.down) {
row += 1;
} else {
col -= 1;
}
}
}
std.debug.print("min row:{d}, max row: {d}\n", .{ minRow, maxRow });
std.debug.print("min col:{d}, max col: {d}\n", .{ minCol, maxCol });
// guess at finding a spot inside
var inside = Point{ .row = @divFloor(maxRow - minRow, 2), .col = @divFloor(maxCol - minCol, 2) };
var filled = try path.clone();
defer filled.deinit();
std.debug.print("count pre: {d}\n", .{path.count()});
try fill(&filled, inside);
std.debug.print("count post: {d}\n", .{filled.count()});
// printGrid(filled);
// Part 2
var path2 = std.AutoHashMap(Point, void).init(allocator);
defer path2.deinit();
var instructions2 = std.ArrayList(Instruction).init(allocator);
defer instructions2.deinit();
try parseInstructions2(content, &instructions2);
minCol = 0;
maxCol = 0;
minRow = 0;
maxRow = 0;
row = 0;
col = 0;
for (instructions2.items) |ins| {
for (0..ins.distance) |_| {
try path2.put(Point{ .row = row, .col = col }, {});
if (row > maxRow) {
maxRow = row;
}
if (row < minRow) {
minRow = row;
}
if (col > maxCol) {
maxCol = col;
}
if (col < minCol) {
minCol = col;
}
if (ins.direction == Direction.up) {
row -= 1;
} else if (ins.direction == Direction.right) {
col += 1;
} else if (ins.direction == Direction.down) {
row += 1;
} else {
col -= 1;
}
}
}
std.debug.print("min row:{d}, max row: {d}\n", .{ minRow, maxRow });
std.debug.print("min col:{d}, max col: {d}\n", .{ minCol, maxCol });
// guess at finding a spot inside
inside = Point{ .row = @divFloor(maxRow - minRow, 2), .col = @divFloor(maxCol - minCol, 2) };
var filled2 = try path2.clone();
defer filled2.deinit();
std.debug.print("count pre: {d}\n", .{path2.count()});
try fill(&filled2, inside);
std.debug.print("count post: {d}\n", .{filled2.count()});
}
fn fill(grid: *std.AutoHashMap(Point, void), point: Point) !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
var toVisit = std.ArrayList(Point).init(allocator);
defer toVisit.deinit();
try toVisit.append(point);
while (toVisit.items.len > 0) {
const p = toVisit.pop();
// std.debug.print("Looping in fill. point: {any}\n", .{p});
const ns = [_]Point{ Point{ .row = p.row - 1, .col = p.col }, Point{ .row = p.row + 1, .col = p.col }, Point{ .row = p.row, .col = p.col + 1 }, Point{ .row = p.row, .col = p.col - 1 } };
for (ns) |px| {
if (!grid.contains(px)) {
try grid.put(px, {});
// try fill(grid, px);
try toVisit.append(px);
}
}
}
}
fn parseInstructions(content: []const u8, instructions: *std.ArrayList(Instruction)) !void {
var lines = std.mem.split(u8, content, "\n");
while (lines.next()) |line| {
if (line.len < 1) {
break;
}
var parts = std.mem.split(u8, line, " ");
const dirString = parts.next().?;
var direction: Direction = undefined;
if (std.mem.eql(u8, dirString, "U")) {
direction = Direction.up;
} else if (std.mem.eql(u8, dirString, "R")) {
direction = Direction.right;
} else if (std.mem.eql(u8, dirString, "D")) {
direction = Direction.down;
} else if (std.mem.eql(u8, dirString, "L")) {
direction = Direction.left;
} else {
unreachable;
}
const distance = std.fmt.parseInt(u8, parts.next().?, 10);
const instruction = Instruction{ .direction = direction, .distance = try distance };
try instructions.*.append(instruction);
}
}
fn parseInstructions2(content: []const u8, instructions: *std.ArrayList(Instruction)) !void {
var lines = std.mem.split(u8, content, "\n");
while (lines.next()) |line| {
if (line.len < 1) {
break;
}
var hex = line[6..12];
const dirString = hex[5..6];
var direction: Direction = undefined;
if (std.mem.eql(u8, dirString, "0")) {
direction = Direction.right;
} else if (std.mem.eql(u8, dirString, "1")) {
direction = Direction.down;
} else if (std.mem.eql(u8, dirString, "2")) {
direction = Direction.left;
} else if (std.mem.eql(u8, dirString, "3")) {
direction = Direction.up;
} else {
unreachable;
}
const distance = try std.fmt.parseInt(usize, hex[0..5], 16);
const instruction = Instruction{ .direction = direction, .distance = distance };
try instructions.append(instruction);
}
}
fn printGrid(grid: std.AutoHashMap(Point, void)) void {
for (0..300) |row| {
for (0..300) |col| {
if (grid.contains(Point{ .row = @as(i32, @intCast(row)) - 43, .col = @as(i32, @intCast(col)) - 5 })) {
std.debug.print("#", .{});
} else {
std.debug.print(".", .{});
}
}
std.debug.print("\n", .{});
}
}