Advent of Code 2024: Day 4
$ zig version 0.13.0
This problem requires looking for two kinds of pattern on a grid of characters. There are no new Zig features here to discuss.
Final Program
const std = @import("std"); pub fn main() !void { // get allocator var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const allocator = arena.allocator(); defer _ = arena.deinit(); // get command-line args const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); // see if filename is on command-line if (args.len == 2) { const filename = args[1]; solveDay(allocator, filename) catch |err| { switch (err) { error.FileNotFound => { std.debug.print("Error: File {s} was not found.\n", .{filename}); std.process.exit(1); }, else => { std.debug.print("Error: in processing file.\n", .{} ); std.process.exit(1); }, } }; } else { std.debug.print("Provide a filename of input data.\n", .{}); } } fn solveDay (allocator: std.mem.Allocator, filename: []const u8) !void { var grid = std.ArrayList([]const u8).init(allocator); defer grid.deinit(); try readData (allocator, filename, &grid); std.debug.print("Part 1: {d}\n", .{part1(&grid)}); std.debug.print("Part 2: {d}\n", .{part2(&grid)}); } fn part1 (grid: *std.ArrayList([]const u8)) usize { var total: usize = 0; for (grid.items, 0..) |_, row| { for (grid.items[row], 0..) |_, col| { // look for xmas/samx in four directions if (foundXmas(grid, row, col, 1, 0)) { total += 1; } if (foundXmas(grid, row, col, 0, 1)) { total += 1; } if (foundXmas(grid, row, col, 1, 1)) { total += 1; } // can't do this last one without a negative direction, so call directly if (isXmas(safe_get(grid, row, col+3), safe_get(grid, row+1, col+2), safe_get(grid, row+2, col+1), safe_get(grid, row+3, col))) { total += 1; } } } return total; } fn part2 (grid: *std.ArrayList([]const u8)) usize { var total: usize = 0; for (grid.items, 0..) |_, row| { for (grid.items[row], 0..) |_, col| { // look for mas centred on (+1, +1) if (('A' == safe_get(grid, row + 1, col + 1)) and isMAndS(safe_get(grid, row, col), safe_get(grid, row + 2, col + 2)) and isMAndS(safe_get(grid, row + 2, col), safe_get(grid, row, col + 2))) { total += 1; } } } return total; } fn isXmas (charA: u8, charB: u8, charC: u8, charD: u8) bool { return ('X' == charA and 'M' == charB and 'A' == charC and 'S' == charD) or ('X' == charD and 'M' == charC and 'A' == charB and 'S' == charA); } fn foundXmas(grid: *std.ArrayList([] const u8), row: usize, col: usize, rowDelta: usize, colDelta: usize) bool { return isXmas(safe_get(grid, row, col), safe_get(grid, row + rowDelta, col + colDelta), safe_get(grid, row + rowDelta + rowDelta, col + colDelta + colDelta), safe_get(grid, row + rowDelta + rowDelta + rowDelta, col + colDelta + colDelta + colDelta)); } fn isMAndS (charA: u8, charB: u8) bool { return ('M' == charA and 'S' == charB) or ('S' == charA and 'M' == charB); } // When (row,col) within grid bounds, return char at that point, else return '.'. fn safe_get (grid: *std.ArrayList([]const u8), row: usize, col: usize) u8 { if (0 <= row and row < grid.items.len and 0 <= col and col < grid.items[row].len) { return grid.items[row][col]; } else { return '.'; } } fn readData (allocator: std.mem.Allocator, filename: []const u8, grid: *std.ArrayList([]const u8)) !void { const file = try std.fs.cwd().openFile(filename, .{}); defer file.close(); const stat = try file.stat(); const data = try file.readToEndAlloc(allocator, stat.size); var lines = std.mem.tokenizeScalar(u8, data, '\n'); while (lines.next()) |line| { try grid.append(line); } }