Initially my first solution was doing what was asked for in part two, because i misunderstood the task.
Solution-1
const std = @import(βstdβ);
//const input = @embedFile(β./small.inpβ);
const input = @embedFile(β./big.inpβ);
fn digit2number(digit: u8) i8 {
switch (digit) {
β1β => return 1,
β2β => return 2,
β3β => return 3,
β4β => return 4,
β5β => return 5,
β6β => return 6,
β7β => return 7,
β8β => return 8,
β9β => return 9,
β0β => return 0,
β.β => return -1,
else => unreachable,
}
}
const peak_t = struct { irow: usize, icol: usize, reached: bool };
const grid_t = struct {
nrows: usize,
ncols: usize,
vals: std.ArrayList(i8),
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
const grid = Self{
.nrows = 0,
.ncols = 0,
.vals = std.ArrayList(i8).init(allocator),
};
return grid;
}
pub fn deinit(self: *Self) void {
self.nrows = 0;
self.ncols = 0;
_ = self.vals.deinit();
}
pub fn get_pos(self: Self, irow: usize, icol: usize) ?i8 {
if (irow < self.nrows and icol < self.ncols) {
return self.vals.items[irow * self.ncols + icol];
}
return null;
}
pub fn read(self: *Self, inputstr: []const u8) !void {
var lines = std.mem.tokenizeScalar(u8, inputstr, '\n');
while (lines.next()) |line| {
self.nrows += 1;
for (line) |char| {
try self.vals.append(digit2number(char));
}
}
self.ncols = self.vals.items.len / self.nrows;
}
pub fn print(self: Self) void {
std.debug.print("\n", .{});
std.debug.print("{d}x{d}\n", .{ self.nrows, self.ncols });
for (0..self.nrows) |irow| {
for (0..self.ncols) |icol| {
const maybe_pos = self.get_pos(irow, icol);
if (maybe_pos) |pos| {
if (pos >= 0) {
std.debug.print("{d}", .{pos});
} else {
std.debug.print(".", .{});
}
}
}
std.debug.print("\n", .{});
}
}
pub fn find_reachable_peaks(self: Self, irow: usize, icol: usize, expect_height: i8, peaks: *std.ArrayList(peak_t)) void {
const maybe_pos = self.get_pos(irow, icol);
if (maybe_pos) |pos| {
// tested position matches
if (pos == expect_height) {
// finished exploration
if (pos == 9) {
for (peaks.items) |*peak| {
if (peak.irow == irow and peak.icol == icol) {
peak.reached = true;
}
}
} else {
if (irow < self.nrows - 1) {
self.find_reachable_peaks(irow + 1, icol, expect_height + 1, peaks);
}
if (irow > 0) {
self.find_reachable_peaks(irow - 1, icol, expect_height + 1, peaks);
}
if (icol < self.ncols - 1) {
self.find_reachable_peaks(irow, icol + 1, expect_height + 1, peaks);
}
if (icol > 0) {
self.find_reachable_peaks(irow, icol - 1, expect_height + 1, peaks);
}
}
}
}
}
pub fn get_score(self: Self, irow: usize, icol: usize, peaks: *std.ArrayList(peak_t)) i32 {
self.find_reachable_peaks(irow, icol, 0, peaks);
var score: i32 = 0;
for (peaks.items) |*peak| {
if (peak.reached) {
score += 1;
peak.reached = false;
}
}
return score;
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var grid = grid_t.init(allocator);
defer _ = grid.deinit();
try grid.read(input);
grid.print();
// create list of peaks
var peaks = std.ArrayList(peak_t).init(allocator);
defer _ = peaks.deinit();
for (0..grid.nrows) |irow| {
for (0..grid.ncols) |icol| {
const maybe_pos = grid.get_pos(irow, icol);
if (maybe_pos) |pos| {
if (pos == 9) {
try peaks.append(peak_t{ .irow = irow, .icol = icol, .reached = false });
}
}
}
}
var sum: i32 = 0;
for (0..grid.nrows) |irow| {
for (0..grid.ncols) |icol| {
const maybe_pos = grid.get_pos(irow, icol);
if (maybe_pos) |pos| {
// check if trail head
if (pos == 0) {
const score: i32 = grid.get_score(irow, icol, &peaks);
//std.debug.print("Score({d},{d}) = {d}\n", .{ irow, icol, score });
sum += score;
}
}
}
}
std.debug.print("Sum of scores: {d}\n", .{sum});
}
Solution-2
const std = @import(βstdβ);
//const input = @embedFile(β./small.inpβ);
const input = @embedFile(β./big.inpβ);
fn digit2number(digit: u8) i8 {
switch (digit) {
β1β => return 1,
β2β => return 2,
β3β => return 3,
β4β => return 4,
β5β => return 5,
β6β => return 6,
β7β => return 7,
β8β => return 8,
β9β => return 9,
β0β => return 0,
β.β => return -1,
else => unreachable,
}
}
const grid_t = struct {
nrows: usize,
ncols: usize,
vals: std.ArrayList(i8),
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
const grid = Self{
.nrows = 0,
.ncols = 0,
.vals = std.ArrayList(i8).init(allocator),
};
return grid;
}
pub fn deinit(self: *Self) void {
self.nrows = 0;
self.ncols = 0;
_ = self.vals.deinit();
}
pub fn get_pos(self: Self, irow: usize, icol: usize) ?i8 {
if (irow < self.nrows and icol < self.ncols) {
return self.vals.items[irow * self.ncols + icol];
}
return null;
}
pub fn read(self: *Self, inputstr: []const u8) !void {
var lines = std.mem.tokenizeScalar(u8, inputstr, '\n');
while (lines.next()) |line| {
self.nrows += 1;
for (line) |char| {
try self.vals.append(digit2number(char));
}
}
self.ncols = self.vals.items.len / self.nrows;
}
pub fn print(self: Self) void {
std.debug.print("\n", .{});
std.debug.print("{d}x{d}\n", .{ self.nrows, self.ncols });
for (0..self.nrows) |irow| {
for (0..self.ncols) |icol| {
const maybe_pos = self.get_pos(irow, icol);
if (maybe_pos) |pos| {
if (pos >= 0) {
std.debug.print("{d}", .{pos});
} else {
std.debug.print(".", .{});
}
}
}
std.debug.print("\n", .{});
}
}
pub fn score_path(self: Self, irow: usize, icol: usize, expect_height: i8) i32 {
var score: i32 = 0;
const maybe_pos = self.get_pos(irow, icol);
if (maybe_pos) |pos| {
// tested position matches
if (pos == expect_height) {
// finished exploration
if (pos == 9) {
score += 1;
} else {
if (irow < self.nrows - 1) {
score += self.score_path(irow + 1, icol, expect_height + 1);
}
if (irow > 0) {
score += self.score_path(irow - 1, icol, expect_height + 1);
}
if (icol < self.ncols - 1) {
score += self.score_path(irow, icol + 1, expect_height + 1);
}
if (icol > 0) {
score += self.score_path(irow, icol - 1, expect_height + 1);
}
}
}
}
return score;
}
pub fn get_score(self: Self, irow: usize, icol: usize) i32 {
return self.score_path(irow, icol, 0);
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var grid = grid_t.init(allocator);
defer _ = grid.deinit();
try grid.read(input);
grid.print();
var sum: i32 = 0;
for (0..grid.nrows) |irow| {
for (0..grid.ncols) |icol| {
const maybe_pos = grid.get_pos(irow, icol);
if (maybe_pos) |pos| {
// check if trail head
if (pos == 0) {
const score: i32 = grid.get_score(irow, icol);
//std.debug.print("Score({d},{d}) = {d}\n", .{ irow, icol, score });
sum += score;
}
}
}
}
std.debug.print("Sum of scores: {d}\n", .{sum});
}