diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Orientation.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Orientation.java new file mode 100644 index 0000000..6ebf10d --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Orientation.java @@ -0,0 +1,28 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; + +public enum Orientation { + NONE, + RIGHT, + LEFT, + UPSIDE_DOWN; + + public Orientation rotated(boolean clockwise) { + switch(this) { + case NONE -> { + return clockwise ? Orientation.RIGHT : Orientation.LEFT; + } + case RIGHT -> { + return clockwise ? Orientation.UPSIDE_DOWN : Orientation.NONE; + } + case UPSIDE_DOWN -> { + return clockwise ? Orientation.LEFT : Orientation.RIGHT; + } + case LEFT -> { + return clockwise ? Orientation.NONE : Orientation.UPSIDE_DOWN; + } + default -> { + return Orientation.NONE; + } + } + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/RotationChecker.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/RotationChecker.java new file mode 100644 index 0000000..893b1f4 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/RotationChecker.java @@ -0,0 +1,38 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; + +import java.util.Map; + +public final class RotationChecker { + private record RotationKey(Orientation from, Orientation to) {} + + private static final Map STANDARD_WALL_KICKS = Map.of( + new RotationKey(Orientation.NONE, Orientation.RIGHT), new int[][] {{0,0}, {-1,0}, {-1,1}, {0,-2}, {-1,-2}}, + new RotationKey(Orientation.RIGHT, Orientation.NONE), new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}}, + new RotationKey(Orientation.RIGHT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}}, + new RotationKey(Orientation.UPSIDE_DOWN, Orientation.RIGHT), new int[][] {{0,0}, {-1,0}, {-1,1}, {0,-2}, {-1,-2}}, + new RotationKey(Orientation.UPSIDE_DOWN, Orientation.LEFT), new int[][] {{0,0}, {1,0}, {1,1}, {0,-2}, {1,-2}}, + new RotationKey(Orientation.LEFT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}}, + new RotationKey(Orientation.LEFT, Orientation.NONE), new int[][] {{0,0}, {-1,0}, {-1,-1}, {0,2}, {-1,2}}, + new RotationKey(Orientation.NONE, Orientation.LEFT), new int[][] {{0,0}, {1,0}, {1,1}, {0,-2}, {1,-2}} + ); + + private static final Map I_WALL_KICKS = Map.of( + new RotationKey(Orientation.NONE, Orientation.RIGHT), new int[][] {{0,0}, {-2,0}, {1,0}, {-2,-1}, {1,2}}, + new RotationKey(Orientation.RIGHT, Orientation.NONE), new int[][] {{0,0}, {2,0}, {-1,0}, {2,1}, {-1,-2}}, + new RotationKey(Orientation.RIGHT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-1,0}, {2,0}, {-1,2}, {2,-1}}, + new RotationKey(Orientation.UPSIDE_DOWN, Orientation.RIGHT), new int[][] {{0,0}, {1,0}, {-2,0}, {1,-2}, {-2,1}}, + new RotationKey(Orientation.UPSIDE_DOWN, Orientation.LEFT), new int[][] {{0,0}, {2,0}, {-1,0}, {2,1}, {-1,-2}}, + new RotationKey(Orientation.LEFT, Orientation.UPSIDE_DOWN), new int[][] {{0,0}, {-2,0}, {1,0}, {-2,-1}, {1,2}}, + new RotationKey(Orientation.LEFT, Orientation.NONE), new int[][] {{0,0}, {1,0}, {-2,0}, {1,-2}, {-2,1}}, + new RotationKey(Orientation.NONE, Orientation.LEFT), new int[][] {{0,0}, {-1,0}, {2,0}, {-1,2}, {2,-1}} + ); + + public static int[][] getKicksArray(Orientation from, Orientation to, Tetromino.Shape shape) { + RotationKey rotationKey = new RotationKey(from, to); + return switch(shape) { + case J, L, S, T, Z -> STANDARD_WALL_KICKS.get(rotationKey); + case I -> I_WALL_KICKS.get(rotationKey); + default -> new int[][]{{0, 0}}; + }; + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 7acf4fe..4e2de8b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -16,6 +16,7 @@ import java.util.UUID; public class Tetromino { private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK; private final static Tag uuidTag = Tag.String("uuid"); + private Orientation orientation = Orientation.NONE; private final Shape shape; private final StatelessGame instance; private final UUID uuid; @@ -48,7 +49,19 @@ public class Tetromino { public boolean rotate(boolean clockwise) { int[][] newShapeArray = this.getTurnedShapeArray(clockwise); - return this.checkCollisionAndMove(this.position, newShapeArray); + Orientation newOrientation = this.orientation.rotated(clockwise); + + // TODO: doesn't work for I-Tetromino + int[][] kicksArray = RotationChecker.getKicksArray(this.orientation, newOrientation, this.shape); + for(int[] k : kicksArray) { + Pos candidate = new Pos(this.position.x() + k[0], this.position.y() + k[1], this.position.z()); + if(this.checkCollisionAndMove(candidate, newShapeArray)) { + this.orientation = newOrientation; + return true; + } + } + + return false; } public boolean moveDown() {