const std = @import("std"); fn StackList(comptime T: type, comptime capacity_type: type, comptime capacity: capacity_type) type { return struct { const Self = @This(); mem: [capacity]T, length: capacity_type, fn add(self: *Self, value: T) void { self.mem[self.length] = value; self.length += 1; } fn has(self: *Self, needle: T) bool { for (0..self.length) |i| { if (self.mem[i] == needle) { return true; } } return false; } fn getMutableSlice(self: *Self) []T { return (&self.mem)[0..self.length]; } fn getSlice(self: *const Self) []const T { return self.mem[0..self.length]; } fn init() Self { return Self{ .mem = undefined, .length = 0, }; } }; } fn addDigit(result: anytype, digit: u8) void { result.* = (result.* * 10) + (digit - '0'); } fn canStartWithGroup(springs: []const u8, group_size: usize) bool { if (springs.len < group_size) { return false; } if (springs.len > group_size and springs[group_size] == '#') { return false; } var i: usize = 0; while (i < group_size) : (i += 1) { if (springs[i] == '.') { return false; } } return true; } const State = [128][32]u64; fn solve(springs: []const u8, groups: []const usize, state: *State) u64 { if (state[springs.len][groups.len] != std.math.maxInt(u64)) { return state[springs.len][groups.len]; } if (groups.len == 0) { for (springs) |char| { if (char == '#') { state[springs.len][groups.len] = 0; return 0; } } state[springs.len][groups.len] = 1; return 1; } const first_group_size = groups[0]; if (first_group_size > springs.len) { state[springs.len][groups.len] = 0; return 0; } const last_check_index = springs.len + 1 - first_group_size; var i: usize = 0; var result: u64 = 0; while (i < last_check_index) : (i += 1) { switch (springs[i]) { '.' => {}, '#' => { if (canStartWithGroup(springs[i..], first_group_size)) { result += solve(springs[@min(springs.len, i + first_group_size + 1)..], groups[1..], &(state.*)); } break; }, '?' => { if (canStartWithGroup(springs[i..], first_group_size)) { result += solve(springs[@min(springs.len, i + first_group_size + 1)..], groups[1..], &(state.*)); } }, else => unreachable, } } state[springs.len][groups.len] = result; return result; } fn solveLine(line: []const u8) u64 { var i: usize = 0; while (line[i] != ' ') : (i += 1) {} var springs = line[0..i]; i += 1; var groups = StackList(usize, usize, 31).init(); while (i < line.len) { var number: usize = 0; while (i < line.len and line[i] != ',') : (i += 1) { addDigit(&number, line[i]); } groups.add(number); i += 1; } const groups_length = groups.length; for (0..4) |j| { _ = j; for (0..groups_length) |k| { groups.add(groups.mem[k]); } } var all_springs = StackList(u8, usize, 120).init(); for (0..5) |j| { if (j != 0) { all_springs.add('?'); } for (springs) |char| { all_springs.add(char); } } var state: State = undefined; for (&state) |*row| { for (row) |*cell| { cell.* = std.math.maxInt(u64); } } return solve(all_springs.getSlice(), groups.getSlice(), &state); } 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 result: u64 = 0; var line_buffer: [1000]u8 = undefined; var line_number: usize = 0; while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line| { result += solveLine(line); line_number += 1; } try stdout.print("{d}\n", .{result}); }