From 0b3c757ce09d9b73a247bac6f735a301bf01ffb7 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 3 Feb 2026 15:51:41 +0100 Subject: [PATCH] fixed srs rotations --- .../types/tetris/game/RotationChecker.java | 64 +++++++++++-------- .../types/tetris/game/Tetromino.java | 47 +++++++++----- 2 files changed, 70 insertions(+), 41 deletions(-) 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 index 893b1f4..f0f91ef 100644 --- 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 @@ -1,38 +1,52 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; import java.util.Map; +import java.util.stream.IntStream; -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}} +public final class RotationChecker {private static final Map STANDARD_WALL_KICKS = Map.of( + Orientation.NONE, new int[][] {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, + Orientation.RIGHT, new int[][] {{0,0}, {1,0}, {1,-1}, {0,2}, {1,2}}, + Orientation.UPSIDE_DOWN, new int[][] {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, + 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}} + private static final Map I_WALL_KICKS = Map.of( + Orientation.NONE, new int[][] {{0,0}, {-1,0}, {2,0}, {-1,0}, {2,0}}, + Orientation.RIGHT, new int[][] {{-1,0}, {0,0}, {0,0}, {0,1}, {0,-2}}, + Orientation.UPSIDE_DOWN, new int[][] {{-1,1}, {1,1}, {-2,1}, {1,0}, {-2,0}}, + Orientation.LEFT, new int[][] {{0,1}, {0,1}, {0,1}, {0,-1}, {0,2}} + ); + + private static final Map O_WALL_KICKS = Map.of( + Orientation.NONE, new int[][] {{0,0}}, + Orientation.RIGHT, new int[][] {{0,-1}}, + Orientation.UPSIDE_DOWN, new int[][] {{-1,-1}}, + Orientation.LEFT, new int[][] {{-1,0}} ); public static int[][] getKicksArray(Orientation from, Orientation to, Tetromino.Shape shape) { - RotationKey rotationKey = new RotationKey(from, to); + int[][] firstOffsets = getOffsetData(from, shape); + int[][] secondOffsets = getOffsetData(to, shape); + int[][] result = new int[firstOffsets.length][2]; + + for(int i = 0; i < firstOffsets.length; i++) { + result[i] = subtractInt(firstOffsets[i], secondOffsets[i]); + } + + return result; + } + + private static int[] subtractInt(int[] first, int[] second) { + return IntStream.range(0, first.length) + .map(i -> first[i] - second[i]) + .toArray(); + } + + private static int[][] getOffsetData(Orientation orientation, Tetromino.Shape shape) { 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}}; + case J, L, S, T, Z -> STANDARD_WALL_KICKS.get(orientation); + case I -> I_WALL_KICKS.get(orientation); + case O -> O_WALL_KICKS.get(orientation); }; } } 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 4e2de8b..0a48247 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 @@ -29,10 +29,10 @@ public class Tetromino { this.uuid = UUID.randomUUID(); switch(this.shape) { - case I -> this.shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}; + case I -> this.shapeArray = new int[][]{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 1, 1, 1, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}; case J -> this.shapeArray = new int[][]{{1, 0, 0}, {1, 1, 1}, {0, 0, 0}}; case L -> this.shapeArray = new int[][]{{0, 0, 1}, {1, 1, 1}, {0, 0, 0}}; - case O -> this.shapeArray = new int[][]{{1, 1}, {1, 1}}; + case O -> this.shapeArray = new int[][]{{0, 1, 1}, {0, 1, 1}, {0, 0, 0}}; case S -> this.shapeArray = new int[][]{{0, 1, 1}, {1, 1, 0}, {0, 0, 0}}; case T -> this.shapeArray = new int[][]{{0, 1, 0}, {1, 1, 1}, {0, 0, 0}}; case Z -> this.shapeArray = new int[][]{{1, 1, 0}, {0, 1, 1}, {0, 0, 0}}; @@ -53,9 +53,12 @@ public class Tetromino { // TODO: doesn't work for I-Tetromino int[][] kicksArray = RotationChecker.getKicksArray(this.orientation, newOrientation, this.shape); + System.out.println(this.shape.toString() + ": " + Arrays.deepToString(kicksArray)); 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)) { + boolean moved = this.checkCollisionAndMove(candidate, newShapeArray); + System.out.println("Candidate: " + Arrays.toString(k) + " " + moved); + if(moved) { this.orientation = newOrientation; return true; } @@ -86,7 +89,7 @@ public class Tetromino { public void draw(boolean withGhost) { if(withGhost) { Pos ghostPos = this.position; - while(!this.checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) { + while(!this.hasCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) { ghostPos = ghostPos.sub(0, 1, 0); } Pos positionChange = this.position.sub(ghostPos); @@ -212,9 +215,8 @@ public class Tetromino { for(int y = 0; y < arrayLength; y++) { if(shapeArray[arrayLength - 1 - y][x] == 1) { switch(this.shape) { - case I -> returnList.add(position.add(x - 1, y - 2, 0)); - case O -> returnList.add(position.add(x, y, 0)); - default -> returnList.add(position.add(x - 1, y - 1, 0)); + case I -> returnList.add(new Pos(position).add(x - 2, y - 2, 0)); + default -> returnList.add(new Pos(position).add(x - 1, y - 1, 0)); } } } @@ -223,7 +225,22 @@ public class Tetromino { return returnList; } - private boolean checkCollision(Pos newPosition, int[][] newShapeArray) { +// private List getBlockPositions(Pos position, int[][] shapeArray) { +// List returnList = new ArrayList<>(); +// if(position == null) return returnList; +// +// for(int x = 0; x < shapeArray.length; x++) { +// for(int y = 0; y < shapeArray.length; y++) { +// if(shapeArray[x][y] == 1) { +// returnList.add(new Pos(position).sub(1, 1, 0).add(x, y, 0)); +// } +// } +// } +// +// return returnList; +// } + + private boolean hasCollision(Pos newPosition, int[][] newShapeArray) { List newBlockPositions = this.getBlockPositions(newPosition, newShapeArray); for(Pos pos : newBlockPositions) { @@ -236,14 +253,12 @@ public class Tetromino { } private boolean checkCollisionAndMove(Pos newPosition, int[][] newShapeArray) { - if(!this.checkCollision(newPosition, newShapeArray)) { - this.remove(); - this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new); - this.setPosition(newPosition); - this.draw(); - return true; - } - return false; + if(this.hasCollision(newPosition, newShapeArray)) return false; + this.remove(); + this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new); + this.setPosition(newPosition); + this.draw(); + return true; } public enum Shape {