Solutions of most (39 out of 50 so far) puzzles in Zig (system language, alternative for C). My first experience with it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.6 KiB

const std = @import("std");
const Char = enum(u4) {
Zero = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Dot = 12,
Symbol = 13,
};
const CharInfo = struct {
adjacents: [8]Char,
this: Char,
fn isAdjacentToSymbol(self: *const CharInfo) bool {
for (0..8) |i| {
if (self.adjacents[i] == .Symbol) {
return true;
}
}
return false;
}
};
const State = struct {
number: u32 = 0,
is_adjacent_to_symbol: bool = false,
fn addDigit(self: *State, char_info: CharInfo) void {
self.number = self.number * 10 + @intFromEnum(char_info.this);
self.is_adjacent_to_symbol = self.is_adjacent_to_symbol or char_info.isAdjacentToSymbol();
}
};
fn solve(engine: [][]const CharInfo) u32 {
var result: u32 = 0;
var current_state = State{};
for (engine) |line| {
//std.debug.print("handling new line\n", .{});
for (line) |char_info| {
//std.debug.print("handling: {s}({s})\n", .{ [_]u8{char_info.this}, char_info.adjacents });
switch (char_info.this) {
.Zero, .One, .Two, .Three, .Four, .Five, .Six, .Seven, .Eight, .Nine => {
current_state.addDigit(char_info);
},
.Dot, .Symbol => {
if (current_state.is_adjacent_to_symbol) {
//std.debug.print("adding: {d}\n", .{current_state.number});
result += current_state.number;
}
current_state = State{};
},
}
}
if (current_state.is_adjacent_to_symbol) {
//std.debug.print("end of line; adding: {d}\n", .{current_state.number});
result += current_state.number;
}
current_state = State{};
}
return result;
}
fn charLinesToCharInfoLines(allocator: std.mem.Allocator, char_lines: [][]const Char) ![][]const CharInfo {
var char_info_lines = try allocator.alloc([]CharInfo, char_lines.len);
for (0..char_lines.len) |i| {
const char_line = char_lines[i];
var char_info_line = try allocator.alloc(CharInfo, char_line.len);
for (0..char_line.len) |j| {
char_info_line[j] = CharInfo{ .this = char_line[j], .adjacents = .{
if (i > 0 and j > 0) char_lines[i - 1][j - 1] else .Dot,
if (i > 0) char_lines[i - 1][j] else .Dot,
if (i > 0 and j + 1 < char_line.len) char_lines[i - 1][j + 1] else .Dot,
if (j > 0) char_line[j - 1] else .Dot,
if (j + 1 < char_line.len) char_line[j + 1] else .Dot,
if (i + 1 < char_lines.len and j > 0) char_lines[i + 1][j - 1] else .Dot,
if (i + 1 < char_lines.len) char_lines[i + 1][j] else .Dot,
if (i + 1 < char_lines.len and j + 1 < char_line.len) char_lines[i + 1][j + 1] else .Dot,
} };
}
char_info_lines[i] = char_info_line;
}
return char_info_lines;
}
fn readInput(allocator: std.mem.Allocator, reader: anytype) ![][]const Char {
var lines = std.ArrayList([]Char).init(allocator);
var line_buffer: [1000]u8 = undefined;
while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line_ref| {
var line = try allocator.alloc(Char, line_ref.len);
for (line_ref, line) |raw_char, *char| {
char.* = switch (raw_char) {
'0'...'9' => @enumFromInt(raw_char - '0'),
'.' => .Dot,
else => .Symbol,
};
}
try lines.append(line);
}
return lines.items;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const raw_in = std.io.getStdIn();
var buffered_reader = std.io.bufferedReader(raw_in.reader());
var reader = buffered_reader.reader();
var allocator_buffer: [1_000_000]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&allocator_buffer);
var allocator = fba.allocator();
var lines_arena = std.heap.ArenaAllocator.init(allocator);
const lines_allocator = lines_arena.allocator();
const char_lines = try readInput(lines_allocator, reader);
var info_lines_arena = std.heap.ArenaAllocator.init(allocator);
const info_lines_allocator = info_lines_arena.allocator();
const info_lines = try charLinesToCharInfoLines(info_lines_allocator, char_lines);
lines_arena.deinit();
const result = solve(info_lines);
info_lines_arena.deinit();
try stdout.print("{d}\n", .{result});
}