====== Day 15: Warehouse Woes ====== Der heutige Tag lässt sich über Schleifen (Teil 1) und Rekursion (Teil 2) lösen. Weil es aber insgesamt einige Bedingungen auf einer zweidimensionalen Karte zu beachten gibt, zählt es zu den schwierigeren Rätseln. Aus diesem Grund sind hier auch nur kommentierte Lösungsvorschläge zu sehen. ++++ Lösungsvorschlag Teil 1 | public void partOne() { int width = inputLines.get(0).length(); int height = 0; // ermittle die Höhe der Karte for (String line: inputLines) { if (line.length()==0) { break; } height++; } robot = new int[2]; // als Instanzvariable - speichert x ([0]) und y ([1]) map = new char[width][height]; // Übertrage alle Chars vom Input in die Karte for (int y = 0; y < height; y++) { String line = inputLines.get(y); for (int x = 0; x < width; x++) { map[x][y] = line.charAt(x); if (line.charAt(x) == '@') { // markiere die Position des Roboters robot[0] = x; robot[1] = y; } } } // Speichert die Bewegungsrichtung. [0] ist x- und [1] ist y-Richtung int[] movement = new int[2]; for (int y = height+1; y < inputLines.size(); y++) { String line = inputLines.get(y); for (int x = 0; x < line.length(); x++) { char c = line.charAt(x); if (c == '<') { movement = new int[]{-1, 0}; } else if (c == '^') { movement = new int[]{0, -1}; } else if (c == '>') { movement = new int[]{1, 0}; } else { movement = new int[]{0, 1}; } // rufe die separate Methode auf, die die Bewegung aller beteiligten Blöcke durchführt, sofern möglich move(movement); } } int sumGPS = 0; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (map[x][y] == 'O') { sumGPS += x + 100*y; } } } System.out.println(sumGPS); } private void move(int[] movement) { // finde die nächste freie Stelle in movement-richtung int[] free = robot; int steps = 1; char c = map[robot[0] + movement[0]*steps][robot[1] + movement[1]*steps]; while (c != '#') { if (c == '.') { free = new int[]{robot[0] + movement[0]*steps,robot[1] + movement[1]*steps}; break; } steps++; c = map[robot[0] + movement[0]*steps][robot[1] + movement[1]*steps]; } // falls nichts zu bewegen (free wurde nicht aktualisiert) if (free[0] == robot[0] && free[1] == robot[1]) { return; } // sonst: // bewege alles von free zu robot in die movement-Richtung while (free[0] != robot[0] || free[1] != robot[1]) { map[free[0]][free[1]] = map[free[0]-movement[0]][free[1]-movement[1]]; // bewege free eins "zurück" in Richtung robot free[0] -= movement[0]; free[1] -= movement[1]; } // ehemaliges robot-feld leer-machen map[robot[0]][robot[1]] = '.'; // robot koordinaten aktualisieren; robot[0] += movement[0]; robot[1] += movement[1]; } ++++ ++++ Lösungsvorschlag Teil 2 | public void partTwo() { // Der Beginn ist sehr ähnlich wie Teil 1 int width = inputLines.get(0).length()*2; int height = 0; for (String line: inputLines) { if (line.length()==0) { break; } height++; } robot = new int[2]; map = new char[width][height]; for (int y = 0; y < height; y++) { String line = inputLines.get(y); for (int x = 0; x < line.length(); x++) { map[x*2][y] = line.charAt(x); map[x*2+1][y] = line.charAt(x); if (line.charAt(x) == '@') { // @ = @. robot[0] = x*2; robot[1] = y; map[x*2+1][y] = '.'; } else if (line.charAt(x) == 'O') { // O = [] map[x*2][y] = '['; map[x*2+1][y] = ']'; } } } int[] movement = new int[2]; for (int y = height+1; y < inputLines.size(); y++) { String line = inputLines.get(y); for (int x = 0; x < line.length(); x++) { char c = line.charAt(x); if (c == '<') { movement = new int[]{-1, 0}; } else if (c == '^') { movement = new int[]{0, -1}; } else if (c == '>') { movement = new int[]{1, 0}; } else { movement = new int[]{0, 1}; } // prüfe zunächst, ob sich der Roboter inklusive aller eventuell beteiligten // Schachteln bewegen ließe. if (checkIfFree(robot[0], robot[1], movement)) { // Falls ja, dann bewege entsprechend alles, was dazugehört moveItAll(robot[0], robot[1], movement); // aktualisiere nach der Bewegung die Roboter-Koordinaten robot[0] += movement[0]; robot[1] += movement[1]; } } } int sumGPS = 0; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { // zähle nur den Beginn einer Schachtel if (map[x][y] == '[') { sumGPS += x + 100*y; } } } System.out.println(sumGPS); } /** * "Bewegt" rekursiv die aktuelle Koordinate NACHDEM die davor-liegenden * Koordinaten bewegt wurden. */ private void moveItAll(int x, int y, int[] movement) { // Basisfall: eine freie Stelle -> es gibt nicht zu verschieben if (map[x][y] == '.') { return; } // die nächsten bewegen // links/rechts if (movement[1] == 0) { moveItAll(x+movement[0], y, movement); } else { // hoch/runter // wenn drüber/drunter der Beginn einer Schachtel ist if (map[x][y+movement[1]] == '[') { moveItAll(x, y+movement[1], movement); moveItAll(x+1, y+movement[1], movement); } // wenn drüber/drunter das Ende einer Schachtel ist else if (map[x][y+movement[1]] == ']') { moveItAll(x, y+movement[1], movement); moveItAll(x-1, y+movement[1], movement); } else { moveItAll(x, y+movement[1], movement); } } // das aktuelle bewegen map[x+movement[0]][y+movement[1]] = map[x][y]; // die alte position des aktuellen löschen map[x][y] = '.'; } /** * Prüft rekursiv, ob die aktuelle Koordinate bzw. die in Bewegungsrichtung beteiligten * Koordinaten frei sind. Beachtet auch die neue Schachtel-Breite! */ private boolean checkIfFree(int x, int y, int[] movement) { if (map[x][y] == '.') { return true; } else if (map[x][y] == '#') { return false; } if (movement[1] == 0) { // left/right return checkIfFree(x+movement[0], y, movement); } else { // up/down // wenn drüber/drunter der Beginn einer Schachtel ist if (map[x][y+movement[1]] == '[') { return checkIfFree(x, y+movement[1], movement) && checkIfFree(x+1, y+movement[1], movement); } // wenn drüber/drunter das Ende einer Schachtel ist else if (map[x][y+movement[1]] == ']') { return checkIfFree(x-1, y+movement[1], movement) && checkIfFree(x, y+movement[1], movement); } else { return checkIfFree(x, y+movement[1], movement); } } } ++++