You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
3.7 KiB
190 lines
3.7 KiB
package main
|
|
|
|
import (
|
|
"image/color"
|
|
)
|
|
|
|
// Block represents a single block in the game
|
|
type Block struct {
|
|
X, Y int
|
|
Type BlockType
|
|
}
|
|
|
|
// BlockType represents different types of tetrominos
|
|
type BlockType int
|
|
|
|
const (
|
|
IBlock BlockType = iota
|
|
JBlock
|
|
LBlock
|
|
OBlock
|
|
SBlock
|
|
TBlock
|
|
ZBlock
|
|
)
|
|
|
|
// Tetromino represents a complete tetris piece
|
|
type Tetromino struct {
|
|
Blocks []Block
|
|
BlockType BlockType
|
|
X, Y int
|
|
}
|
|
|
|
// Colors for different block types
|
|
var BlockColors = map[BlockType]color.Color{
|
|
IBlock: color.RGBA{0, 255, 255, 255}, // Cyan
|
|
JBlock: color.RGBA{0, 0, 255, 255}, // Blue
|
|
LBlock: color.RGBA{255, 165, 0, 255}, // Orange
|
|
OBlock: color.RGBA{255, 255, 0, 255}, // Yellow
|
|
SBlock: color.RGBA{0, 255, 0, 255}, // Green
|
|
TBlock: color.RGBA{128, 0, 128, 255}, // Purple
|
|
ZBlock: color.RGBA{255, 0, 0, 255}, // Red
|
|
}
|
|
|
|
// TetrominoShapes defines the shape of each tetromino type
|
|
var TetrominoShapes = map[BlockType][][]bool{
|
|
IBlock: {
|
|
{false, false, false, false},
|
|
{false, false, false, false},
|
|
{true, true, true, true},
|
|
{false, false, false, false},
|
|
},
|
|
JBlock: {
|
|
{true, false, false},
|
|
{true, true, true},
|
|
{false, false, false},
|
|
},
|
|
LBlock: {
|
|
{false, false, true},
|
|
{true, true, true},
|
|
{false, false, false},
|
|
},
|
|
OBlock: {
|
|
{true, true},
|
|
{true, true},
|
|
},
|
|
SBlock: {
|
|
{false, true, true},
|
|
{true, true, false},
|
|
{false, false, false},
|
|
},
|
|
TBlock: {
|
|
{false, true, false},
|
|
{true, true, true},
|
|
{false, false, false},
|
|
},
|
|
ZBlock: {
|
|
{true, true, false},
|
|
{false, true, true},
|
|
{false, false, false},
|
|
},
|
|
}
|
|
|
|
// Rotation offsets for I piece wall kicks
|
|
var IKicks = [][2]int{
|
|
{0, 0},
|
|
{-2, 0},
|
|
{1, 0},
|
|
{-2, -1},
|
|
{1, 2},
|
|
}
|
|
|
|
// Rotation offsets for other pieces wall kicks
|
|
var NormalKicks = [][2]int{
|
|
{0, 0},
|
|
{-1, 0},
|
|
{1, 0},
|
|
{0, -1},
|
|
}
|
|
|
|
// NewTetromino creates a new tetromino of the specified type
|
|
func NewTetromino(blockType BlockType, x, y int) *Tetromino {
|
|
shape := TetrominoShapes[blockType]
|
|
blocks := make([]Block, 0)
|
|
|
|
for i := 0; i < len(shape); i++ {
|
|
for j := 0; j < len(shape[i]); j++ {
|
|
if shape[i][j] {
|
|
blocks = append(blocks, Block{
|
|
X: j,
|
|
Y: i,
|
|
Type: blockType,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adjust initial position for I piece
|
|
if blockType == IBlock {
|
|
y-- // Start one row higher
|
|
}
|
|
|
|
return &Tetromino{
|
|
Blocks: blocks,
|
|
BlockType: blockType,
|
|
X: x,
|
|
Y: y,
|
|
}
|
|
}
|
|
|
|
// Move moves the tetromino by the specified delta
|
|
func (t *Tetromino) Move(dx, dy int) {
|
|
t.X += dx
|
|
t.Y += dy
|
|
}
|
|
|
|
// Rotate rotates the tetromino clockwise
|
|
func (t *Tetromino) Rotate() {
|
|
if t.BlockType == OBlock {
|
|
return // O block doesn't need rotation
|
|
}
|
|
|
|
// Get the size of the shape matrix
|
|
size := 3
|
|
if t.BlockType == IBlock {
|
|
size = 4
|
|
}
|
|
|
|
// Create a temporary matrix for rotation
|
|
matrix := make([][]bool, size)
|
|
for i := range matrix {
|
|
matrix[i] = make([]bool, size)
|
|
}
|
|
|
|
// Fill the matrix with current block positions
|
|
for _, block := range t.Blocks {
|
|
if block.Y >= 0 && block.Y < size && block.X >= 0 && block.X < size {
|
|
matrix[block.Y][block.X] = true
|
|
}
|
|
}
|
|
|
|
// Create a new rotated shape
|
|
newBlocks := make([]Block, 0)
|
|
|
|
// Perform rotation
|
|
for y := 0; y < size; y++ {
|
|
for x := 0; x < size; x++ {
|
|
if matrix[y][x] {
|
|
// Rotate coordinates 90 degrees clockwise
|
|
newX := size - 1 - y
|
|
newY := x
|
|
newBlocks = append(newBlocks, Block{
|
|
X: newX,
|
|
Y: newY,
|
|
Type: t.BlockType,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Blocks = newBlocks
|
|
}
|
|
|
|
// GetAbsolutePositions returns the absolute positions of all blocks in the tetromino
|
|
func (t *Tetromino) GetAbsolutePositions() [][2]int {
|
|
positions := make([][2]int, len(t.Blocks))
|
|
for i, block := range t.Blocks {
|
|
positions[i] = [2]int{t.X + block.X, t.Y + block.Y}
|
|
}
|
|
return positions
|
|
}
|
|
|