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
}