247 lines
8.6 KiB
Java
247 lines
8.6 KiB
Java
package dev.forstenlechner.aoc;
|
|
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.stream.Stream;
|
|
|
|
import static java.util.stream.Collectors.toList;
|
|
|
|
public class Day11 {
|
|
|
|
private enum SeatState {
|
|
EMPTY {
|
|
@Override
|
|
void print() {
|
|
System.out.print("L");
|
|
}
|
|
}, OCCUPIED {
|
|
@Override
|
|
void print() {
|
|
System.out.print("#");
|
|
}
|
|
}, FLOOR {
|
|
@Override
|
|
void print() {
|
|
System.out.print(".");
|
|
}
|
|
};
|
|
|
|
abstract void print();
|
|
|
|
static SeatState from(char c) {
|
|
return switch (c) {
|
|
case 'L' -> EMPTY;
|
|
case '#' -> OCCUPIED;
|
|
default -> FLOOR;
|
|
};
|
|
}
|
|
}
|
|
|
|
private record Location(int row, int col) {};
|
|
|
|
private enum Directon {
|
|
UP {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() -1, cur.col);
|
|
}
|
|
}, DOWN {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() +1, cur.col);
|
|
}
|
|
}, LEFT{
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row(), cur.col -1);
|
|
}
|
|
}, RIGHT{
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row(), cur.col +1);
|
|
}
|
|
}, LEFT_UP {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() -1, cur.col -1);
|
|
}
|
|
}, LEFT_DOWN {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() +1, cur.col -1);
|
|
}
|
|
}, RIGHT_UP {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() -1, cur.col +1);
|
|
}
|
|
}, RIGHT_DOWN {
|
|
@Override
|
|
Location next(Location cur) {
|
|
return new Location(cur.row() +1, cur.col +1);
|
|
}
|
|
};
|
|
|
|
abstract Location next(Location cur);
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
new Day11().solve();
|
|
}
|
|
|
|
private List<List<SeatState>> copySeatMap(List<List<SeatState>> seatMap) {
|
|
return seatMap.stream().map(ArrayList::new).collect(toList());
|
|
}
|
|
|
|
private void solve() throws Exception {
|
|
Stream<String> lines = Files.lines(Paths.get("day11/input"));
|
|
List<List<SeatState>> seatMap = lines
|
|
.map(l -> l.chars().mapToObj(c -> (char) c).map(SeatState::from).collect(toList()))
|
|
.collect(toList());
|
|
|
|
solveFirst(seatMap);
|
|
|
|
solveSecond(seatMap);
|
|
}
|
|
|
|
private void printMap(List<List<SeatState>> seatMap) {
|
|
seatMap.forEach(row -> {
|
|
row.forEach(SeatState::print);
|
|
System.out.println();
|
|
});
|
|
}
|
|
|
|
private void solveSecond(List<List<SeatState>> seatMap) {
|
|
boolean changed = true;
|
|
while (changed) {
|
|
// printMap(seatMap);
|
|
// System.out.println();
|
|
changed = false;
|
|
var nextSeatMap = copySeatMap(seatMap);
|
|
for (int row = 0; row < seatMap.size(); row++) {
|
|
for (int column = 0; column < seatMap.get(row).size(); column++) {
|
|
SeatState prev = seatMap.get(row).get(column);
|
|
SeatState next = calcSeatWithDirection(seatMap, row, column);
|
|
changed |= prev != next;
|
|
nextSeatMap.get(row).set(column, next);
|
|
}
|
|
}
|
|
seatMap = nextSeatMap;
|
|
}
|
|
|
|
Long occupiedSeats = seatMap.stream().map(col -> col.stream().filter(state -> state == SeatState.OCCUPIED).count()).reduce(0L, Long::sum);
|
|
System.out.println(occupiedSeats);
|
|
}
|
|
|
|
private void solveFirst(List<List<SeatState>> seatMap) {
|
|
boolean changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
var nextSeatMap = copySeatMap(seatMap);
|
|
for (int row = 0; row < seatMap.size(); row++) {
|
|
for (int column = 0; column < seatMap.get(row).size(); column++) {
|
|
SeatState prev = seatMap.get(row).get(column);
|
|
SeatState next = calcSeat(seatMap, row, column);
|
|
changed |= prev != next;
|
|
nextSeatMap.get(row).set(column, next);
|
|
}
|
|
}
|
|
seatMap = nextSeatMap;
|
|
}
|
|
|
|
Long occupiedSeats = seatMap.stream().map(col -> col.stream().filter(state -> state == SeatState.OCCUPIED).count()).reduce(0L, Long::sum);
|
|
System.out.println(occupiedSeats);
|
|
}
|
|
|
|
private SeatState calcSeat(List<List<SeatState>> seatMap, int row, int column) {
|
|
int occupiedSeatsAround = 0;
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row-1, column-1);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row-1, column);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row-1, column+1);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row+1, column-1);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row+1, column);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row+1, column+1);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row, column-1);
|
|
occupiedSeatsAround += isSeatOccupiedInt(seatMap, row, column+1);
|
|
|
|
if (seatMap.get(row).get(column) == SeatState.EMPTY && occupiedSeatsAround == 0) {
|
|
return SeatState.OCCUPIED;
|
|
}
|
|
if (seatMap.get(row).get(column) == SeatState.OCCUPIED && occupiedSeatsAround >= 4) {
|
|
return SeatState.EMPTY;
|
|
}
|
|
return seatMap.get(row).get(column);
|
|
}
|
|
|
|
private int isSeatOccupiedInt(List<List<SeatState>> seatMap, int row, int column) {
|
|
if (row >= 0 && row < seatMap.size()
|
|
&& column >= 0 && column < seatMap.get(row).size()) {
|
|
return seatMap.get(row).get(column) == SeatState.OCCUPIED ? 1 : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private SeatState calcSeatWithDirection(List<List<SeatState>> seatMap, int row, int column) {
|
|
int occupiedSeatsAround = 0;
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.UP);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.DOWN);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.LEFT);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.RIGHT);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.LEFT_UP);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.LEFT_DOWN);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.RIGHT_UP);
|
|
occupiedSeatsAround += isSeatOccupiedIntWithDirection(seatMap, row, column, Directon.RIGHT_DOWN);
|
|
|
|
if (seatMap.get(row).get(column) == SeatState.EMPTY && occupiedSeatsAround == 0) {
|
|
return SeatState.OCCUPIED;
|
|
}
|
|
if (seatMap.get(row).get(column) == SeatState.OCCUPIED && occupiedSeatsAround >= 5) { // change in rule!
|
|
return SeatState.EMPTY;
|
|
}
|
|
return seatMap.get(row).get(column);
|
|
}
|
|
|
|
private int isSeatOccupiedIntWithDirection(List<List<SeatState>> seatMap, int row, int column, Directon directon) {
|
|
return isSeatOccupiedIntWithDirection(seatMap, new Location(row, column), directon);
|
|
}
|
|
|
|
private int isSeatOccupiedIntWithDirection(List<List<SeatState>> seatMap, Location test, Directon directon) {
|
|
test = directon.next(test);
|
|
while (test.row() >= 0 && test.row() < seatMap.size()
|
|
&& test.col() >= 0 && test.col() < seatMap.get(test.row()).size()
|
|
&& seatMap.get(test.row).get(test.col()) == SeatState.FLOOR) {
|
|
test = directon.next(test);
|
|
}
|
|
if (test.row() >= 0 && test.row() < seatMap.size()
|
|
&& test.col() >= 0 && test.col() < seatMap.get(test.row()).size()) {
|
|
return seatMap.get(test.row()).get(test.col()) == SeatState.OCCUPIED ? 1 : 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|