diff --git a/docs/day20.md b/docs/day20.md new file mode 100644 index 0000000..02411a0 --- /dev/null +++ b/docs/day20.md @@ -0,0 +1,137 @@ +--- +url: "https://adventofcode.com/2024/day/20" +--- + +## Day 20: Race Condition + +The Historians are quite pixelated again. This time, a massive, black building looms over you - you're right outside the CPU! + +While The Historians get to work, a nearby program sees that you're idle and challenges you to a race. Apparently, you've arrived just in time for the frequently-held race condition festival! + +The race takes place on a particularly long and twisting code path; programs compete to see who can finish in the fewest picoseconds. The winner even gets their very own mutex! + +They hand you a map of the racetrack (your puzzle input). For example: + +```txt +############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...#...# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +############### +``` + +The map consists of track (`.`) - including the start (`S`) and end (`E`) positions (both of which also count as track) - and walls (`#`). + +When a program runs through the racetrack, it starts at the start position. Then, it is allowed to move up, down, left, or right; each such move takes `1` picosecond. The goal is to reach the end position as quickly as possible. In this example racetrack, the fastest time is `84` picoseconds. + +Because there is only a single path from the start to the end and the programs all go the same speed, the races used to be pretty boring. To make things more interesting, they introduced a new rule to the races: programs are allowed to cheat. + +The rules for cheating are very strict. Exactly once during a race, a program may disable collision for up to 2 picoseconds. This allows the program to pass through walls as if they were regular track. At the end of the cheat, the program must be back on normal track again; otherwise, it will receive a segmentation fault and get disqualified. + +So, a program could complete the course in 72 picoseconds (saving 12 picoseconds) by cheating for the two moves marked 1 and 2: + +```txt +############### +#...#...12....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...#...# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +############### +``` + +Or, a program could complete the course in 64 picoseconds (saving 20 picoseconds) by cheating for the two moves marked `1` and `2`: + +```txt +############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...12..# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +############### +``` + +This cheat saves 38 picoseconds: + +```txt +############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...#...# +###.####1##.### +#...###.2.#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +############### +``` + +This cheat saves 64 picoseconds and takes the program directly to the end: + +```txt +############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..21...#...# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +############### +``` + +Each cheat has a distinct start position (the position where the cheat is activated, just before the first move that is allowed to go through walls) and end position; cheats are uniquely identified by their start position and end position. + +In this example, the total number of cheats (grouped by the amount of time they save) are as follows: + +* There are 14 cheats that save 2 picoseconds. +* There are 14 cheats that save 4 picoseconds. +* There are 2 cheats that save 6 picoseconds. +* There are 4 cheats that save 8 picoseconds. +* There are 2 cheats that save 10 picoseconds. +* There are 3 cheats that save 12 picoseconds. +* There is one cheat that saves 20 picoseconds. +* There is one cheat that saves 36 picoseconds. +* There is one cheat that saves 38 picoseconds. +* There is one cheat that saves 40 picoseconds. +* There is one cheat that saves 64 picoseconds. + +You aren't sure what the conditions of the racetrack will be like, so to give yourself as many options as possible, you'll need a list of the best cheats. How many cheats would save you at least 100 picoseconds? \ No newline at end of file diff --git a/src/day20/day20.go b/src/day20/day20.go new file mode 100644 index 0000000..996fa54 --- /dev/null +++ b/src/day20/day20.go @@ -0,0 +1,175 @@ +package day20 + +import ( + "slices" + "strings" +) + +const CHEAT_LENGTH_OF_INTEREST = 100 +const EMPTY_SPACE = '.' +const END = 'E' +const START = 'S' +const MOVES_TO_USE_CHEAT = 2 +const THREAD_POOL = 64 + +type point struct { + x, y int +} + +type maze struct { + start, end point + width, height uint + emptySpaces map[point]bool +} + +func (m maze) valid(p point) bool { + return p.x >= 0 && p.y >= 0 && p.x < int(m.width) && p.y < int(m.height) +} + +type thread struct { + p point + moves []point +} + +func Solve(input string) uint { + m, sol := SolvePuzzle(input) + cheats := Cheats(m, sol) + var cnt uint = 0 + for k, v := range cheats { + if k >= CHEAT_LENGTH_OF_INTEREST { + cnt += v + } + } + return cnt +} + +func SolvePuzzle(input string) (maze, []point) { + m := parseInput(input) + sol := solve(m) + return m, sol +} + +func Cheats(m maze, sol []point) map[uint]uint { + cheats := make(map[uint]uint) + solution := make(map[point]uint) + for i, p := range sol { + solution[p] = uint(i) + } + + for i := 1; i < int(m.width-1); i++ { + for j := 1; j < int(m.height-1); j++ { + p := point{x: i, y: j} + if m.emptySpaces[p] || solution[p] > 0 { + continue + } + + east, south, west, north := point{x: p.x + 1, y: p.y}, point{x: p.x, y: p.y + 1}, point{x: p.x - 1, y: p.y}, point{x: p.x, y: p.y - 1} + if (solution[east] == 0 || solution[west] == 0) && (solution[south] == 0 || solution[north] == 0) { + continue + } + + cheats[max(cheatLength(east, west, solution), cheatLength(south, north, solution))-MOVES_TO_USE_CHEAT] += 1 + } + } + + return cheats +} + +func parseInput(input string) maze { + var m maze + m.emptySpaces = make(map[point]bool) + for j, line := range strings.Split(input, "\n") { + m.width = uint(len(line)) + for i, r := range line { + p := point{x: i, y: j} + switch r { + case EMPTY_SPACE: + m.emptySpaces[p] = true + case START: + m.start = p + case END: + m.emptySpaces[p] = true + m.end = p + } + } + m.height = uint(j) + 1 + } + return m +} + +func solve(m maze) []point { + seenSpaces := make(map[point]uint) + seenSpaces[m.start] = 1 + threads := []thread{{p: m.start, moves: []point{m.start}}} + coldStorage := make([]thread, 0) + solution := make([]point, 0) + for { + nextThreads := make([]thread, 0) + for i, t := range threads { + if i >= THREAD_POOL { + coldStorage = append(coldStorage, t) + continue + } else if t.p == m.end { + if len(solution) == 0 || len(t.moves) < len(solution) { + solution = t.moves + } + } else { + nextThreads = append(calcNextMoves(m, t, seenSpaces), nextThreads...) + } + } + + if len(nextThreads) == 0 { + if len(coldStorage) > 0 { + x := THREAD_POOL + if len(coldStorage) < x { + x = len(coldStorage) + } + nextThreads = coldStorage[:x] + coldStorage = slices.Delete(coldStorage, 0, x) + } else { + if len(solution) == 0 { + panic("No solution with no more spaces to check") + } + return solution + } + } + for i, t := range nextThreads { + if len(solution) > 0 && len(t.moves) >= len(solution) { + nextThreads = slices.Delete(nextThreads, i, i) + } + if seenSpaces[t.p] == 0 || uint(len(t.moves)) < seenSpaces[t.p] { + seenSpaces[t.p] = uint(len(t.moves)) + } + } + threads = nextThreads + } +} + +func calcNextMoves(m maze, curr thread, seenSpaces map[point]uint) []thread { + nextMoves := make([]thread, 0) + possibilities := []thread{{p: point{x: curr.p.x + 1, y: curr.p.y}, moves: curr.moves}, + {p: point{x: curr.p.x, y: curr.p.y + 1}, moves: curr.moves}, + {p: point{x: curr.p.x - 1, y: curr.p.y}, moves: curr.moves}, + {p: point{x: curr.p.x, y: curr.p.y - 1}, moves: curr.moves}} + for _, t := range possibilities { + if m.valid(t.p) && m.emptySpaces[t.p] { + if seenSpaces[t.p] == 0 || uint(len(t.moves))+1 < seenSpaces[t.p] { + t.moves = append(t.moves, t.p) + nextMoves = append(nextMoves, t) + } + } + } + return nextMoves +} + +func cheatLength(a, b point, solution map[point]uint) uint { + if solution[a] == 0 || solution[b] == 0 { + return 0 + } + + if solution[a] > solution[b] { + return solution[a] - solution[b] + } else { + return solution[b] - solution[a] + } +} diff --git a/src/day20/day20_test.go b/src/day20/day20_test.go new file mode 100644 index 0000000..c3eb052 --- /dev/null +++ b/src/day20/day20_test.go @@ -0,0 +1,210 @@ +package day20 + +import ( + "testing" +) + +func TestSmall(t *testing.T) { + input := `S.. +##. +E..` + m, sol := SolvePuzzle(input) + if len(sol) != 7 { + t.Errorf("Calculated solution (%d) was not expected", sol) + } + + Cheats(m, sol) +} + +func TestSampleOne(t *testing.T) { + input := `############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...#...# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +###############` + result := Solve(input) + if result != 0 { + t.Errorf("Calculated solution (%d) was not expected", result) + } +} + +func TestSampleOneCheats(t *testing.T) { + input := `############### +#...#...#.....# +#.#.#.#.#.###.# +#S#...#.#.#...# +#######.#.#.### +#######.#.#...# +#######.#.###.# +###..E#...#...# +###.#######.### +#...###...#...# +#.#####.#.###.# +#.#...#.#.#...# +#.#.#.#.#.#.### +#...#...#...### +###############` + m, sol := SolvePuzzle(input) + result := Cheats(m, sol) + if len(result) != 11 { + t.Errorf("Calculated solution (%d) was not expected", result) + } +} + +func TestPart1(t *testing.T) { + input := `############################################################################################################################################# +#.........###...###...###.........#...#...#...#...###...............#...###.............#.....#.......###...........#.....###...#...........# +#.#######.###.#.###.#.###.#######.#.#.#.#.#.#.#.#.###.#############.#.#.###.###########.#.###.#.#####.###.#########.#.###.###.#.#.#########.# +#.......#...#.#.#...#...#.......#.#.#.#.#.#.#...#.#...#.....#.....#...#...#.#...........#.#...#.....#.#...#.....#...#...#.#...#...#...#.....# +#######.###.#.#.#.#####.#######.#.#.#.#.#.#.#####.#.###.###.#.###.#######.#.#.###########.#.#######.#.#.###.###.#.#####.#.#.#######.#.#.##### +#...###...#.#.#...#...#...###...#.#.#.#.#.#.....#.#.....#...#...#...#.....#.#.#.....#.....#.#...#...#...#...###...#.....#...#.......#...#...# +#.#.#####.#.#.#####.#.###.###.###.#.#.#.#.#####.#.#######.#####.###.#.#####.#.#.###.#.#####.#.#.#.#######.#########.#########.###########.#.# +#.#.#...#.#.#.#.....#...#...#...#.#.#...#.#...#.#...###...#...#...#...#.....#.#.#...#.#.....#.#.#.......#.###...###.......#...#.......###.#.# +#.#.#.#.#.#.#.#.#######.###.###.#.#.#####.#.#.#.###.###.###.#.###.#####.#####.#.#.###.#.#####.#.#######.#.###.#.#########.#.###.#####.###.#.# +#.#...#.#.#.#...#...###...#.#...#.#.....#.#.#.#.#...#...#...#.....#...#.....#...#...#.#.....#.#...#...#.#...#.#.#...###...#.....#...#...#.#.# +#.#####.#.#.#####.#.#####.#.#.###.#####.#.#.#.#.#.###.###.#########.#.#####.#######.#.#####.#.###.#.#.#.###.#.#.#.#.###.#########.#.###.#.#.# +#.....#...#...###.#.......#.#.#...#...#.#.#.#.#.#.#...#...#.......#.#.#...#.#.......#.#.....#.#...#.#.#...#.#.#...#.....#.........#.....#.#.# +#####.#######.###.#########.#.#.###.#.#.#.#.#.#.#.#.###.###.#####.#.#.#.#.#.#.#######.#.#####.#.###.#.###.#.#.###########.###############.#.# +###...#.....#...#.........#.#.#...#.#.#.#...#...#.#.#...###...#...#.#.#.#...#.........#.#...#.#.#...#.#...#.#.#.....#...#.......#...#...#.#.# +###.###.###.###.#########.#.#.###.#.#.#.#########.#.#.#######.#.###.#.#.###############.#.#.#.#.#.###.#.###.#.#.###.#.#.#######.#.#.#.#.#.#.# +#...#...###...#.#...#.....#...#...#.#.#.#.......#.#.#.......#.#...#.#.#.....#.......#...#.#.#.#.#...#.#...#...#...#...#.........#.#.#.#.#.#.# +#.###.#######.#.#.#.#.#########.###.#.#.#.#####.#.#.#######.#.###.#.#.#####.#.#####.#.###.#.#.#.###.#.###.#######.###############.#.#.#.#.#.# +#.#...#.......#...#.#.......#...###.#.#...#.....#...#.......#.#...#.#.#...#.#.....#.#.#...#.#.#.#...#.#...#.....#...#...#...#...#.#...#.#.#.# +#.#.###.###########.#######.#.#####.#.#####.#########.#######.#.###.#.#.#.#.#####.#.#.#.###.#.#.#.###.#.###.###.###.#.#.#.#.#.#.#.#####.#.#.# +#.#.###.......#...#.........#...#...#.....#.....#.....#...#...#.###.#.#.#.#.#.....#...#...#...#.#.#...#.#...###.....#.#.#.#...#.#.#.....#.#.# +#.#.#########.#.#.#############.#.#######.#####.#.#####.#.#.###.###.#.#.#.#.#.###########.#####.#.#.###.#.###########.#.#.#####.#.#.#####.#.# +#.#.#...#...#...#.............#.#...#.....#.....#...###.#.#...#.#...#...#.#.#...###.....#.....#...#...#.#.#...#.......#...#.....#.#.#...#.#.# +#.#.#.#.#.#.#################.#.###.#.#####.#######.###.#.###.#.#.#######.#.###.###.###.#####.#######.#.#.#.#.#.###########.#####.#.#.#.#.#.# +#.#.#.#...#...................#...#.#.....#...#...#.....#...#.#.#.......#.#...#...#.#...#...#.#.......#.#.#.#.#.....#...#...#...#.#...#...#.# +#.#.#.###########################.#.#####.###.#.#.#########.#.#.#######.#.###.###.#.#.###.#.#.#.#######.#.#.#.#####.#.#.#.###.#.#.#########.# +#.#.#.......#...................#.#.....#...#...#.#.........#.#.#...#...#...#.#...#.#.#...#.#.#.#...###.#.#.#...#...#.#...#...#...#.........# +#.#.#######.#.#################.#.#####.###.#####.#.#########.#.#.#.#.#####.#.#.###.#.#.###.#.#.#.#.###.#.#.###.#.###.#####.#######.######### +#...#...###...#.......###.......#...#...#...###...#.#...###...#.#.#.#.....#.#.#...#.#.#.#...#.#.#.#.#...#...#...#.#...#...#...#.....#...#...# +#####.#.#######.#####.###.#########.#.###.#####.###.#.#.###.###.#.#.#####.#.#.###.#.#.#.#.###.#.#.#.#.#######.###.#.###.#.###.#.#####.#.#.#.# +#.....#.......#.....#.#...#...#...#.#...#.#...#.#...#.#...#...#...#.#...#.#.#.#...#.#.#.#.....#.#.#.#...#.....#...#...#.#.....#...#...#.#.#.# +#.###########.#####.#.#.###.#.#.#.#.###.#.#.#.#.#.###.###.###.#####.#.#.#.#.#.#.###.#.#.#######.#.#.###.#.#####.#####.#.#########.#.###.#.#.# +#...........#...#...#.#.#...#...#.#.###.#...#.#.#...#...#.#...#.....#.#.#.#...#.#...#.#.......#.#.#.#...#.#...#.....#.#.#.........#.#...#.#.# +###########.###.#.###.#.#.#######.#.###.#####.#.###.###.#.#.###.#####.#.#.#####.#.###.#######.#.#.#.#.###.#.#.#####.#.#.#.#########.#.###.#.# +#.........#.#...#...#.#...#...#...#...#.....#.#.#...###.#.#.#...#...#.#.#...#...#.#...###...#.#.#.#.#...#...#.......#...#.....#...#.#...#.#.# +#.#######.#.#.#####.#.#####.#.#.#####.#####.#.#.#.#####.#.#.#.###.#.#.#.###.#.###.#.#####.#.#.#.#.#.###.#####################.#.#.#.###.#.#.# +#...#...#...#.......#.......#.#.....#...#...#...#...#...#.#.#...#.#.#.#.#...#...#.#...#...#.#.#.#.#.....#.....................#.#.#.#...#.#.# +###.#.#.#####################.#####.###.#.#########.#.###.#.###.#.#.#.#.#.#####.#.###.#.###.#.#.#.#######.#####################.#.#.#.###.#.# +###...#.....#...#.....#.....#.....#.#...#.#...#.....#.#...#.###...#.#.#...#.....#.#...#.#...#.#.#.###.....#.......#...........#.#.#.#...#.#.# +###########.#.#.#.###.#.###.#####.#.#.###.#.#.#.#####.#.###.#######.#.#####.#####.#.###.#.###.#.#.###.#####.#####.#.#########.#.#.#.###.#.#.# +#...#.....#...#.#.###...#...#...#...#...#...#.#.#...#.#...#...#.....#.....#.....#.#.#...#...#.#.#...#.#.....#.....#.#.........#.#...#...#.#.# +#.#.#.###.#####.#.#######.###.#.#######.#####.#.#.#.#.###.###.#.#########.#####.#.#.#.#####.#.#.###.#.#.#####.#####.#.#########.#####.###.#.# +#.#...#...#...#...#.......#...#.......#.#...#.#.#.#...#...#...#.#...#.....#...#.#.#.#...###.#.#.#...#...#.....###...#.........#.#.....#...#.# +#.#####.###.#.#####.#######.#########.#.#.#.#.#.#.#####.###.###.#.#.#.#####.#.#.#.#.###.###.#.#.#.#######.#######.###########.#.#.#####.###.# +#.....#.....#.#...#.......#.#.........#...#...#.#.....#...#...#.#.#.#.....#.#.#.#.#.....#...#.#.#.#.....#.....#...#...........#.#.#.....#...# +#####.#######.#.#.#######.#.#.#################.#####.###.###.#.#.#.#####.#.#.#.#.#######.###.#.#.#.###.#####.#.###.###########.#.#.#####.### +#.....#.....#...#.......#.#.#...#...#...#...###.#...#.#...#...#...#.#...#...#.#.#.#.......#...#.#.#...#.......#.#...#...###.....#...#...#...# +#.#####.###.###########.#.#.###.#.#.#.#.#.#.###.#.#.#.#.###.#######.#.#.#####.#.#.#.#######.###.#.###.#########.#.###.#.###.#########.#.###.# +#.#.....###...........#.#...###...#...#...#...#.#.#.#.#.#...#...#...#.#...#...#...#.......#...#.#.###.....###...#...#.#.#...#.....#...#.#...# +#.#.#################.#.#####################.#.#.#.#.#.#.###.#.#.###.###.#.#############.###.#.#.#######.###.#####.#.#.#.###.###.#.###.#.### +#...#...#.......#...#.#...#.......#...#...#...#...#.#.#.#.#...#...#...###.#.....#.........#...#...#...###.....#...#...#...#...###...###.#...# +#####.#.#.#####.#.#.#.###.#.#####.#.#.#.#.#.#######.#.#.#.#.#######.#####.#####.#.#########.#######.#.#########.#.#########.###########.###.# +#...#.#.#.#...#...#...#...#.....#...#...#...#.....#.#.#.#.#.......#.....#.....#.#...#.....#.###.....#...#.......#.........#.#.........#.....# +#.#.#.#.#.#.#.#########.#######.#############.###.#.#.#.#.#######.#####.#####.#.###.#.###.#.###.#######.#.###############.#.#.#######.####### +#.#.#.#.#...#.....#...#...#.....#...#.......#.#...#...#...#.......#...#.#...#...###...#...#...#.#.....#...#...#.......#...#...#.....#.......# +#.#.#.#.#########.#.#.###.#.#####.#.#.#####.#.#.###########.#######.#.#.#.#.###########.#####.#.#.###.#####.#.#.#####.#.#######.###.#######.# +#.#...#.###...###...#...#.#.......#...#.....#.#.#...#...#...#.....#.#.#...#...###.......#...#.#...###.......#...#.....#.......#...#...#...#.# +#.#####.###.#.#########.#.#############.#####.#.#.#.#.#.#.###.###.#.#.#######.###.#######.#.#.###################.###########.###.###.#.#.#.# +#.....#.....#.#...#...#.#.###...#.......#.....#...#...#.#.....#...#.#...#...#.#...#.....#.#.#...#...............#...........#...#...#...#...# +#####.#######.#.#.#.#.#.#.###.#.#.#######.#############.#######.###.###.#.#.#.#.###.###.#.#.###.#.#############.###########.###.###.######### +#...#.......#.#.#...#...#.....#.#.........#.......#...#.....#...#...#...#.#...#...#...#.#.#.....#.............#.........#...###.....#.....### +#.#.#######.#.#.###############.###########.#####.#.#.#####.#.###.###.###.#######.###.#.#.###################.#########.#.###########.###.### +#.#.###...#.#.#...........#...#.#.......#...#...#...#.#...#.#...#...#.#...#.......#...#...#.......###...#...#.........#.#.#...#...###...#...# +#.#.###.#.#.#.###########.#.#.#.#.#####.#.###.#.#####.#.#.#.###.###.#.#.###.#######.#######.#####.###.#.#.#.#########.#.#.#.#.#.#.#####.###.# +#.#...#.#...#...........#...#.#.#.....#.#.....#.....#.#.#...###.....#.#.###...#.....#...#...#...#.....#...#.........#.#.#...#...#...#...#...# +#.###.#.###############.#####.#.#####.#.###########.#.#.#############.#.#####.#.#####.#.#.###.#.###################.#.#.###########.#.###.### +#...#.#.......#...#...#...#...#.......#...#.........#...#...###...###...#.....#.#.....#.#.....#...............#...#...#.............#...#...# +###.#.#######.#.#.#.#.###.#.#############.#.#############.#.###.#.#######.#####.#.#####.#####################.#.#.#####################.###.# +#...#.........#.#...#...#.#.#...#.......#...#...#...###...#...#.#.#.....#.#...#.#.#...#.....................#...#.......###...#...#...#.#...# +#.#############.#######.#.#.#.#.#.#####.#####.#.#.#.###.#####.#.#.#.###.#.#.#.#.#.#.#.#####################.###########.###.#.#.#.#.#.#.#.### +#.#.....#.....#.#.......#...#.#.#.#.....#.....#...#...#.#.....#.#...#...#...#.#.#.#.#...#.................#.............#...#.#.#.#.#...#...# +#.#.###.#.###.#.#.###########.#.#.#.#####.###########.#.#.#####.#####.#######.#.#.#.###.#.###############.###############.###.#.#.#.#######.# +#...#...#.#...#.#...#...#...#.#...#.......#...........#.#.#.....#.....#.......#.#...###...#...............#...#.....#...#...#.#.#.#.#.......# +#####.###.#.###.###.#.#.#.#.#.#############.###########.#.#.#####.#####.#######.###########.###############.#.#.###.#.#.###.#.#.#.#.#.####### +#...#.....#...#.#...#.#.#.#...#.............###...###...#...#...#.....#.........#...#.......#...............#...#...#.#...#.#.#.#...#.....### +#.#.#########.#.#.###.#.#.#####.###############.#.###.#######.#.#####.###########.#.#.#######.###################.###.###.#.#.#.#########.### +#.#.......###...#.#...#.#.#.....#...............#.....#...#...#.......#######...#.#.#.........#.......###.........#...#...#.#...#...#...#...# +#.#######.#######.#.###.#.#.#####.#####################.#.#.#################.#.#.#.###########.#####.###.#########.###.###.#####.#.#.#.###.# +#.....#...#...#...#.###...#.......#...............#.....#...###.....#########.#...#.###.........#...#.....#...#.....#...###.#.....#.#.#.#...# +#####.#.###.#.#.###.###############.#############.#.###########.###.#########.#####.###.#########.#.#######.#.#.#####.#####.#.#####.#.#.#.### +#.....#.....#...#...#...............#...........#.#.............#...#########...#...#...#.........#...#.....#...#...#.###...#.....#...#...### +#.###############.###.###############.#########.#.###############.#############.#.###.###.###########.#.#########.#.#.###.#######.########### +#.#...#.....#...#.###...............#.#.........#.....#...#.......###########...#...#.....#...###...#...#...#.....#.#.....#.......#...#...### +#.#.#.#.###.#.#.#.#################.#.#.#############.#.#.#.#################.#####.#######.#.###.#.#####.#.#.#####.#######.#######.#.#.#.### +#.#.#.#.###...#.#.#...#.............#.#.#...#...#...#...#...#.....###########...#...###.....#...#.#.......#...#.....#.....#.........#...#...# +#.#.#.#.#######.#.#.#.#.#############.#.#.#.#.#.#.#.#########.###.#############.#.#####.#######.#.#############.#####.###.#################.# +#.#.#.#...#.....#.#.#.#.......#.......#...#...#...#...#...###.#...#############.#.....#.......#...#...........#.....#...#...#.............#.# +#.#.#.###.#.#####.#.#.#######.#.#####################.#.#.###.#.###############.#####.#######.#####.#########.#####.###.###.#.###########.#.# +#.#.#...#.#.......#.#.......#...###.....#...#.......#...#.#...#.......#########...#...###...#.......###.......#...#...#.###.#...........#...# +#.#.###.#.#########.#######.#######.###.#.#.#.#####.#####.#.#########.###########.#.#####.#.###########.#######.#.###.#.###.###########.##### +#...###...#...#...#.......#.###...#.###...#...#.....#.....#.#.........#######.....#.###...#...........#.........#...#.#.#...#.....#.....#...# +###########.#.#.#.#######.#.###.#.#.###########.#####.#####.#.###############.#####.###.#############.#############.#.#.#.###.###.#.#####.#.# +#...........#...#.........#.#...#...#.......###.....#.#.....#.......#########.....#...#...#...#.....#.........#.....#...#.....###.#.......#.# +#.#########################.#.#######.#####.#######.#.#.###########.#############.###.###.#.#.#.###.#########.#.#################.#########.# +#.........................#...#.......#...#.....#...#.#.....#.....#.#############...#...#...#...###...#.....#.#...#.............#.#...#...#.# +#########################.#####.#######.#.#####.#.###.#####.#.###.#.###############.###.#############.#.###.#.###.#.###########.#.#.#.#.#.#.# +#.........###...#...#.....#...#.#.......#.......#.....#.....#..E#...###########...#.#...#.....###...#...#...#...#...#.....#.....#...#...#...# +#.#######.###.#.#.#.#.#####.#.#.#.#####################.#######################.#.#.#.###.###.###.#.#####.#####.#####.###.#.################# +#.......#.#...#.#.#.#...#...#...#.....#...###...#.....#.......#################.#.#.#...#...#...#.#.#.....#...#.......###.#...#...#...#...### +#######.#.#.###.#.#.###.#.###########.#.#.###.#.#.###.#######.#################.#.#.###.###.###.#.#.#.#####.#.###########.###.#.#.#.#.#.#.### +#...###.#.#...#...#.###...#...........#.#.#...#...#...#...###...###############.#.#.#...###.#...#.#.#.......#...........#...#...#...#...#...# +#.#.###.#.###.#####.#######.###########.#.#.#######.###.#.#####.###############.#.#.#.#####.#.###.#.###################.###.###############.# +#.#.#...#...#...#...#...#...#.......#...#...#.......#...#.....#.###############.#.#.#...#...#...#.#.#.......#...#.......###.....#.....#...#.# +#.#.#.#####.###.#.###.#.#.###.#####.#.#######.#######.#######.#.###############.#.#.###.#.#####.#.#.#.#####.#.#.#.#############.#.###.#.#.#.# +#.#.#.....#.#...#.....#.#.....#.....#...#.....#...###.....#...#.###############.#.#.#...#...#...#.#.#.....#.#.#.#.............#...###.#.#.#.# +#.#.#####.#.#.#########.#######.#######.#.#####.#.#######.#.###.###############.#.#.#.#####.#.###.#.#####.#.#.#.#############.#######.#.#.#.# +#.#.......#...#.......#.........#...#...#...#...#...#...#.#...#.###############.#.#.#.#...#.#.#...#.#...#.#.#.#.#...#...#.....###...#.#.#.#.# +#.#############.#####.###########.#.#.#####.#.#####.#.#.#.###.#.###############.#.#.#.#.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.#######.#.#.#.#.#.# +#...#...#.......#...#...#.....#...#.#.#.....#.....#.#.#.#.###.#.....###########.#...#.#.#.#.#.#...#.#.#...#...#.#.#...#.#.........#.#.#.#.#.# +###.#.#.#.#######.#.###.#.###.#.###.#.#.#########.#.#.#.#.###.#####.###########.#####.#.#.#.#.###.#.#.#########.#.#####.###########.#.#.#.#.# +###...#.#.#.....#.#.....#.#...#...#...#.#...#...#.#.#.#...#...#...#...#########.....#.#.#...#...#.#.#.......#...#...#...#.....#.....#.#.#.#.# +#######.#.#.###.#.#######.#.#####.#####.#.#.#.#.#.#.#.#####.###.#.###.#############.#.#.#######.#.#.#######.#.#####.#.###.###.#.#####.#.#.#.# +#...###...#...#...#...#...#...#...#.....#.#.#.#...#.#.....#...#.#...#.#####S..#.....#.#.###.....#.#.#.......#...#...#...#.###...#...#...#...# +#.#.#########.#####.#.#.#####.#.###.#####.#.#.#####.#####.###.#.###.#.#######.#.#####.#.###.#####.#.#.#########.#.#####.#.#######.#.######### +#.#.#...#...#.......#.#...#...#...#.....#.#.#.....#.#...#.#...#...#...#####...#.....#...#...#...#.#.#.....#...#.#.#.....#.........#.........# +#.#.#.#.#.#.#########.###.#.#####.#####.#.#.#####.#.#.#.#.#.#####.#########.#######.#####.###.#.#.#.#####.#.#.#.#.#.#######################.# +#.#...#...#...........#...#.#...#.#.....#.#...#...#.#.#...#.#...#...###.....#.......###...#...#.#.#.#.....#.#.#...#.....#...........#.......# +#.#####################.###.#.#.#.#.#####.###.#.###.#.#####.#.#.###.###.#####.#########.###.###.#.#.#.#####.#.#########.#.#########.#.####### +#.#.............#.......#...#.#.#.#...#...#...#...#.#.#.....#.#...#...#.....#.........#.....###.#.#.#.......#.........#.#.........#.#...#...# +#.#.###########.#.#######.###.#.#.###.#.###.#####.#.#.#.#####.###.###.#####.#########.#########.#.#.#################.#.#########.#.###.#.#.# +#...#.........#...#.......#...#.#...#.#.###...#...#...#.....#...#...#.....#...#.......#.........#.#.........#.........#...#.......#...#...#.# +#####.#######.#####.#######.###.###.#.#.#####.#.###########.###.###.#####.###.#.#######.#########.#########.#.###########.#.#########.#####.# +#...#.#.....#.......#.....#...#.....#.#.#...#.#.###.......#.#...#...#...#.#...#.....###.........#.......#...#.......#...#.#.....#...#...#...# +#.#.#.#.###.#########.###.###.#######.#.#.#.#.#.###.#####.#.#.###.###.#.#.#.#######.###########.#######.#.#########.#.#.#.#####.#.#.###.#.### +#.#...#.#...#...#...#...#...#.......#.#.#.#...#...#.....#...#...#.#...#.#.#...#...#.....###.....#...#...#.........#...#.#.#...#...#...#.#...# +#.#####.#.###.#.#.#.###.###.#######.#.#.#.#######.#####.#######.#.#.###.#.###.#.#.#####.###.#####.#.#.###########.#####.#.#.#.#######.#.###.# +#.....#.#...#.#.#.#.#...#...#.....#.#...#...#...#...#...#...#...#.#.#...#.#...#.#.....#...#.....#.#.#...........#.#...#.#...#...#.....#.....# +#####.#.###.#.#.#.#.#.###.###.###.#.#######.#.#.###.#.###.#.#.###.#.#.###.#.###.#####.###.#####.#.#.###########.#.#.#.#.#######.#.########### +#.....#.###...#...#.#.###.#...###.#.#.......#.#...#.#.#...#.#.#...#.#...#.#...#...#...#...#.....#.#...#...#.....#.#.#.#.#.......#...........# +#.#####.###########.#.###.#.#####.#.#.#######.###.#.#.#.###.#.#.###.###.#.###.###.#.###.###.#####.###.#.#.#.#####.#.#.#.#.#################.# +#.#...#.#...#.......#...#.#.....#.#.#.#.....#.###.#.#.#.#...#.#...#.###...#...#...#...#...#...#...###.#.#.#.....#.#.#.#.#.......#...#...#...# +#.#.#.#.#.#.#.#########.#.#####.#.#.#.#.###.#.###.#.#.#.#.###.###.#.#######.###.#####.###.###.#.#####.#.#.#####.#.#.#.#.#######.#.#.#.#.#.### +#...#...#.#.#...#...#...#.#...#.#...#.#.#...#.#...#.#...#...#...#.#...#.....#...#.....#...###.#.....#...#.......#...#...#.......#.#...#.#...# +#########.#.###.#.#.#.###.#.#.#.#####.#.#.###.#.###.#######.###.#.###.#.#####.###.#####.#####.#####.#####################.#######.#####.###.# +#.........#.....#.#.#...#.#.#.#.#.....#.#...#.#...#...#.....#...#.#...#.....#...#...#...#.....#...#.........###...#...###...#...#...###.#...# +#.###############.#.###.#.#.#.#.#.#####.###.#.###.###.#.#####.###.#.#######.###.###.#.###.#####.#.#########.###.#.#.#.#####.#.#.###.###.#.### +#.#...#.......#...#.#...#...#...#...#...#...#...#.#...#.....#.###.#...#...#.#...#...#...#.#...#.#...#.....#.....#...#...###...#...#...#...### +#.#.#.#.#####.#.###.#.#############.#.###.#####.#.#.#######.#.###.###.#.#.#.#.###.#####.#.#.#.#.###.#.###.#############.#########.###.####### +#.#.#.#.#.....#.#...#.............#.#...#.#...#.#.#.#.......#...#.#...#.#...#...#...#...#.#.#.#.#...#...#.#...#...#...#.........#...#.......# +#.#.#.#.#.#####.#.###############.#.###.#.#.#.#.#.#.#.#########.#.#.###.#######.###.#.###.#.#.#.#.#####.#.#.#.#.#.#.#.#########.###.#######.# +#...#...#.......#.................#.....#...#...#...#...........#...###.........###...###...#...#.......#...#...#...#...........###.........# +#############################################################################################################################################` + result := Solve(input) + if result != 1346 { + t.Errorf("Calculated solution (%d) was not expected", result) + } +}