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.
175 lines
4.4 KiB
175 lines
4.4 KiB
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});
|
|
}
|
|
|