diff --git a/src/main/java/net/earthcomputer/clientcommands/command/MinesweeperCommand.java b/src/main/java/net/earthcomputer/clientcommands/command/MinesweeperCommand.java index c9cd1659..dc1a2494 100644 --- a/src/main/java/net/earthcomputer/clientcommands/command/MinesweeperCommand.java +++ b/src/main/java/net/earthcomputer/clientcommands/command/MinesweeperCommand.java @@ -5,6 +5,7 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import it.unimi.dsi.fastutil.ints.IntArrayList; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; @@ -19,6 +20,7 @@ import org.joml.Vector2i; import java.util.Random; +import java.util.stream.Stream; import static com.mojang.brigadier.arguments.IntegerArgumentType.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; @@ -219,13 +221,18 @@ public boolean mouseReleased(double mouseX, double mouseY, int button) { int tileY = Mth.floorDiv((int) (mouseY - topLeftY - 12), 16); if (isWithinBounds(tileX, tileY) && gameActive()) { + byte tile = getTile(tileX, tileY); if (button == InputConstants.MOUSE_BUTTON_LEFT) { if (ticksPlaying == 0) { generateMines(tileX, tileY); ticksPlaying = 1; } - click(tileX, tileY); + if (isCovered(tile)) { + click(tileX, tileY); + } else { + click3x3(tileX, tileY); + } assert minecraft != null && minecraft.player != null; if (emptyTilesRemaining <= 0) { @@ -290,6 +297,14 @@ private boolean isWithinBounds(int x, int y) { return 0 <= x && x < boardWidth && 0 <= y && y < boardHeight; } + private Stream getNeighbours(int x, int y) { + return Stream.of( + new Vector2i(x - 1, y - 1), new Vector2i(x, y - 1), new Vector2i(x + 1, y - 1), + new Vector2i(x - 1, y), new Vector2i(x + 1, y), + new Vector2i(x - 1, y + 1), new Vector2i(x, y + 1), new Vector2i(x + 1, y + 1) + ).filter(pos -> isWithinBounds(pos.x, pos.y)); + } + private void click(int x, int y) { byte tile = getTile(x, y); if (!isCovered(tile) || isFlagged(tile)) { @@ -307,41 +322,31 @@ private void click(int x, int y) { uncover(x, y); emptyTilesRemaining--; // we need to leave room for the current tile in the queue - int[] queue = new int[emptyTilesRemaining + 1]; - int queueIdx = 0; - queue[0] = y * boardWidth + x; - while (queueIdx >= 0) { - int idx = queue[queueIdx--]; + IntArrayList queue = new IntArrayList(emptyTilesRemaining + 1); + queue.add(y * boardWidth + x); + while (!queue.isEmpty()) { + int idx = queue.popInt(); int xPart = idx % boardWidth; int yPart = idx / boardWidth; - for (Vector2i possibleNeighbour : new Vector2i[]{ - new Vector2i(xPart - 1, yPart - 1), - new Vector2i(xPart, yPart - 1), - new Vector2i(xPart + 1, yPart - 1), - - new Vector2i(xPart - 1, yPart), - new Vector2i(xPart + 1, yPart), - - new Vector2i(xPart - 1, yPart + 1), - new Vector2i(xPart, yPart + 1), - new Vector2i(xPart + 1, yPart + 1), - }) { - if (isWithinBounds(possibleNeighbour.x, possibleNeighbour.y)) { - byte value = getTile(possibleNeighbour.x, possibleNeighbour.y); - uncover(possibleNeighbour.x, possibleNeighbour.y); - if (isCovered(value)) { - emptyTilesRemaining--; - // if it's an empty tile, we put it in the queue to go activate all its neighbours - if (tileType(value) == EMPTY_TILE_TYPE) { - queue[++queueIdx] = possibleNeighbour.y * boardWidth + possibleNeighbour.x; - } + getNeighbours(xPart, yPart).forEach(neighbour -> { + byte value = getTile(neighbour.x, neighbour.y); + uncover(neighbour.x, neighbour.y); + if (isCovered(value)) { + emptyTilesRemaining--; + // if it's an empty tile, we put it in the queue to go activate all its neighbours + if (tileType(value) == EMPTY_TILE_TYPE) { + queue.add(neighbour.y * boardWidth + neighbour.x); } } - } + }); } } } + private void click3x3(int x, int y) { + getNeighbours(x, y).forEach(neighbour -> click(neighbour.x, neighbour.y)); + } + private void flag(int x, int y) { if (!isCovered(getTile(x, y))) { return;