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 }