From ed16c41c9c7948dacccccf7555ff3c6c41e064a7 Mon Sep 17 00:00:00 2001 From: Dustin Swan Date: Mon, 25 Dec 2023 21:04:40 -0700 Subject: [PATCH] Adding some unfinished days --- day12/index.js | 71 ++++++++++++++ day12/main.zig | 87 +++++++++++++++++ day17/main.zig | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ day18/main.zig | 232 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 644 insertions(+) create mode 100644 day12/index.js create mode 100644 day12/main.zig create mode 100644 day17/main.zig create mode 100644 day18/main.zig diff --git a/day12/index.js b/day12/index.js new file mode 100644 index 0000000..63dbe7f --- /dev/null +++ b/day12/index.js @@ -0,0 +1,71 @@ +const fs = require("node:fs"); + +let data; +try { + data = fs.readFileSync("test.txt", "utf8"); +} catch (err) { + return +} + +const lines = data.trim().split("\n"); +var part1 = 0; +var part2 = 0; + +lines.forEach((l) => { + const parts = l.split(" "); + const map = parts[0]; + const damaged = parts[1].split(",").map(Number); + // const all = allArrangements(map) + // const valid = all.filter((m) => isValid(m, damaged)); + // part1 += valid.length; + + const map2 = [map, map, map, map, map].join("?"); + const damaged2 = [damaged, damaged, damaged, damaged, damaged].flat(); + // console.log(damaged2); + const all2 = allValidArrangements(map2, damaged2); + console.log("all2", all2); + part2 += all2.length; +}); + +// console.log("part1", part1); +console.log("part2", part1); + +function allValidArrangements(map, damaged, index = 0) { + const i = map.substring(index).indexOf("?"); + if (i === -1) { + return map; + } + + const one = allValidArrangements(replaceAt(map, i + index, "#"), damaged, index + 1); + const two = allValidArrangements(replaceAt(map, i + index, "."), damaged, index + 1); + return [one, two].flat(); +} + + +function allArrangements(map, index = 0) { + const i = map.substring(index).indexOf("?"); + if (i === -1) { + return map; + } + + const one = allArrangements(replaceAt(map, i + index, "#"), index + 1); + const two = allArrangements(replaceAt(map, i + index, "."), index + 1); + return [one, two].flat(); +} + +function replaceAt(str, index, replacement) { + return str.substring(0, index) + replacement + str.substring(index + replacement.length); +} + +function isValid(map, damaged) { + const trimmed = map.replace(/^\.+/, "").replace(/\.+$/, ""); + const parts = trimmed.split(/\.+/); + let isValid = parts.length === damaged.length; + damaged.forEach((d, i) => { + if (!parts[i] || parts[i].length !== d) { + isValid = false; + } + }); + + return isValid; +} diff --git a/day12/main.zig b/day12/main.zig new file mode 100644 index 0000000..63e23aa --- /dev/null +++ b/day12/main.zig @@ -0,0 +1,87 @@ +const std = @import("std"); + +const Record = struct { map: []const u8, damaged: std.ArrayList(u8) }; + +pub fn main() !void { + const content = @embedFile("test.txt"); + var lines = std.mem.split(u8, content, "\n"); + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + + var records = std.ArrayList(Record).init(allocator); + defer records.deinit(); + + // parse lines + while (lines.next()) |line| { + if (line.len < 1) { + break; + } + var parts = std.mem.split(u8, line, " "); + const map = parts.next().?; + var damageIterator = std.mem.split(u8, parts.next().?, ","); + var damaged = std.ArrayList(u8).init(allocator); + while (damageIterator.next()) |d| { + const parsed = try std.fmt.parseInt(u8, d, 10); + try damaged.append(parsed); + } + try records.append(Record{ .map = map, .damaged = damaged }); + } + std.debug.print("records: {any}\n", .{records.items}); + + var part1: u8 = 0; + for (records.items) |r| { + // var all = std.ArrayList(u8).init(allocator); + const all = allArrangements(r.map, r.damaged, 0); + std.debug.print("all arrangements: {any}\n", .{all}); + + // part1 += numValid(r); + } + + std.debug.print("Part1: {d}\n", .{part1}); +} + +// replaces ?s with every possible combination of . or # +// fn allArrangements(r: Record, i: u8) []const u8 { +fn allArrangements(map: []const u8, damaged: std.ArrayList(u8), start: u8) []const u8 { + std.debug.print("allArrangements. map: {any} damage: {any} start: {any}\n", .{ map, damaged, start }); + // find the first ? + const idx = std.mem.indexOf(u8, map, "?"); + if (idx == null) { + return map; + } + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + + var records = std.ArrayList(Record).init(allocator); + defer records.deinit(); + + var one: [map.len]u8 = undefined; + @memcpy(one, map); + std.debug.print("? idx: {?d}\n", .{idx}); + return &[_]u8{1}; +} + +fn numValid(r: Record) u8 { + // var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + // const allocator = gpa.allocator(); + // + // // generate all possible arrangements + // var all = std.ArrayList(u8).init(allocator); + // defer all.deinit(); + + const num = numQuestionMarks(r.map); + std.debug.print("num ?: {d}\n", .{num}); + return num; +} + +fn numQuestionMarks(str: []const u8) u8 { + var i: u8 = 0; + for (str) |char| { + if (char == '?') { + i += 1; + } + } + return i; +} diff --git a/day17/main.zig b/day17/main.zig new file mode 100644 index 0000000..2cc4e93 --- /dev/null +++ b/day17/main.zig @@ -0,0 +1,254 @@ +const std = @import("std"); + +const Dir = enum(usize) { up, right, down, left }; +const Coord = struct { row: usize, col: usize }; +const Beam = struct { dir: Dir, coord: Coord }; + +pub fn main() !void { + var content = @embedFile("test.txt"); + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + + var grid = std.ArrayList(std.ArrayList(u8)).init(allocator); + defer grid.deinit(); + + var lines = std.mem.split(u8, content, "\n"); + + while (lines.next()) |line| { + if (line.len < 1) { + break; + } + + var lineArrayList = std.ArrayList(u8).init(allocator); + + for (line) |char| { + try lineArrayList.append(char); + } + + try grid.append(lineArrayList); + } + + const energy = try energize(Beam{ .dir = Dir.right, .coord = Coord{ .row = 0, .col = 0 } }, grid); + + std.debug.print("Part 1: {d}\n", .{energy}); + + const height = grid.items.len; + const width = grid.items[0].items.len; + + var maxEnergy: usize = 0; + + for (0..height) |row| { + for ([_]usize{ 0, width - 1 }) |col| { + const dir = if (col == 0) Dir.right else Dir.left; + const start = Beam{ .dir = dir, .coord = Coord{ .row = row, .col = col } }; + const e = try energize(start, grid); + if (e > maxEnergy) { + maxEnergy = e; + } + } + } + + for (0..width) |col| { + for ([_]usize{ 0, height - 1 }) |row| { + const dir = if (row == 0) Dir.down else Dir.up; + const start = Beam{ .dir = dir, .coord = Coord{ .row = row, .col = col } }; + const e = try energize(start, grid); + if (e > maxEnergy) { + maxEnergy = e; + } + } + } + + std.debug.print("Part 2: {d}\n", .{maxEnergy}); +} + +fn energize(start: Beam, grid: std.ArrayList(std.ArrayList(u8))) !usize { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + + var beams = std.ArrayList(Beam).init(allocator); + defer beams.deinit(); + + // add the first beam + try beams.append(start); + + var energized = std.AutoHashMap(Coord, void).init(allocator); + defer energized.deinit(); + + var beamHistory = std.AutoHashMap(Beam, void).init(allocator); + defer beamHistory.deinit(); + + const height = grid.items.len; + const width = grid.items[0].items.len; + + while (true) { + // make 2 new lists: beams to add, and beams to remove. + // batch these while iterating, and do it all after + var beamsToAdd = std.ArrayList(Beam).init(allocator); + defer beamsToAdd.deinit(); + + var beamsToRemove = std.ArrayList(usize).init(allocator); + defer beamsToRemove.deinit(); + + if (beams.items.len == 0) { + break; + } + + for ((&beams).items, 0..) |*b, beamNumber| { + if (isOutOfGrid(b, grid)) { + try beamsToRemove.append(beamNumber); + continue; + } + + try energized.put(b.coord, {}); + + if (beamHistory.contains(b.*)) { + try beamsToRemove.append(beamNumber); + continue; + } + + try beamHistory.put(b.*, {}); + + const row = b.coord.row; + const col = b.coord.col; + + const value = grid.items[row].items[col]; + + const goStraight = value == '.' or (value == '|' and (b.dir == .up or b.dir == .down)) or + (value == '-' and (b.dir == .left or b.dir == .right)); + + if (goStraight) { + switch (b.dir) { + .up => if (row == 0) { + b.coord.row = height + 10; // put it out of the grid to get cleaned up + } else { + b.coord.row -= 1; + }, + .right => b.coord.col += 1, + .down => b.coord.row += 1, + .left => if (col == 0) { + b.coord.col = width + 10; // put it out of the grid to get cleaned up + } else { + b.coord.col -= 1; + }, + } + } else if (value == '|') { + if (row == 0) { + // if we are on the top row, change the beam to go down + b.dir = Dir.down; + b.coord.row += 1; + } else { + // otherwise, change beam direction to up and move it up one cell + b.dir = Dir.up; + b.coord.row -= 1; + if (row != height - 1) { + // and if we're not on the _bottom_ row, + // create a new beam going down, below this cell + const newBeam = Beam{ .dir = Dir.down, .coord = Coord{ .row = row + 1, .col = col } }; + try beamsToAdd.append(newBeam); + } + } + } else if (value == '-') { + if (col == 0) { + // if we are on the first col, change the beam to go right + b.dir = Dir.right; + b.coord.col += 1; + } else { + // otherwise, change beam direction to left and move it left one cell + b.dir = Dir.left; + b.coord.col -= 1; + if (col != width - 1) { + // and if we're not on the _last_ column, + // create a new beam going right, to the right this cell + const newBeam = Beam{ .dir = Dir.right, .coord = Coord{ .row = row, .col = col + 1 } }; + try beamsToAdd.append(newBeam); + } + } + } else if (value == '/') { + switch (b.dir) { + .up => { + b.dir = Dir.right; + b.coord.col += 1; + }, + .right => if (row == 0) { + b.coord.row = height + 10; // put it out of the grid to get cleaned up + } else { + b.dir = Dir.up; + b.coord.row -= 1; + }, + .down => if (col == 0) { + b.coord.row = height + 10; // put it out of the grid to get cleaned up + } else { + b.dir = Dir.left; + b.coord.col -= 1; + }, + .left => { + b.dir = Dir.down; + b.coord.row += 1; + }, + } + } else if (value == '\\') { + switch (b.dir) { + .up => if (col == 0) { + b.coord.col = width + 10; // put it out of the grid to get cleaned up + } else { + b.dir = Dir.left; + b.coord.col -= 1; + }, + .right => { + b.dir = Dir.down; + b.coord.row += 1; + }, + .down => { + b.dir = Dir.right; + b.coord.col += 1; + }, + .left => if (row == 0) { + b.coord.row = height + 10; // put it out of the grid to get cleaned up + } else { + b.dir = Dir.up; + b.coord.row -= 1; + }, + } + } + } + + // remove the beams in reverse order + const len = beamsToRemove.items.len; + for (0..len) |j| { + const idx = beamsToRemove.items[len - j - 1]; + _ = beams.orderedRemove(idx); + } + beamsToRemove.clearAndFree(); + + // add the new beams + for (beamsToAdd.items) |beam| { + try beams.append(beam); + } + beamsToAdd.clearAndFree(); + } + + return energized.count(); +} + +fn isOutOfGrid(beam: *Beam, grid: std.ArrayList(std.ArrayList(u8))) bool { + const row = beam.coord.row; + const col = beam.coord.col; + const height = grid.items.len; + const width = grid.items[0].items.len; + return row < 0 or row >= height or col < 0 or col >= width; +} + +fn printGrid(grid: std.ArrayList(std.ArrayList(u8)), energized: std.AutoHashMap(Coord, void)) void { + for (grid.items, 0..) |line, row| { + for (line.items, 0..) |char, col| { + if (char == '.' and energized.contains(Coord{ .row = row, .col = col })) { + std.debug.print("#", .{}); + } else { + std.debug.print("{c}", .{char}); + } + } + std.debug.print("\n", .{}); + } +} diff --git a/day18/main.zig b/day18/main.zig new file mode 100644 index 0000000..994fb56 --- /dev/null +++ b/day18/main.zig @@ -0,0 +1,232 @@ +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", .{}); + } +}