package io.github.lonamiwebs.klooni.game; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import io.github.lonamiwebs.klooni.Klooni; // Represents a piece with an arbitrary shape, which // can be either rectangles (squares too) or L shaped // with any rotation. public class Piece { //region Members final Vector2 pos; final int colorIndex; private final int rotation; final int cellCols, cellRows; private boolean shape[][]; // Default arbitrary value float cellSize = 10f; //endregion //region Constructors // Rectangle-shaped constructor // // If swapSize is true, the rows and columns will be swapped. // colorIndex represents a random index that will be used // to determine the color of this piece when drawn on the screen. private Piece(int cols, int rows, int rotateSizeBy, int colorIndex) { this.colorIndex = colorIndex; pos = new Vector2(); rotation = rotateSizeBy % 2; cellCols = rotation == 1 ? rows : cols; cellRows = rotation == 1 ? cols : rows; shape = new boolean[cellRows][cellCols]; for (int i = 0; i < cellRows; ++i) { for (int j = 0; j < cellCols; ++j) { shape[i][j] = true; } } } // L-shaped constructor private Piece(int lSize, int rotateCount, int colorIndex) { this.colorIndex = colorIndex; pos = new Vector2(); cellCols = cellRows = lSize; shape = new boolean[lSize][lSize]; rotation = rotateCount % 4; switch (rotation) { case 0: // ┌ for (int j = 0; j < lSize; ++j) shape[0][j] = true; for (int i = 0; i < lSize; ++i) shape[i][0] = true; break; case 1: // ┐ for (int j = 0; j < lSize; ++j) shape[0][j] = true; for (int i = 0; i < lSize; ++i) shape[i][lSize-1] = true; break; case 2: // ┘ for (int j = 0; j < lSize; ++j) shape[lSize-1][j] = true; for (int i = 0; i < lSize; ++i) shape[i][lSize-1] = true; break; case 3: // └ for (int j = 0; j < lSize; ++j) shape[lSize-1][j] = true; for (int i = 0; i < lSize; ++i) shape[i][0] = true; break; } } //endregion //region Static methods // Generates a random piece with always the same color for the generated shape static Piece random() { // 9 pieces [0…8]; 4 possible rotations [0…3] return fromIndex(MathUtils.random(8), MathUtils.random(4)); } private static Piece fromIndex(int colorIndex, int rotateCount) { switch (colorIndex) { // Squares case 0: return new Piece(1, 1, 0, colorIndex); case 1: return new Piece(2, 2, 0, colorIndex); case 2: return new Piece(3, 3, 0, colorIndex); // Lines case 3: return new Piece(1, 2, rotateCount, colorIndex); case 4: return new Piece(1, 3, rotateCount, colorIndex); case 5: return new Piece(1, 4, rotateCount, colorIndex); case 6: return new Piece(1, 5, rotateCount, colorIndex); // L's case 7: return new Piece(2, rotateCount, colorIndex); case 8: return new Piece(3, rotateCount, colorIndex); } throw new RuntimeException("Random function is broken."); } //endregion //region Package local methods void draw(SpriteBatch batch) { final Color c = Klooni.theme.getCellColor(colorIndex); for (int i = 0; i < cellRows; ++i) for (int j = 0; j < cellCols; ++j) if (shape[i][j]) Cell.draw(c, batch, pos.x + j * cellSize, pos.y + i * cellSize, cellSize); } // Calculates the rectangle of the piece with screen coordinates Rectangle getRectangle() { return new Rectangle(pos.x, pos.y, cellCols * cellSize, cellRows * cellSize); } // Determines whether the shape is filled on the given row and column boolean filled(int i, int j) { return shape[i][j]; } // Calculates the area occupied by the shape int calculateArea() { int area = 0; for (int i = 0; i < cellRows; ++i) { for (int j = 0; j < cellCols; ++j) { if (shape[i][j]) { area++; } } } return area; } // Calculates the gravity center of the piece shape Vector2 calculateGravityCenter() { int filledCount = 0; Vector2 result = new Vector2(); for (int i = 0; i < cellRows; ++i) { for (int j = 0; j < cellCols; ++j) { if (shape[i][j]) { filledCount++; result.add( pos.x + j * cellSize - cellSize * 0.5f, pos.y + i * cellSize - cellSize * 0.5f); } } } return result.scl(1f / filledCount); } //endregion //region Serialization void write(DataOutputStream out) throws IOException { // colorIndex, rotation out.writeInt(colorIndex); out.writeInt(rotation); } static Piece read(DataInputStream in) throws IOException { return fromIndex(in.readInt(), in.readInt()); } //endregion }