Skip to content

Commit 1f92e1f

Browse files
committed
Day 23 java
1 parent 512dd4c commit 1f92e1f

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

2021/java/src/main/java/aoc2021/D22.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ long countOn() { // number of cubes set on
5050
}
5151

5252
Cube intersect(Cube c) { // intersect of two cubes
53-
return new Cube(!c.on, x.intersect(c.x), y.intersect(c.y), z.intersect(c.z));
53+
return new Cube(c.on, x.intersect(c.x), y.intersect(c.y), z.intersect(c.z));
5454
}
5555

5656
boolean valid() { // if this cube is a valid cube
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package aoc2021;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.Collections;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.OptionalInt;
9+
import java.util.concurrent.ConcurrentHashMap;
10+
import java.util.stream.IntStream;
11+
import java.util.stream.Stream;
12+
import static java.lang.Math.max;
13+
import static java.lang.Math.min;
14+
15+
/**
16+
* Advent of Code (AOC) 2021 Day 23 Amphipod
17+
*/
18+
public class D23 {
19+
20+
record State(List<List<String>> rooms, List<String> hallway) {
21+
int roomSize() {
22+
return amphipods().mapToInt(a -> a.charAt(1) - '0').max().getAsInt();
23+
}
24+
Stream<String> amphipodsInRooms() {
25+
return rooms.stream().flatMap(r -> r.stream()).filter(a -> a.length() > 1);
26+
}
27+
Stream<String> amphipods() {
28+
return Stream.concat(hallway.stream().filter(a -> a.length() > 1), amphipodsInRooms());
29+
}
30+
}
31+
32+
record Move(State state, int energy){}
33+
34+
public static void main(String... args) throws IOException {
35+
State state1 = new State(List.of(List.of("D1","C1"), List.of("C2", "A1"), List.of("D2","A2"), List.of("B1","B2")), Collections.nCopies(11, "."));
36+
State state2 = new State(List.of(List.of("D1","D3","D4","C1"), List.of("C2","C3","B3", "A1"), List.of("D2","B4","A3","A2"), List.of("B1","A4","C4","B2")), Collections.nCopies(11, "."));
37+
38+
int part1 = solve(state1);
39+
System.out.printf("part 1: %s\n", part1);
40+
41+
int part2 = solve(state2); // will take some time
42+
System.out.printf("part 2: %s\n", part2);
43+
}
44+
45+
static int solve(State state) {
46+
Map<State,Integer> energy = new ConcurrentHashMap<>(Map.of(state, 0)); // States and lowest energy to achieve the state
47+
int min = Integer.MAX_VALUE;
48+
for (int updated = 0; energy.size() > updated;) { //while no more updates
49+
updated = energy.size();
50+
// get all the possible moves from current states forward
51+
var possible = energy.entrySet().stream().flatMap(e -> possibleMoves(e.getKey(), e.getValue()).stream()).toList();
52+
possible.forEach(m -> energy.merge(m.state, m.energy, (a,b) -> min(a,b))); // merge new minimum energy values
53+
// check if we have finish moves and get minimum energy for those
54+
int possinleMin = possible.stream().filter(m -> finished(m.state)).mapToInt(m -> m.energy).min().orElse(Integer.MAX_VALUE);
55+
min = min(min, possinleMin);
56+
}
57+
return min;
58+
}
59+
60+
static boolean finished(State state) { // All rooms have correct entries inside
61+
return IntStream.range(0, 4).mapToObj(i -> state.rooms.get(i).stream().allMatch(r -> r.charAt(0) == 'A' + i)).allMatch(b -> b == true);
62+
}
63+
64+
static List<Move> possibleMoves(State state, int energy) {
65+
return state.amphipods().flatMap(amph -> possibleMoves(amph, state, energy).stream()).toList();
66+
}
67+
68+
static List<Move> possibleMoves(String amphipod, State state, int energy) { // all the possible moves for single amphipod
69+
List<Move> moves = new ArrayList<>();
70+
moves.addAll(hallwayToRoom(amphipod, state, energy));
71+
moves.addAll(roomToHallway(amphipod, state, energy));
72+
return moves;
73+
}
74+
75+
static List<Move> roomToHallway(String amph, State state, int energy) {
76+
OptionalInt currentRoom = IntStream.range(0, 4).filter(i -> state.rooms.get(i).contains(amph)).findAny();
77+
if (finished(amph, state) || !currentRoom.isPresent()) {
78+
return List.of();
79+
}
80+
List<String> room = state.rooms.get(currentRoom.getAsInt());
81+
if (!room.stream().dropWhile(p -> p.equals(".")).findFirst().get().equals(amph)) { // first in room to m ove
82+
return List.of();
83+
}
84+
int toHallwaySteps = room.indexOf(amph) + 1;
85+
int hallIndex = roomHallIndex(currentRoom.getAsInt());
86+
87+
List<Move> res = new ArrayList<>();
88+
for (int i = 0; i < 11; i++) { // iterate through hall
89+
if (!roomToHallway.contains(i) && clearPath(amph, i, hallIndex, state)) { // ignore doorways and check for clear path
90+
List<String> r = state.rooms.get(currentRoom.getAsInt());
91+
var nroom = replace(r, r.indexOf(amph), ".");
92+
var rooms = replace(state.rooms, currentRoom.getAsInt(), nroom);
93+
var hall = replace(state.hallway, i, amph);
94+
State s = new State(rooms, hall); // new state
95+
res.add(new Move(s, energy + energy(amph, toHallwaySteps+Math.abs(hallIndex-i))));
96+
}
97+
98+
}
99+
return res;
100+
}
101+
102+
static List<Move> hallwayToRoom(String amph, State state, int energy) {
103+
int amphIdx = state.hallway.indexOf(amph);
104+
if (amphIdx != -1) { // amphipod is in hallway
105+
List<String> room = targetRoom(amph, state);
106+
int hallRoomIdx = targetRoomHallIndex(amph, state);
107+
if (acceptIntoRoom(room, amph) && clearPathToRoom(amph, state)) { // it can move to room
108+
int roomIdx = IntStream.range(0, room.size()).filter(i -> !room.get(i).equals(".")).findFirst().orElse(room.size())-1;
109+
var newRoom = replace(room, roomIdx, amph);
110+
var rooms = replace(state.rooms, targetRoomIndex(amph), newRoom);
111+
var hall = replace(state.hallway, amphIdx, ".");
112+
int steps = max(hallRoomIdx, amphIdx) - min(hallRoomIdx, amphIdx);
113+
Move m = new Move(new State(rooms, hall), energy + energy(amph, steps + roomIdx + 1));
114+
return List.of(m);
115+
}
116+
}
117+
return List.of();
118+
}
119+
120+
static Map<Character,Integer> energy = Map.of('A',1, 'B', 10, 'C', 100, 'D', 1000);
121+
122+
static int energy(String amph, int steps) {
123+
return energy.get(amph.charAt(0)) * steps;
124+
}
125+
126+
static boolean acceptIntoRoom(List<String> room, String amphipod) {
127+
return !room.stream().anyMatch(a -> !(a.startsWith(amphipod.substring(0, 1)) || a.equals(".")));
128+
}
129+
130+
static int targetRoomHallIndex(String amphipod, State state) {
131+
return roomToHallway.get(amphipod.charAt(0)-'A');
132+
}
133+
134+
static List<Integer> roomToHallway = List.of(2, 4, 6, 8);
135+
static int roomHallIndex(int roomIndex) {
136+
return roomToHallway.get(roomIndex);
137+
}
138+
139+
static List<String> targetRoom(String amph, State state) {
140+
return state.rooms.get(targetRoomIndex(amph));
141+
}
142+
143+
static int targetRoomIndex(String amph) {
144+
return amph.charAt(0) - 'A';
145+
}
146+
147+
static boolean finished(String amph, State state) {
148+
List<String> room = targetRoom(amph, state);
149+
if (!room.contains(amph)) {
150+
return false;
151+
}
152+
return !room.stream()
153+
.dropWhile(a -> !a.equals(amph))
154+
.anyMatch(a -> !a.startsWith(amph.substring(0,1)));
155+
}
156+
157+
static boolean clearPath(String amph, int idx1, int idx2, State state) {
158+
List<String> path = state.hallway.subList(min(idx1, idx2), max(idx1, idx2)+1);
159+
return !path.stream().anyMatch(h -> !h.equals(amph) && h.length() > 1);
160+
}
161+
162+
static boolean clearPathToRoom(String amph, State state) {
163+
return clearPath(amph, targetRoomHallIndex(amph, state), state.hallway.indexOf(amph), state);
164+
}
165+
166+
static boolean sameTypeInLast(char amphipod, String room) {
167+
return Character.toUpperCase(room.charAt(1)) == Character.toUpperCase(amphipod);
168+
}
169+
170+
static <T> List<T> replace(List<T> list, int index, T value) {
171+
List<T> l = new ArrayList<>(list);
172+
l.set(index, value);
173+
return l;
174+
}
175+
}

0 commit comments

Comments
 (0)