diff --git a/inputs/20/real.txt b/inputs/20/real.txt new file mode 100644 index 0000000..f06d288 --- /dev/null +++ b/inputs/20/real.txt @@ -0,0 +1,141 @@ +############################################################################################################################################# +#...........#...###...#.....#.........#...#.......###.........###...#...#...#...#.........#...###.....###.....#...#...#...#...#...#...###...# +#.#########.#.#.###.#.#.###.#.#######.#.#.#.#####.###.#######.###.#.#.#.#.#.#.#.#.#######.#.#.###.###.###.###.#.#.#.#.#.#.#.#.#.#.#.#.###.#.# +#...#.......#.#.#...#.#...#.#.......#...#.#.#.....#...#.......#...#...#.#.#...#.#...#.....#.#.#...#...#...#...#.#...#...#.#.#.#.#...#...#.#.# +###.#.#######.#.#.###.###.#.#######.#####.#.#.#####.###.#######.#######.#.#####.###.#.#####.#.#.###.###.###.###.#########.#.#.#.#######.#.#.# +#...#...#...#.#.#...#...#.#...#...#.#.....#.#...###.#...#.....#.......#...#...#...#.#.....#.#.#.#...#...#...###...#...#...#.#.#.#.......#.#.# +#.#####.#.#.#.#.###.###.#.###.#.#.#.#.#####.###.###.#.###.###.#######.#####.#.###.#.#####.#.#.#.#.###.###.#######.#.#.#.###.#.#.#.#######.#.# +#...#...#.#.#.#.....#...#...#...#.#.#.#.....#...#...#...#...#.###...#.#.....#...#.#.....#...#...#...#.#...#...#...#.#...#...#.#.#.......#.#.# +###.#.###.#.#.#######.#####.#####.#.#.#.#####.###.#####.###.#.###.#.#.#.#######.#.#####.###########.#.#.###.#.#.###.#####.###.#.#######.#.#.# +#...#...#.#.#.......#.#...#.....#...#.#.#.....#...#...#.#...#.#...#.#.#...#...#...#...#...........#...#...#.#.#...#.###...#...#.#.......#.#.# +#.#####.#.#.#######.#.#.#.#####.#####.#.#.#####.###.#.#.#.###.#.###.#.###.#.#.#####.#.###########.#######.#.#.###.#.###.###.###.#.#######.#.# +#.#.....#.#.....#...#.#.#.#...#.....#.#.#...#...#...#...#...#.#...#.#...#.#.#...#...#.#...###.....#.......#.#.#...#.#...#...#...#.#.......#.# +#.#.#####.#####.#.###.#.#.#.#.#####.#.#.###.#.###.#########.#.###.#.###.#.#.###.#.###.#.#.###.#####.#######.#.#.###.#.###.###.###.#.#######.# +#.#...###.....#.#...#.#.#...#.......#.#.#...#...#.#...###...#.#...#.#...#...#...#.#...#.#.#...#...#.#...###.#.#.#...#...#.###.#...#.#.......# +#.###.#######.#.###.#.#.#############.#.#.#####.#.#.#.###.###.#.###.#.#######.###.#.###.#.#.###.#.#.#.#.###.#.#.#.#####.#.###.#.###.#.####### +#...#.#...#...#.....#.#.#...........#...#...#...#...#...#...#...#...#.......#.###.#.#...#.#.....#.#.#.#.#...#...#.....#.#...#.#.#...#.#.....# +###.#.#.#.#.#########.#.#.#########.#######.#.#########.###.#####.#########.#.###.#.#.###.#######.#.#.#.#.###########.#.###.#.#.#.###.#.###.# +#...#...#...#...#...#.#...#.......#.#.......#...#.......#...#...#...#...#...#.#...#.#.#...#.....#.#.#.#.#.#...........#.#...#.#.#...#.#.#...# +#.###########.#.#.#.#.#####.#####.#.#.#########.#.#######.###.#.###.#.#.#.###.#.###.#.#.###.###.#.#.#.#.#.#.###########.#.###.#.###.#.#.#.### +#...........#.#.#.#.#.#...#.....#...#.....#...#.#.#.....#.....#.#...#.#.#.#...#.#...#.#...#...#...#.#.#...#...#...#.....#.....#...#.#.#.#...# +###########.#.#.#.#.#.#.#.#####.#########.#.#.#.#.#.###.#######.#.###.#.#.#.###.#.###.###.###.#####.#.#######.#.#.#.#############.#.#.#.###.# +#...#.......#.#...#.#...#.....#.#...#.....#.#.#.#.#.#...#...#...#.....#...#...#.#...#...#...#.#.....#.#.......#.#.#...#.....#...#...#.#.#...# +#.#.#.#######.#####.#########.#.#.#.#.#####.#.#.#.#.#.###.#.#.###############.#.###.###.###.#.#.#####.#.#######.#.###.#.###.#.#.#####.#.#.### +#.#...#...#...#...#.......#...#...#.#.....#.#...#.#.#...#.#.#.#...#.........#.#...#...#.#...#.#.#...#.#.#.....#.#.#...#...#.#.#.......#.#...# +#.#####.#.#.###.#.#######.#.#######.#####.#.#####.#.###.#.#.#.#.#.#.#######.#.###.###.#.#.###.#.#.#.#.#.#.###.#.#.#.#####.#.#.#########.###.# +#.......#...###.#...#.....#.........#.....#.....#...#...#.#.#...#...#.......#...#.#...#.#.###.#.#.#...#...#...#.#.#.#...#.#...#...#...#.#...# +###############.###.#.###############.#########.#####.###.#.#########.#########.#.#.###.#.###.#.#.#########.###.#.#.#.#.#.#####.#.#.#.#.#.### +#.............#...#.#...............#.......#...#.....#...#...###...#.......#...#.#.#...#.#...#.#.......#...###.#...#.#...#...#.#.#.#.#.#...# +#.###########.###.#.###############.#######.#.###.#####.#####.###.#.#######.#.###.#.#.###.#.###.#######.#.#####.#####.#####.#.#.#.#.#.#.###.# +#.......#...#.....#.................#.......#...#.....#...#...#...#.#...###.#.###.#.#...#...#...#...###.#.....#...#...#...#.#.#.#...#...#...# +#######.#.#.#########################.#########.#####.###.#.###.###.#.#.###.#.###.#.###.#####.###.#.###.#####.###.#.###.#.#.#.#.#########.### +#.....#.#.#...#...#.....#...#.......#.#...#...#.#.....#...#.###...#.#.#.#...#...#.#.#...#.....#...#.#...#.....###.#.....#...#...#...#...#...# +#.###.#.#.###.#.#.#.###.#.#.#.#####.#.#.#.#.#.#.#.#####.###.#####.#.#.#.#.#####.#.#.#.###.#####.###.#.###.#######.###############.#.#.#.###.# +#...#.#...###...#...###...#...#...#.#.#.#.#.#.#.#.#...#...#.#...#.#.#.#.#.#.....#.#.#...#.#...#...#.#...#.....#...#...#.....#.....#...#.....# +###.#.#########################.#.#.#.#.#.#.#.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#####.#.###.#.#.#.###.#.###.#####.#.###.#.#.###.#.############### +#...#...###...#.............#...#...#...#.#.#.#.#.#.#...#.#.#.#.#.#.#.#.#.#...#...#.#...#.#.#...#.#...#.#.....#.#...#...###...#.....###...### +#.#####.###.#.#.###########.#.###########.#.#.#.#.#.###.#.#.#.#.#.#.#.#.#.###.#.###.#.###.#.###.#.###.#.#.#####.#.#############.###.###.#.### +#.....#.#...#.#...........#.#.........#...#.#...#.#.###.#.#.#.#.#.#.#.#.#...#.#.#...#...#.#...#.#.###...#.....#.#.#...#...#...#...#.....#...# +#####.#.#.###.###########.#.#########.#.###.#####.#.###.#.#.#.#.#.#.#.#.###.#.#.#.#####.#.###.#.#.###########.#.#.#.#.#.#.#.#.###.#########.# +#...#.#.#.#...#...........#...........#...#.....#.#.#...#.#.#.#...#.#.#.#...#.#.#.....#.#.#...#.#.#.........#...#...#...#...#.....#.........# +#.#.#.#.#.#.###.#########################.#####.#.#.#.###.#.#.#####.#.#.#.###.#.#####.#.#.#.###.#.#.#######.#######################.######### +#.#.#.#.#.#...#.......#...............#...#...#.#.#.#...#.#.#...###.#.#.#...#.#.###...#.#.#.#...#.#...#...#.....#.......#.....#...#.........# +#.#.#.#.#.###.#######.#.#############.#.###.#.#.#.#.###.#.#.###.###.#.#.###.#.#.###.###.#.#.#.###.###.#.#.#####.#.#####.#.###.#.#.#########.# +#.#.#.#.#.#...#.....#...#...#.........#.....#.#.#.#...#.#.#...#.#...#.#.....#.#.#...#...#.#.#...#...#...#...###.#.....#.#.###...#.#...#...#.# +#.#.#.#.#.#.###.###.#####.#.#.###############.#.#.###.#.#.###.#.#.###.#######.#.#.###.###.#.###.###.#######.###.#####.#.#.#######.#.#.#.#.#.# +#.#...#.#.#...#.#...#...#.#.#...............#.#.#.#...#.#...#.#.#...#.......#.#.#...#.###.#...#.....#.......#...#.....#...#...###...#...#.#.# +#.#####.#.###.#.#.###.#.#.#.###############.#.#.#.#.###.###.#.#.###.#######.#.#.###.#.###.###.#######.#######.###.#########.#.###########.#.# +#.....#...#...#.#.#...#...#...#...........#.#...#.#...#...#.#.#.###...#.....#...###.#...#.#...###...#.....###.....###...#...#.......#...#...# +#####.#####.###.#.#.#########.#.#########.#.#####.###.###.#.#.#.#####.#.###########.###.#.#.#####.#.#####.###########.#.#.#########.#.#.##### +#...#.....#...#.#.#.........#...#...#...#...#...#.....#...#.#.#.#.....#.....#...#...#...#.#.#.....#.#...#.......#.....#...#.......#...#.....# +#.#.#####.###.#.#.#########.#####.#.#.#.#####.#.#######.###.#.#.#.#########.#.#.#.###.###.#.#.#####.#.#.#######.#.#########.#####.#########.# +#.#...###.#...#.#...#...###.......#...#.#.....#.....###.....#...#.#...#.....#.#...#...###...#.....#...#.........#...#.....#...#...#.........# +#.###.###.#.###.###.#.#.###############.#.#########.#############.#.#.#.#####.#####.#############.#################.#.###.###.#.###.######### +#...#.....#...#.#...#.#.#...............#.#.........#...###.....#.#.#.#.#.....#...#...###.........#...........#...#.#...#.#...#.....#...#...# +###.#########.#.#.###.#.#.###############.#.#########.#.###.###.#.#.#.#.#.#####.#.###.###.#########.#########.#.#.#.###.#.#.#########.#.#.#.# +###...#.....#...#.#...#.#...........#.....#...........#.....#...#...#.#.#.#.....#.#...#...#.........#.......#...#...#...#...#.....###.#.#.#.# +#####.#.###.#####.#.###.###########.#.#######################.#######.#.#.#.#####.#.###.###.#########.#####.#########.#######.###.###.#.#.#.# +#.....#.#...#.....#...#.#.........#...#.....................#.....#...#.#...#.....#...#...#.#.........#...#...........###...#...#.....#...#.# +#.#####.#.###.#######.#.#.#######.#####.###################.#####.#.###.#####.#######.###.#.#.#########.#.###############.#.###.###########.# +#.......#...#.......#.#.#.......#.......###.....#.....#...#.......#...#...###...#...#...#...#...#.......#.......#.........#.....#...........# +###########.#######.#.#.#######.###########.###.#.###.#.#.###########.###.#####.#.#.###.#######.#.#############.#.###############.########### +###...#.....#.....#...#.........#...###...#.#...#.#...#.#.#.........#.....#.....#.#...#.#.......#.#...........#...#...............#...#.....# +###.#.#.#####.###.###############.#.###.#.#.#.###.#.###.#.#.#######.#######.#####.###.#.#.#######.#.#########.#####.###############.#.#.###.# +#...#...#...#.#...#.....#...#.....#.....#...#.....#...#.#.#.#.....#.....#...#...#.###...#.........#.........#.#...#.....#...#...###.#.#.#...# +#.#######.#.#.#.###.###.#.#.#.#######################.#.#.#.#.###.#####.#.###.#.#.#########################.#.#.#.#####.#.#.#.#.###.#.#.#.### +#.........#.#.#...#.#...#.#.#.#.........#.....#.....#...#...#...#.......#.....#...#...#.....................#...#.......#.#.#.#.....#...#...# +###########.#.###.#.#.###.#.#.#.#######.#.###.#.###.###########.###################.#.#.#################################.#.#.#############.# +#.......#...#...#.#.#...#.#...#.......#...###.#.###...#.........#.......###...###...#.#...................#...###.........#...#...#.........# +#.#####.#.#####.#.#.###.#.###########.#######.#.#####.#.#########.#####.###.#.###.###.###################.#.#.###.#############.#.#.######### +#...#...#.......#...#...#.###...###...###...#.#.#E....#...........#.....#...#.....#...#...#...#...........#.#.....#...#.........#...###.....# +###.#.###############.###.###.#.###.#####.#.#.#.###################.#####.#########.###.#.#.#.#.###########.#######.#.#.###############.###.# +#...#.............###.....#...#.....#...#.#.#.#.###########.......#.....#.....#...#.###.#.#.#.#.......#.....#...#...#.#.................#...# +#.###############.#########.#########.#.#.#.#.#.###########.#####.#####.#####.#.#.#.###.#.#.#.#######.#.#####.#.#.###.###################.### +#.#...#...#.....#...#...#...#...#...#.#.#.#.#.#.#...#######.....#.......#...#...#.#...#.#.#.#.#.....#...#.....#...#...#...#...............### +#.#.#.#.#.#.###.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.###########.#########.#.#####.###.#.#.#.#.#.###.#####.#########.###.#.#.################# +#.#.#.#.#.#.###...#.#.#.#.....#...#...#...#.#...#.#.###########.......#...#.#...#...#.#.#...#.#...#...#...#.......#...#.#.#...###.....#...### +#.#.#.#.#.#.#####.#.#.#.###################.#####.#.#################.#.###.#.#.###.#.#.#####.###.###.#.###.#####.###.#.#.###.###.###.#.#.### +#...#...#...#.....#.#.#.#...#...#.....#...#.......#.........#########S#...#.#.#.....#.#.....#...#...#.#.....#...#...#...#...#.....#...#.#...# +#############.#####.#.#.#.#.#.#.#.###.#.#.#################.#############.#.#.#######.#####.###.###.#.#######.#.###.#######.#######.###.###.# +#...###...#...#...#...#...#...#.#...#...#...#.............#.#########...#.#.#.......#.....#.#...#...#.........#...#...#####...#...#.....#...# +#.#.###.#.#.###.#.#############.###.#######.#.###########.#.#########.#.#.#.#######.#####.#.#.###.###############.###.#######.#.#.#######.### +#.#.....#.#.....#.............#.###.....#...#...........#...#.....#...#.#.#.#.......#.....#.#.#...#...#.......###...#...#...#.#.#...#.....### +#.#######.###################.#.#######.#.#############.#####.###.#.###.#.#.#.#######.#####.#.#.###.#.#.#####.#####.###.#.#.#.#.###.#.####### +#...#...#...###...............#.........#...#...........###...#...#.#...#.#.#.......#.......#...#...#...#.....#...#.#...#.#.#...###...###...# +###.#.#.###.###.###########################.#.#############.###.###.#.###.#.#######.#############.#######.#####.#.#.#.###.#.#############.#.# +#...#.#...#.....#...#.....#...#.....###...#.#.....###.....#...#...#.#.#...#.#...#...#...#.....#...#.......#.....#.#.#.#...#.#...#...#...#.#.# +#.###.###.#######.#.#.###.#.#.#.###.###.#.#.#####.###.###.###.###.#.#.#.###.#.#.#.###.#.#.###.#.###.#######.#####.#.#.#.###.#.#.#.#.#.#.#.#.# +#.#...###...#.....#...###...#...###.....#.#.....#...#...#.###.#...#.#.#.#...#.#.#.....#...###.#.###.........#.....#...#.#...#.#...#...#...#.# +#.#.#######.#.###########################.#####.###.###.#.###.#.###.#.#.#.###.#.#############.#.#############.#########.#.###.#############.# +#.#.#.....#...#.............###...#.......#...#.....#...#.#...#.###.#.#.#...#.#...#...#.....#.#...###.........###...###.#.###.#.......#.....# +#.#.#.###.#####.###########.###.#.#.#######.#.#######.###.#.###.###.#.#.###.#.###.#.#.#.###.#.###.###.###########.#.###.#.###.#.#####.#.##### +#...#...#.......#.....#...#.....#...###...#.#.###...#...#...#...#...#.#...#.#.#...#.#.#.#...#...#.#...#...........#.#...#.#...#.....#.#.....# +#######.#########.###.#.#.#############.#.#.#.###.#.###.#####.###.###.###.#.#.#.###.#.#.#.#####.#.#.###.###########.#.###.#.#######.#.#####.# +#...###.......#...###...#.#.............#...#.....#...#.#.....###...#.###.#.#.#.....#...#.....#.#.#.....#...#...#...#.#...#.#.......#.......# +#.#.#########.#.#########.#.#########################.#.#.#########.#.###.#.#.###############.#.#.#######.#.#.#.#.###.#.###.#.############### +#.#.....#.....#.#...#.....#.#.........#...#...#.......#.#.......#...#...#.#.#...#.............#...###.....#...#...###.#.....#.#...#.........# +#.#####.#.#####.#.#.#.#####.#.#######.#.#.#.#.#.#######.#######.#.#####.#.#.###.#.###################.###############.#######.#.#.#.#######.# +#.#.....#.......#.#.#...#...#.#.....#...#...#...#.......#...#...#.....#.#.#.#...#.....#.....#...#...#.......###.......#.....#...#.#.#.......# +#.#.#############.#.###.#.###.#.###.#############.#######.#.#.#######.#.#.#.#.#######.#.###.#.#.#.#.#######.###.#######.###.#####.#.#.####### +#.#.#...###.......#.....#.###...###.#...#...#...#.....#...#...#...#...#.#.#.#.#.....#.#.#...#.#.#.#.#...#...#...#...#...###.#...#...#.......# +#.#.#.#.###.#############.#########.#.#.#.#.#.#.#####.#.#######.#.#.###.#.#.#.#.###.#.#.#.###.#.#.#.#.#.#.###.###.#.#.#####.#.#.###########.# +#.#...#.....#.....#.....#.#.........#.#.#.#.#.#.#.....#.#...#...#.#.#...#.#.#.#...#...#.#...#.#.#.#...#.#.....#...#.#.#...#.#.#.#...#...#...# +#.###########.###.#.###.#.#.#########.#.#.#.#.#.#.#####.#.#.#.###.#.#.###.#.#.###.#####.###.#.#.#.#####.#######.###.#.#.#.#.#.#.#.#.#.#.#.### +#.....#.....#.###.#.###.#.#.........#.#.#.#.#.#.#.....#.#.#.#...#.#.#.###.#.#.#...#...#...#.#.#.#...#...#...#...#...#...#.#.#.#.#.#.#.#...### +#####.#.###.#.###.#.###.#.#########.#.#.#.#.#.#.#####.#.#.#.###.#.#.#.###.#.#.#.###.#.###.#.#.#.###.#.###.#.#.###.#######.#.#.#.#.#.#.####### +#.....#.#...#.#...#...#...#.......#.#.#.#.#.#.#...#...#.#.#...#.#.#.#...#.#.#.#.#...#...#.#.#.#.#...#.#...#...###.........#...#.#.#...#...### +#.#####.#.###.#.#####.#####.#####.#.#.#.#.#.#.###.#.###.#.###.#.#.#.###.#.#.#.#.#.#####.#.#.#.#.#.###.#.#######################.#.#####.#.### +#.#.....#.....#.......#...#.....#...#.#...#.#.#...#...#.#...#.#.#.#.#...#.#.#.#.#.#...#...#.#.#...#...#...........###.......###...#.....#...# +#.#.###################.#.#####.#####.#####.#.#.#####.#.###.#.#.#.#.#.###.#.#.#.#.#.#.#####.#.#####.#############.###.#####.#######.#######.# +#...#...................#.......#...#.....#...#...#...#...#.#...#.#.#...#.#.#.#.#...#.#.....#.....#...#...#.....#.....#...#.....#...#.......# +#####.###########################.#.#####.#######.#.#####.#.#####.#.###.#.#.#.#.#####.#.#########.###.#.#.#.###.#######.#.#####.#.###.####### +#.....#...#.....................#.#.#...#.#.......#.....#.#.#.....#.#...#.#.#.#...#...#.#...#...#...#.#.#...#...#.....#.#.#.....#...#.....### +#.#####.#.#.###################.#.#.#.#.#.#.###########.#.#.#.#####.#.###.#.#.###.#.###.#.#.#.#.###.#.#.#####.###.###.#.#.#.#######.#####.### +#...#...#...#...#...###...#.....#.#.#.#...#.......#.....#.#.#.#.....#...#.#.#...#.#...#.#.#.#.#...#.#.#...###...#...#.#.#.#.#...###.#...#...# +###.#.#######.#.#.#.###.#.#.#####.#.#.###########.#.#####.#.#.#.#######.#.#.###.#.###.#.#.#.#.###.#.#.###.#####.###.#.#.#.#.#.#.###.#.#.###.# +###...#####...#...#.....#...#...#.#...###.........#.....#.#.#.#...#...#...#.#...#.....#...#.#...#.#.#.#...#.....#...#.#.#.#...#.....#.#.....# +###########.#################.#.#.#######.#############.#.#.#.###.#.#.#####.#.#############.###.#.#.#.#.###.#####.###.#.#.###########.####### +#.......#...#.....#...#.....#.#.#.#.......#.....#.....#.#.#.#.#...#.#.......#.......#...#...#...#.#.#.#...#.....#...#...#.#.....#...#.......# +#.#####.#.###.###.#.#.#.###.#.#.#.#.#######.###.#.###.#.#.#.#.#.###.###############.#.#.#.###.###.#.#.###.#####.###.#####.#.###.#.#.#######.# +#.#...#.#...#.#...#.#...###.#.#.#.#...#...#...#.#.###...#...#...###.......#...#.....#.#...#...#...#.#...#.#.....#...#...#.#.#...#.#.........# +#.#.#.#.###.#.#.###.#######.#.#.#.###.#.#.###.#.#.#######################.#.#.#.#####.#####.###.###.###.#.#.#####.###.#.#.#.#.###.########### +#.#.#.#.....#.#...#.#.......#.#.#.###...#...#.#.#...........###.....#...#.#.#.#...###...#...###...#...#...#.....#.#...#.#.#.#...#...........# +#.#.#.#######.###.#.#.#######.#.#.#########.#.#.###########.###.###.#.#.#.#.#.###.#####.#.#######.###.#########.#.#.###.#.#.###.###########.# +#...#...#...#.#...#.#.....#...#...#.........#.#.#.........#...#...#...#...#.#...#...#...#.......#.#...#.........#...#...#.#.#...#...#...#...# +#######.#.#.#.#.###.#####.#.#######.#########.#.#.#######.###.###.#########.###.###.#.#########.#.#.###.#############.###.#.#.###.#.#.#.#.### +###.....#.#.#.#...#.#.....#...###...#...#...#.#.#.......#...#.#...#...#.....###.#...#.#.........#...###.......#...#...###...#...#.#...#.#...# +###.#####.#.#.###.#.#.#######.###.###.#.#.#.#.#.#######.###.#.#.###.#.#.#######.#.###.#.#####################.#.#.#.###########.#.#####.###.# +#...#.....#.#...#...#.#...#...#...#...#.#.#.#.#...#.....#...#.#.#...#.#...###...#.###.#.............###...###...#.#.........#...#.....#.#...# +#.###.#####.###.#####.#.#.#.###.###.###.#.#.#.###.#.#####.###.#.#.###.###.###.###.###.#############.###.#.#######.#########.#.#######.#.#.### +#...#...###.....#.....#.#.#.#...#...###...#.#.#...#...###...#.#.#.###...#...#...#...#.#...#.......#...#.#.........#.........#...#...#.#.#...# +###.###.#########.#####.#.#.#.###.#########.#.#.#####.#####.#.#.#.#####.###.###.###.#.#.#.#.#####.###.#.###########.###########.#.#.#.#.###.# +###...#...#.......#.....#.#.#.#...###...#...#.#.....#.....#...#.#.#.....#...###.#...#.#.#.#.....#.#...#.#.....#...#...#.......#...#...#.....# +#####.###.#.#######.#####.#.#.#.#####.#.#.###.#####.#####.#####.#.#.#####.#####.#.###.#.#.#####.#.#.###.#.###.#.#.###.#.#####.############### +###...#...#...#...#.#.....#.#.#...#...#...#...#.....#...#.....#.#.#.....#...#...#.#...#.#.#...#.#.#...#.#...#.#.#...#...#...#.......#...#...# +###.###.#####.#.#.#.#.#####.#.###.#.#######.###.#####.#.#####.#.#.#####.###.#.###.#.###.#.#.#.#.#.###.#.###.#.#.###.#####.#.#######.#.#.#.#.# +#...#...#...#...#...#.....#.#.#...#.......#.###.....#.#...#...#.#...#...#...#...#.#.....#.#.#...#...#.#.#...#.#.###...#...#...#...#...#...#.# +#.###.###.#.#############.#.#.#.#########.#.#######.#.###.#.###.###.#.###.#####.#.#######.#.#######.#.#.#.###.#.#####.#.#####.#.#.#########.# +#...#.#...#...............#.#.#.#.........#.....#...#.#...#...#.#...#...#.#.....#.......#.#.......#.#.#.#.#...#.#.....#.....#.#.#.#...#...#.# +###.#.#.###################.#.#.#.#############.#.###.#.#####.#.#.#####.#.#.###########.#.#######.#.#.#.#.#.###.#.#########.#.#.#.#.#.#.#.#.# +###...#.....................#...#...............#.....#.......#...#####...#.............#.........#...#...#.....#...........#...#...#...#...# +############################################################################################################################################# \ No newline at end of file diff --git a/solutions/20.zig b/solutions/20.zig index bb469b9..73fd62b 100644 --- a/solutions/20.zig +++ b/solutions/20.zig @@ -10,7 +10,7 @@ pub fn main() !void { defer _ = gpa.deinit(); const allocator = gpa.allocator(); - const response = try partOne(false, false, allocator); + const response = try partTwo(false, false, allocator); print("{}\n", .{response}); } @@ -29,7 +29,7 @@ fn partOne(is_test_case: bool, debug: bool, allocator: std.mem.Allocator) !u32 { const data = try util.readAllInputWithAllocator(input_file, allocator); defer allocator.free(data); - const map = buildMap(data, allocator); + var map = buildMap(data, allocator); defer allocator.free(map); defer { for (map) |line| { @@ -41,6 +41,9 @@ fn partOne(is_test_case: bool, debug: bool, allocator: std.mem.Allocator) !u32 { // functions to do one-and-only-one thing. const start_point = findPoint(map, 'S'); const end_point = findPoint(map, 'E'); + // Cleanup the map so that cheats-to-the-end will still be legal + map[end_point.y][end_point.x] = '.'; + map[start_point.y][start_point.x] = '.'; log("Start point is {s} and end point is {s}\n", .{ start_point, end_point }, debug); const neighboursFunc = &struct { @@ -57,10 +60,46 @@ fn partOne(is_test_case: bool, debug: bool, allocator: std.mem.Allocator) !u32 { } }.func; - const shortestPathLength = util.dijkstra([][]u8, Point, &map, neighboursFunc, start_point, end_point, debug, allocator) catch unreachable; - return shortestPathLength; + var distances_map = util.dijkstra([][]u8, Point, &map, neighboursFunc, start_point, null, debug, allocator); + defer distances_map.deinit(); + + var distances_map_from_end = util.dijkstra([][]u8, Point, &map, neighboursFunc, end_point, null, debug, allocator); + defer distances_map_from_end.deinit(); + + const shortest_non_cheating_path = distances_map.get(end_point).?; + const cheats = findAllPossibleCheats(map, allocator); + defer allocator.free(cheats); + + var scored_cheats = scoreCheats(cheats, shortest_non_cheating_path, distances_map, distances_map_from_end, debug, allocator); + defer scored_cheats.deinit(); + + var total: u32 = 0; + var it = scored_cheats.iterator(); + const target_speedup: u8 = if (is_test_case) 12 else 100; + log("Here are the scored cheats:\n", .{}, debug); + while (it.next()) |e| { + if (e.value_ptr.* >= target_speedup) { + total += 1; + } + if (e.value_ptr.* > 0) { + log("{}: {}\n", .{ e.key_ptr.*, e.value_ptr.* }, debug); + } + } + + return total; } +const Cheat = struct { + start: Point, + end: Point, + pub fn format(self: Cheat, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = options; + + try writer.print("[{s},{s}]", .{ self.start, self.end }); + } +}; + fn buildNeighboursFunction(map: *const [][]u8) *const fn (p: *Point, alloc: std.mem.Allocator) []Point { return struct { pub fn call(p: *Point, alloc: std.mem.Allocator) []Point { @@ -102,12 +141,187 @@ fn findPoint(data: [][]u8, char: u8) Point { unreachable; } +fn findAllPossibleCheats(data: [][]u8, allocator: std.mem.Allocator) []Cheat { + var set = std.AutoHashMap(Cheat, void).init(allocator); + defer set.deinit(); + + for (data, 0..) |line, y| { + for (line, 0..) |c, x| { + var shouldPrintDebugStatements = false; + if (y == 7 and x == 7) { + shouldPrintDebugStatements = true; + } + log("In 7/7 case\n", .{}, shouldPrintDebugStatements); + if (c != '.') { + continue; + } + + if (x + 2 < data[0].len and data[y][x + 2] == '.') { + set.put(Cheat{ .start = Point{ .x = x, .y = y }, .end = Point{ .x = x + 2, .y = y } }, {}) catch unreachable; + } + if (x >= 2 and data[y][x - 2] == '.') { + set.put(Cheat{ .start = Point{ .x = x, .y = y }, .end = Point{ .x = x - 2, .y = y } }, {}) catch unreachable; + } else {} + if (y + 2 < data.len and data[y + 2][x] == '.') { + set.put(Cheat{ .start = Point{ .x = x, .y = y }, .end = Point{ .x = x, .y = y + 2 } }, {}) catch unreachable; + } + if (y >= 2 and data[y - 2][x] == '.') { + set.put(Cheat{ .start = Point{ .x = x, .y = y }, .end = Point{ .x = x, .y = y - 2 } }, {}) catch unreachable; + } + } + } + + var output = std.ArrayList(Cheat).init(allocator); + var set_iter = set.keyIterator(); + while (set_iter.next()) |p| { + output.append(p.*) catch unreachable; + } + return output.toOwnedSlice() catch unreachable; +} + +fn scoreCheats(cheats: []Cheat, base_lowest_time: u32, distances_from_start: std.AutoHashMap(Point, u32), distances_from_end: std.AutoHashMap(Point, u32), debug: bool, allocator: std.mem.Allocator) std.AutoHashMap(Cheat, i64) { + var output = std.AutoHashMap(Cheat, i64).init(allocator); + for (cheats) |cheat| { + output.put(cheat, scoreCheat(cheat, base_lowest_time, distances_from_start, distances_from_end, debug)) catch unreachable; + } + return output; +} + +// Note - `i64`, rather than `u32`, because a cheat might make the time _longer_! +fn scoreCheat(cheat: Cheat, base_lowest_time: u32, distances_from_start: std.AutoHashMap(Point, u32), distances_from_end: std.AutoHashMap(Point, u32), debug: bool) i64 { + const distance_from_start = distances_from_start.get(cheat.start).?; + const distance_from_end = distances_from_end.get(cheat.end).?; + const total_time_with_cheat = distance_from_start + distance_from_end + 2; + log("DEBUG - total_time_with_cheat for {s} is {} - based on {} and {}\n", .{ cheat, total_time_with_cheat, distance_from_start, distance_from_end }, debug); + return @as(i64, base_lowest_time) - @as(i64, total_time_with_cheat); +} + test "partOne" { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const response = try partOne(true, true, allocator); - print("{}\n", .{response}); - try expect(response == 84); + print("Found {} sufficiently-speedy cheats for partOne\n", .{response}); + try expect(response == 8); +} + +fn partTwo(is_test_case: bool, debug: bool, allocator: std.mem.Allocator) !u32 { + const input_file = try util.getInputFile("20", is_test_case); + const data = try util.readAllInputWithAllocator(input_file, allocator); + defer allocator.free(data); + + var map = buildMap(data, allocator); + defer allocator.free(map); + defer { + for (map) |line| { + allocator.free(line); + } + } + + // Technically slightly inefficient to do it this way, as we could have done it during `buildMap`, but I prefer my + // functions to do one-and-only-one thing. + const start_point = findPoint(map, 'S'); + const end_point = findPoint(map, 'E'); + // Cleanup the map so that cheats-to-the-end will still be legal + map[end_point.y][end_point.x] = '.'; + map[start_point.y][start_point.x] = '.'; + log("Start point is {s} and end point is {s}\n", .{ start_point, end_point }, debug); + + const neighboursFunc = &struct { + pub fn func(d: *const [][]u8, point: *Point, alloc: std.mem.Allocator) []Point { + var response = std.ArrayList(Point).init(alloc); + const ns = point.neighbours(d.*[0].len, d.len, alloc); + for (ns) |n| { + if (d.*[n.y][n.x] != '#') { + response.append(n) catch unreachable; + } + } + alloc.free(ns); + return response.toOwnedSlice() catch unreachable; + } + }.func; + + var distances_map = util.dijkstra([][]u8, Point, &map, neighboursFunc, start_point, null, debug, allocator); + defer distances_map.deinit(); + + var distances_map_from_end = util.dijkstra([][]u8, Point, &map, neighboursFunc, end_point, null, debug, allocator); + defer distances_map_from_end.deinit(); + + const shortest_non_cheating_path = distances_map.get(end_point).?; + var cheats = findCheatsWithMaximumLength(map, 20, allocator); + defer cheats.deinit(); + + var scored_cheats = scoreCheatsWithVariableLength(cheats, shortest_non_cheating_path, distances_map, distances_map_from_end, debug, allocator); + defer scored_cheats.deinit(); + + var total: u32 = 0; + var it = scored_cheats.iterator(); + const target_speedup: u8 = if (is_test_case) 66 else 100; + log("Here are the scored cheats:\n", .{}, debug); + while (it.next()) |e| { + if (e.value_ptr.* >= target_speedup) { + total += 1; + } + if (e.value_ptr.* > 0) { + log("{}: {}\n", .{ e.key_ptr.*, e.value_ptr.* }, debug); + } + } + + return total; +} + +fn findCheatsWithMaximumLength(map: [][]u8, maximum_length: u32, allocator: std.mem.Allocator) std.AutoHashMap(Cheat, u64) { + var output = std.AutoHashMap(Cheat, u64).init(allocator); + // Just realized - after running this - that I could probably speed this up by only iterating over the Points that are in the distance maps, + // since those are the only valid (non-wall) spaces. Eh - still only took a coupla seconds. Could add that optimization if it mattered! + for (map, 0..) |start_line, start_y| { + for (start_line, 0..) |start_c, start_x| { + for (map, 0..) |end_line, end_y| { + for (end_line, 0..) |end_c, end_x| { + if (start_c == '.' and end_c == '.') { + const cheat = Cheat{ .start = Point{ .x = start_x, .y = start_y }, .end = Point{ .x = end_x, .y = end_y } }; + const length_of_cheat = findLengthOfCheat(cheat); + if (length_of_cheat <= maximum_length) { + output.put(cheat, length_of_cheat) catch unreachable; + } + } + } + } + } + } + return output; +} + +fn findLengthOfCheat(cheat: Cheat) u64 { + return @as(u64, (if (cheat.start.x > cheat.end.x) cheat.start.x - cheat.end.x else cheat.end.x - cheat.start.x) + (if (cheat.start.y > cheat.end.y) cheat.start.y - cheat.end.y else cheat.end.y - cheat.start.y)); +} + +fn scoreCheatsWithVariableLength(cheats: std.AutoHashMap(Cheat, u64), shortest_non_cheating_path: u32, distances_map: std.AutoHashMap(Point, u32), distances_map_from_end: std.AutoHashMap(Point, u32), debug: bool, allocator: std.mem.Allocator) std.AutoHashMap(Cheat, i128) { + var output = std.AutoHashMap(Cheat, i128).init(allocator); + var e_it = cheats.iterator(); + while (e_it.next()) |e| { + output.put(e.key_ptr.*, scoreCheatWithVariableLength(e.key_ptr.*, e.value_ptr.*, shortest_non_cheating_path, distances_map, distances_map_from_end, debug)) catch unreachable; + } + return output; +} + +// Note - `i128`, rather than `u32`, because a cheat might make the time _longer_! +// (And we can't use i64 because the variable cheat-length is a usize, which is u64, so...:shrug: +fn scoreCheatWithVariableLength(cheat: Cheat, cheat_length: u64, base_lowest_time: u32, distances_from_start: std.AutoHashMap(Point, u32), distances_from_end: std.AutoHashMap(Point, u32), debug: bool) i128 { + const distance_from_start = distances_from_start.get(cheat.start).?; + const distance_from_end = distances_from_end.get(cheat.end).?; + const total_time_with_cheat = distance_from_start + distance_from_end + cheat_length; + log("DEBUG - total_time_with_cheat for {s} is {} - based on {} and {}\n", .{ cheat, total_time_with_cheat, distance_from_start, distance_from_end }, debug); + return @as(i128, base_lowest_time) - @as(i128, total_time_with_cheat); +} + +test "partTwo" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const response = try partTwo(true, true, allocator); + print("Found {} sufficiently-speedy cheats for partTwo\n", .{response}); + try expect(response == 67); } diff --git a/solutions/util.zig b/solutions/util.zig index a4526ee..072e95b 100644 --- a/solutions/util.zig +++ b/solutions/util.zig @@ -134,10 +134,11 @@ pub fn log(comptime message: []const u8, args: anytype, debug: bool) void { } } -// Basic implementation of Dijkstra - given start and end, find the length of the shortest path that joins them. +// Basic implementation of Dijkstra - given start and end, explore until a shortest path is found to `end`. // Assumes that all links have cost 1. -const DijkstraError = error{NoPathFound}; - +// Returns distances rather than the length of the path because that's often useful. In particular, pass `null` as `end` +// to get minimum distances from `start` to _every_ node. +// // Zig does not really support the passing-in of bare anonymous functions that depend on higher-level variables - you'll // get errors like `'' not accessible from inner function` or `crossing function boundary`. // @@ -147,12 +148,11 @@ const DijkstraError = error{NoPathFound}; // So, instead of passing in a nicely-encapsulated partial-application `getNeighbours` which _just_ takes a `node_type`, it needs to take in the data as well. Blech. // // (Check out the implementation at commit `d85d29` to see what it looked like before this change!) -pub fn dijkstra(comptime data_type: type, comptime node_type: type, data: *const data_type, getNeighbours: *const fn (d: *const data_type, n: *node_type, allocator: std.mem.Allocator) []node_type, start: node_type, end: node_type, debug: bool, allocator: std.mem.Allocator) DijkstraError!u32 { +pub fn dijkstra(comptime data_type: type, comptime node_type: type, data: *const data_type, getNeighbours: *const fn (d: *const data_type, n: *node_type, allocator: std.mem.Allocator) []node_type, start: node_type, end: ?node_type, debug: bool, allocator: std.mem.Allocator) std.AutoHashMap(node_type, u32) { var visited = std.AutoHashMap(node_type, void).init(allocator); defer visited.deinit(); var distances = std.AutoHashMap(node_type, u32).init(allocator); - defer distances.deinit(); distances.put(start, 0) catch unreachable; // Not strictly necessary - we could just iterate over all keys of `distances` and filter out those that are @@ -162,7 +162,7 @@ pub fn dijkstra(comptime data_type: type, comptime node_type: type, data: *const defer unvisited_candidates.deinit(); unvisited_candidates.put(start, {}) catch unreachable; - return while (true) { + while (true) { var cand_it = unvisited_candidates.keyIterator(); var curr: node_type = undefined; var lowest_distance_found: u32 = std.math.maxInt(u32); @@ -181,14 +181,14 @@ pub fn dijkstra(comptime data_type: type, comptime node_type: type, data: *const } if (lowest_distance_found == std.math.maxInt(u32)) { - log("ERROR - iterated over all candidates, but found none with non-infinite distance", .{}, debug); - break DijkstraError.NoPathFound; + log("Iterated over all candidates, but found none with non-infinite distance\n", .{}, debug); + break; } log("Settled on {s} as the new curr", .{curr}, debug); - if (std.meta.eql(curr, end)) { + if (end != null and std.meta.eql(curr, end.?)) { log(" and that is the target, so we're done!\n", .{}, debug); - break lowest_distance_found; + break; } else { log(" - now exploring its neighbours\n", .{}, debug); } @@ -217,7 +217,9 @@ pub fn dijkstra(comptime data_type: type, comptime node_type: type, data: *const visited.put(curr, {}) catch unreachable; _ = unvisited_candidates.remove(curr); log("{s} has now been fully visited - loop begins again\n", .{curr}, debug); - }; + } + + return distances; } test "Dijkstra" { @@ -269,9 +271,11 @@ test "Dijkstra" { } }.func; - const result = dijkstra([]u8, Point, &data, neighboursFunc, start, end, false, allocator) catch unreachable; - // print("Dijkstra result is {}\n", .{result}); - try expect(result == 84); + var result = dijkstra([]u8, Point, &data, neighboursFunc, start, end, false, allocator); + defer result.deinit(); + const distance = result.get(end).?; + print("Dijkstra result is {}\n", .{distance}); + try expect(distance == 84); } test {