@SuppressWarnings("serial") public class HilfPingu extends PenguinPen { private static final int[][] penguinPen = generatePenguinPen(24, 17); private static final int width = penguinPen.length; private static final int height = penguinPen[0].length; private static int x = 1, y = 0; // Spielerposition // Für Wechsulinen müssen wir die Bewegungsrichtungen zwischenspeichern, damit // die Rechte-Hand-Regel pro Wechsuline angewendet werden kann. private static int[][] direction = createSingleValue2DArray(width, height, -1); // Konstanten für das Bewegen von Objekten (Pinguinen / NICHT Spieler): public static final int DIRECTION_DEFAULT = -1; public static final int DIRECTION_DOWN = 0; public static final int DIRECTION_RIGHT = 1; public static final int DIRECTION_UP = 2; public static final int DIRECTION_LEFT = 3; public static void move(int direction) { // Bewegung nicht möglich? Nichts tun. if (!canMove(direction)) { // darf keine Mauer sein System.out.println("Dieser Zug ist nicht möglich."); return; } // Schritt 1: Füttern der Pinguine (aktuelle Position) for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) if (y + j >= 0 && penguin(x + i, y + j)) { penguinPen[x + i][y + j] = FREE; // soll verschwinden System.out.println("(" + (x+i) + "," + (y+j) + ") wird frei -- Pinguin ist satt."); } // Schritt 3: Spieler bewegen penguinPen[x][y] = FREE; // alte Position frei machen int oldX = x, oldY = y; switch (direction) { // Neue Position berechnen: case MOVE_LEFT: x--; break; case MOVE_RIGHT: x++; break; case MOVE_UP: y--; break; case MOVE_DOWN: y++; break; } penguinPen[x][y] = ZOOKEEPER; // neue Position besetzen System.out.println("(" + oldX + "," + oldY + ") ==> (" + x + "," + y + ") -- Spielschritt."); // Schritt 2: Pinguine bewegen movePenguins(); // Änderungen sichtbar machen draw(penguinPen); } /** Gibt true zurück, falls ein Zug in die übergebene Richtung möglich ist. */ private static boolean canMove(int direction) { int xNew = x, yNew = y; switch (direction) { case MOVE_LEFT: xNew--; break; case MOVE_RIGHT: xNew++; break; case MOVE_UP: yNew--; break; case MOVE_DOWN: yNew++; break; default: return false; // ungültige Richtung } if (xNew < 0 || yNew < 0 || xNew >= width || yNew >= height) return false; return !wall(xNew, yNew); // free reicht nicht! } private static boolean free(int x, int y) { return penguinPen[x][y] == FREE; } private static boolean penguin(int x, int y) { return penguinPen[x][y] >= PENGUIN_OOO && penguinPen[x][y] <= PENGUIN_IOO; } private static boolean wall(int x, int y) { return penguinPen[x][y] == WALL; } /** * Führt die Bewegung für alle Pinguine entsprechend der angegebenen Regeln * durch. Es wird davon ausgegangen, dass der Spieler zuvor schon bewegt wurde * (also das Zielfeld bereits belegt wurde). */ private static void movePenguins() { // Altes Array kopieren, sonst könnte es vorkommen, dass wir bestimmte // Pinguine mehrfach bewegen (bei Bewegung nach rechts/unten). Wir // iterieren dann über die Array-Kopie (d. h. wir holen uns die zu // bewegenden Pinguine daraus), schreiben bzw. prüfen aber immer ins // bzw. mit dem aktuellen (veränderten) Array. int[][] oldPen = new int[width][height]; for (int x = 0; x < width; x++) for (int y = 0; y < height; y++) oldPen[x][y] = penguinPen[x][y]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { switch (oldPen[x][y]) { case PENGUIN_OOI: // Zufulline moveZufullin(x, y); break; case PENGUIN_OIO: // Wechsuline moveWechsulin(x, y); break; case PENGUIN_OII: // Springuine moveSpringuin(x, y); break; case PENGUIN_IOO: // Schlauine moveSchlauin(x, y); break; } } } } /** Liefert die Zielposition als Array für eine bestimmte Position und Richtung. */ private static int[] getGoalPosition(int x, int y, int direction) { switch (direction) { case DIRECTION_DOWN: return new int[] {x, y+1}; case DIRECTION_DEFAULT: // nur für Wechsuline case DIRECTION_RIGHT: return new int[] {x+1, y}; case DIRECTION_UP: return new int[] {x, y-1}; case DIRECTION_LEFT: return new int[] {x-1, y}; default: return null; } } /** Bewegt das Objekt an Position [x, y] an eine andere Position. */ private static void movePenguin(int x, int y, int[] to) { int obj = penguinPen[x][y]; penguinPen[x][y] = FREE; // alte Position frei machen penguinPen[to[0]][to[1]] = obj; // neue Position besetzen System.out.println("(" + x + "," + y + ") ==> (" + to[0] + "," + to[1] + ") -- Pinguin flüchtet."); } private static void moveZufullin(int x, int y) { int possibleDirections = 0; // Anzahl möglicher Richtungen berechnen if (free(x, y + 1)) possibleDirections++; if (free(x + 1, y)) possibleDirections++; if (y > 0 && free(x, y - 1)) possibleDirections++; if (free(x - 1, y)) possibleDirections++; if (possibleDirections > 0) { // Array mit möglichen Richtungen befüllen int[] directions = new int[possibleDirections]; if (free(x, y + 1)) directions[--possibleDirections] = DIRECTION_DOWN; if (free(x + 1, y)) directions[--possibleDirections] = DIRECTION_RIGHT; if (y > 0 && free(x, y - 1)) directions[--possibleDirections] = DIRECTION_UP; if (free(x - 1, y)) directions[--possibleDirections] = DIRECTION_LEFT; // Zug in zufällige Richtung durchführen: int randomDirection = (int) (directions.length * Math.random()); movePenguin(x, y, getGoalPosition(x, y, directions[randomDirection])); } } /** Führt einen Zug in eine Richtung aus. Dazu muss die Zielposition berechnet werden * und die Richtung an der Zielposition gesetzt werden (da Position auch geändert wird). */ private static void performMoveWechsulin(int x, int y, int direction) { int[] newPos = getGoalPosition(x, y, direction); HilfPingu.direction[newPos[0]][newPos[1]] = direction; movePenguin(x, y, newPos); } private static void moveWechsulin(int x, int y) { if (y == 0) { // am Eingang 180° Drehung if (free(x, 1)) performMoveWechsulin(x, y, DIRECTION_DOWN); return; } if (direction[x][y] == DIRECTION_DEFAULT) { // Anfangszustand (nach rechts) if (wall(x+1, y)) { // Mauer vor uns -> ab jetzt RHR direction[x][y] = DIRECTION_UP; // -> linksherum drehen // neu prüfen (unteres if) } else if (free(x+1, y)) { // -> weiter nach rechts performMoveWechsulin(x, y, direction[x][y]); return; } } if (direction[x][y] == DIRECTION_DOWN && wall(x-1, y) || direction[x][y] == DIRECTION_RIGHT && wall(x, y+1) || direction[x][y] == DIRECTION_UP && wall(x+1, y) || direction[x][y] == DIRECTION_LEFT && wall(x, y-1)) { // -> Mauer rechts von uns if (direction[x][y] == DIRECTION_DOWN && wall(x, y+1) || direction[x][y] == DIRECTION_RIGHT && wall(x+1, y) || direction[x][y] == DIRECTION_UP && wall(x, y-1) || direction[x][y] == DIRECTION_LEFT && wall(x-1, y)) { // -> Mauer vor uns direction[x][y]++; // linksherum drehen direction[x][y] %= 4; // 4 -> 0 moveWechsulin(x, y); // neu prüfen (ggf. 180°) } else if (direction[x][y] == DIRECTION_DOWN && free(x, y+1) || direction[x][y] == DIRECTION_RIGHT && free(x+1, y) || direction[x][y] == DIRECTION_UP && free(x, y-1) || direction[x][y] == DIRECTION_LEFT && free(x-1, y)) { // -> Geradeaus frei (auch nicht durch anderen Pinguin blockiert) performMoveWechsulin(x, y, direction[x][y]); } } else if (direction[x][y] == DIRECTION_DOWN && free(x-1, y) || direction[x][y] == DIRECTION_RIGHT && free(x, y+1) || direction[x][y] == DIRECTION_UP && free(x+1, y) || direction[x][y] == DIRECTION_LEFT && free(x, y-1)) { // -> Kein anderer Pinguin blockiert den Weg nach rechts (und keine Mauer rechts von uns) performMoveWechsulin(x, y, (direction[x][y] + 3) % 4); } } private static void moveSpringuin(int x, int y) { // Anzahl möglicher Positionen ermitteln: int possiblePositions = 0; for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) if (free(i, j)) possiblePositions++; if (possiblePositions > 0) { int[][] positions = new int[possiblePositions][2]; for (int i = 0; i < width; i++) for (int j = 0; j < height; j++) if (free(i, j)) { --possiblePositions; positions[possiblePositions][0] = i; positions[possiblePositions][1] = j; } // Zug an zufällige Position durchführen: int randomIndex = (int) (positions.length * Math.random()); movePenguin(x, y, positions[randomIndex]); } } private static void moveSchlauin(int x, int y) { int oldDistance = calcDistance(x, y); // Gehe in die erste Richtung, die die Distanz zum Pfleger erhöht // (kann sowieso nur um maximal 1 größer sein), sonst gar nicht. if (free(x, y+1) && calcDistance(x, y+1) > oldDistance) movePenguin(x, y, getGoalPosition(x, y, DIRECTION_DOWN)); else if (free(x+1, y) && calcDistance(x+1, y) > oldDistance) movePenguin(x, y, getGoalPosition(x, y, DIRECTION_RIGHT)); else if (y > 0 && free(x, y-1) && calcDistance(x, y-1) > oldDistance) movePenguin(x, y, getGoalPosition(x, y, DIRECTION_UP)); else if (free(x-1, y) && calcDistance(x-1, y) > oldDistance) movePenguin(x, y, getGoalPosition(x, y, DIRECTION_LEFT)); } /** Berechnet den Abstand zwischen Spieler und übergebenen Koordinaten. */ private static int calcDistance(int x, int y) { return Math.abs(HilfPingu.x - x) + Math.abs(HilfPingu.y - y); } private static int[][] createSingleValue2DArray(int lines, int columns, int value) { int[][] arr = new int[lines][columns]; for (int i = 0; i < width; i++) for (int j = 0; j < columns; j++) arr[i][j] = value; return arr; } /*********************************************/ /* Ab hier soll nichts mehr geändert werden! */ /*********************************************/ public static void main(String[] args) { draw(penguinPen); handleUserInput(); } private static void handleUserInput() { while (true) { try { Thread.sleep(10); } catch (InterruptedException ie) { /* Intentionally left blank */ } int step = nextStep(); if (step != NO_MOVE) { // System.out.print(step+","); move(step); } } } }