148 lines
3.4 KiB
D
148 lines
3.4 KiB
D
import std;
|
|
|
|
void main()
|
|
{
|
|
File("input", "r").byLineCopy.array.calculateNumberOfOccupiedSeatsStable.writeln;
|
|
}
|
|
|
|
auto calculateNewSeatState(const char seat, ulong numberOfSeenOccupiedSeats)
|
|
{
|
|
if (seat == '#' && numberOfSeenOccupiedSeats >= 5)
|
|
{
|
|
return 'L';
|
|
}
|
|
else if (seat == 'L' && numberOfSeenOccupiedSeats == 0)
|
|
{
|
|
return '#';
|
|
}
|
|
else
|
|
{
|
|
return seat;
|
|
}
|
|
}
|
|
|
|
auto generateIndexes(ptrdiff_t posY, ptrdiff_t posX, ptrdiff_t y, ptrdiff_t x)
|
|
{
|
|
return recurrence!((state, n) => tuple(state[n - 1][0] + y, state[n - 1][1] + x))(
|
|
tuple(posY, posX)).drop(1);
|
|
}
|
|
|
|
auto isValidPosition(Tuple!(ptrdiff_t, ptrdiff_t) pos, size_t height, size_t width)
|
|
{
|
|
return pos[0] >= 0 && pos[0] < height && pos[1] >= 0 && pos[1] < width;
|
|
}
|
|
|
|
auto findFirstSeatInDirection(const char[][] seats, const Tuple!(ptrdiff_t,
|
|
ptrdiff_t) direction, const Tuple!(ptrdiff_t,
|
|
ptrdiff_t) initialPosition, const size_t height, const size_t width)
|
|
{
|
|
return generateIndexes(initialPosition[0], initialPosition[1], direction[0], direction[1]).until!(
|
|
pos => !pos.isValidPosition(height, width))
|
|
.map!(pos => seats[pos[0]][pos[1]])
|
|
.find!(seat => seat != '.');
|
|
}
|
|
|
|
auto calculateNextSeatOccupation(const char[][] seats)
|
|
{
|
|
if (seats.empty || seats.front.empty)
|
|
{
|
|
return seats;
|
|
}
|
|
auto height = seats.length;
|
|
auto width = seats.front.length;
|
|
|
|
return seats.enumerate.map!((indexedRow) {
|
|
ptrdiff_t i = indexedRow.index;
|
|
auto row = indexedRow.value;
|
|
return row.byChar.enumerate.map!((indexedSeat) {
|
|
ptrdiff_t j = indexedSeat.index;
|
|
auto seat = indexedSeat.value;
|
|
auto numberOfSeenOccupiedSeats = [
|
|
tuple(0L, 1L), tuple(-1L, 1L), tuple(-1L, 0L), tuple(-1L,
|
|
-1L), tuple(0L, -1L), tuple(1L, -1L), tuple(1L, 0L), tuple(1L, 1L)
|
|
].map!(direction => findFirstSeatInDirection(seats, direction,
|
|
tuple(i, j), height, width))
|
|
.filter!(lineOfSight => !lineOfSight.empty)
|
|
.map!(lineOfSeight => lineOfSeight.front)
|
|
.filter!(it => it == '#')
|
|
.count;
|
|
return seat.calculateNewSeatState(numberOfSeenOccupiedSeats);
|
|
}).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.LL.L#
|
|
#LLLLLL.LL
|
|
L.L.L..L..
|
|
LLLL.LL.LL
|
|
L.LL.LL.LL
|
|
L.LLLLL.LL
|
|
..L.L.....
|
|
LLLLLLLLL#
|
|
#.LLLLLL.L
|
|
#.LLLLL.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 == 26);
|
|
}
|