package tetromino import "tetris/internal/types" // TetrominoShapes defines the shape of each tetromino type var TetrominoShapes = map[types.BlockType][][]bool{ types.IBlock: { {false, false, false, false}, {false, false, false, false}, {true, true, true, true}, {false, false, false, false}, }, types.JBlock: { {true, false, false}, {true, true, true}, {false, false, false}, }, types.LBlock: { {false, false, true}, {true, true, true}, {false, false, false}, }, types.OBlock: { {true, true}, {true, true}, }, types.SBlock: { {false, true, true}, {true, true, false}, {false, false, false}, }, types.TBlock: { {false, true, false}, {true, true, true}, {false, false, false}, }, types.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}, } // Tetromino represents a complete tetris piece type Tetromino struct { Blocks []types.Block BlockType types.BlockType X, Y int } // New creates a new tetromino of the specified type func New(blockType types.BlockType, x, y int) *Tetromino { shape := TetrominoShapes[blockType] blocks := make([]types.Block, 0) for i := range shape { for j := range shape[i] { if shape[i][j] { blocks = append(blocks, types.Block{ X: j, Y: i, Type: blockType, }) } } } // Adjust initial position for I piece if blockType == types.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 == types.OBlock { return // O block doesn't need rotation } // Get the size of the shape matrix size := 3 if t.BlockType == types.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([]types.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, types.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 }