import std; void main() { File("input", "r").byLineCopy.array.calculateNumberOfOccupiedSeatsStable.writeln; } auto calculateValidNeighbouringSeatPositions(size_t i, size_t j, size_t height, size_t width) { return [ tuple(i - 1, j - 1), tuple(i - 1, j), tuple(i - 1, j + 1), tuple(i, j - 1), tuple(i, j + 1), tuple(i + 1, j - 1), tuple(i + 1, j), tuple(i + 1, j + 1) ].filter!(position => position[0] >= 0 && position[0] < height && position[1] >= 0 && position[1] < width); } auto calculateNewSeatState(const char seat, ulong numberOfOccupiedNeighbouringSeats) { if (seat == '#' && numberOfOccupiedNeighbouringSeats >= 4) { return 'L'; } else if (seat == 'L' && numberOfOccupiedNeighbouringSeats == 0) { return '#'; } else { return seat; } } auto calculateNextSeatOccupation(const char[][] seats) { if (seats.empty || seats.front.empty) { return seats; } immutable height = seats.length; immutable width = seats.front.length; return seats.enumerate.map!((indexedRow) { immutable i = indexedRow.index; const row = indexedRow.value; return row.byChar.enumerate.map!((indexedSeat) { immutable j = indexedSeat.index; immutable seat = indexedSeat.value; immutable numberOfOccupiedNeighbouringSeats = calculateValidNeighbouringSeatPositions(i, j, height, width).map!(position => seats[position[0]][position[1]]) .filter!(it => it == '#') .count; return seat.calculateNewSeatState(numberOfOccupiedNeighbouringSeats); }).array; }).array; } unittest { auto input = `L.LL.LL.LL LLLLLLL.LL L.L.L..L.. LLLL.LL.LL L.LL.LL.LL L.LLLLL.LL ..L.L..... LLLLLLLLLL L.LLLLLL.L L.LLLLL.LL`.dup.split("\n"); assert(input.calculateNextSeatOccupation.join("\n") == `#.##.##.## #######.## #.#.#..#.. ####.##.## #.##.##.## #.#####.## ..#.#..... ########## #.######.# #.#####.##`); } unittest { auto input = `#.##.##.## #######.## #.#.#..#.. ####.##.## #.##.##.## #.#####.## ..#.#..... ########## #.######.# #.#####.##`.dup.split("\n"); assert(input.calculateNextSeatOccupation.join("\n") == `#.LL.L#.## #LLLLLL.L# L.L.L..L.. #LLL.LL.L# #.LL.LL.LL #.LLLL#.## ..L.L..... #LLLLLLLL# #.LLLLLL.L #.#LLLL.##`); } unittest { auto input = `#.LL.L#.## #LLLLLL.L# L.L.L..L.. #LLL.LL.L# #.LL.LL.LL #.LLLL#.## ..L.L..... #LLLLLLLL# #.LLLLLL.L #.#LLLL.##`.dup.split("\n"); assert(input.calculateNextSeatOccupation.join("\n") == `#.##.L#.## #L###LL.L# L.#.#..#.. #L##.##.L# #.##.LL.LL #.###L#.## ..#.#..... #L######L# #.LL###L.L #.#L###.##`); } unittest { auto input = `#.##.L#.## #L###LL.L# L.#.#..#.. #L##.##.L# #.##.LL.LL #.###L#.## ..#.#..... #L######L# #.LL###L.L #.#L###.##`.dup.split("\n"); assert(input.calculateNextSeatOccupation.join("\n") == `#.#L.L#.## #LLL#LL.L# L.L.L..#.. #LLL.##.L# #.LL.LL.LL #.LL#L#.## ..L.L..... #L#LLLL#L# #.LLLLLL.L #.#L#L#.##`); } unittest { auto input = `#.#L.L#.## #LLL#LL.L# L.L.L..#.. #LLL.##.L# #.LL.LL.LL #.LL#L#.## ..L.L..... #L#LLLL#L# #.LLLLLL.L #.#L#L#.##`.dup.split("\n"); assert(input.calculateNextSeatOccupation.join("\n") == `#.#L.L#.## #LLL#LL.L# L.#.L..#.. #L##.##.L# #.#L.LL.LL #.#L#L#.## ..L.L..... #L#L##L#L# #.LLLLLL.L #.#L#L#.##`); } auto calculateNumberOfOccupiedSeatsStable(const char[][] seats) { return recurrence!((seats, n) => seats[n - 1].calculateNextSeatOccupation)(seats).slide(2) .map!array .find!((pair) => pair[0] == pair[1]) .front .front .join .filter!(seat => seat == '#') .count; } unittest { auto input = `L.LL.LL.LL LLLLLLL.LL L.L.L..L.. LLLL.LL.LL L.LL.LL.LL L.LLLLL.LL ..L.L..... LLLLLLLLLL L.LLLLLL.L L.LLLLL.LL`.dup.split("\n"); assert(input.calculateNumberOfOccupiedSeatsStable == 37); }