CCCPaste
-- Tetris Game for SimpleOS
-- CC: Tweaked compatible

local w, h = term.getSize()

-- Game board dimensions
local boardWidth = 10
local boardHeight = 18
local boardX = math.floor((w - boardWidth * 2) / 2)
local boardY = 2

-- Tetromino shapes
local shapes = {
    { -- I
        {{1,1,1,1}},
        {{1},{1},{1},{1}}
    },
    { -- O
        {{1,1},{1,1}}
    },
    { -- T
        {{0,1,0},{1,1,1}},
        {{1,0},{1,1},{1,0}},
        {{1,1,1},{0,1,0}},
        {{0,1},{1,1},{0,1}}
    },
    { -- S
        {{0,1,1},{1,1,0}},
        {{1,0},{1,1},{0,1}}
    },
    { -- Z
        {{1,1,0},{0,1,1}},
        {{0,1},{1,1},{1,0}}
    },
    { -- J
        {{1,0,0},{1,1,1}},
        {{1,1},{1,0},{1,0}},
        {{1,1,1},{0,0,1}},
        {{0,1},{0,1},{1,1}}
    },
    { -- L
        {{0,0,1},{1,1,1}},
        {{1,0},{1,0},{1,1}},
        {{1,1,1},{1,0,0}},
        {{1,1},{0,1},{0,1}}
    }
}

local shapeColors = {
    colors.cyan,
    colors.yellow,
    colors.purple,
    colors.green,
    colors.red,
    colors.blue,
    colors.orange
}

-- Game state
local board = {}
local currentShape = nil
local currentRotation = 1
local currentX, currentY = 1, 1
local currentType = 1
local score = 0
local level = 1
local lines = 0
local gameOver = false
local speed = 0.5

-- Initialize board
local function initBoard()
    board = {}
    for y = 1, boardHeight do
        board[y] = {}
        for x = 1, boardWidth do
            board[y][x] = 0
        end
    end
end

-- Get current shape data
local function getShape()
    local rotations = shapes[currentType]
    return rotations[((currentRotation - 1) % #rotations) + 1]
end

-- Check collision
local function checkCollision(shape, px, py)
    for y, row in ipairs(shape) do
        for x, cell in ipairs(row) do
            if cell == 1 then
                local bx = px + x - 1
                local by = py + y - 1
                if bx < 1 or bx > boardWidth or by > boardHeight then
                    return true
                end
                if by >= 1 and board[by][bx] ~= 0 then
                    return true
                end
            end
        end
    end
    return false
end

-- Spawn new piece
local function spawnPiece()
    currentType = math.random(1, #shapes)
    currentRotation = 1
    currentX = math.floor(boardWidth / 2) - 1
    currentY = 1
    
    if checkCollision(getShape(), currentX, currentY) then
        gameOver = true
    end
end

-- Lock piece to board
local function lockPiece()
    local shape = getShape()
    for y, row in ipairs(shape) do
        for x, cell in ipairs(row) do
            if cell == 1 then
                local by = currentY + y - 1
                local bx = currentX + x - 1
                if by >= 1 and by <= boardHeight and bx >= 1 and bx <= boardWidth then
                    board[by][bx] = currentType
                end
            end
        end
    end
end

-- Clear completed lines
local function clearLines()
    local cleared = 0
    local y = boardHeight
    while y >= 1 do
        local full = true
        for x = 1, boardWidth do
            if board[y][x] == 0 then
                full = false
                break
            end
        end
        if full then
            table.remove(board, y)
            local newRow = {}
            for x = 1, boardWidth do
                newRow[x] = 0
            end
            table.insert(board, 1, newRow)
            cleared = cleared + 1
        else
            y = y - 1
        end
    end
    
    if cleared > 0 then
        local points = {40, 100, 300, 1200}
        score = score + (points[cleared] or 1200) * level
        lines = lines + cleared
        level = math.floor(lines / 10) + 1
        speed = math.max(0.05, 0.5 - (level - 1) * 0.05)
    end
end

-- Draw game
local function draw()
    term.setBackgroundColor(colors.black)
    term.clear()
    
    -- Draw border
    term.setBackgroundColor(colors.gray)
    for y = 0, boardHeight + 1 do
        term.setCursorPos(boardX - 1, boardY + y)
        term.write(" ")
        term.setCursorPos(boardX + boardWidth * 2, boardY + y)
        term.write(" ")
    end
    for x = -1, boardWidth * 2 do
        term.setCursorPos(boardX + x, boardY + boardHeight + 1)
        term.write(" ")
    end
    
    -- Draw board
    for y = 1, boardHeight do
        for x = 1, boardWidth do
            term.setCursorPos(boardX + (x - 1) * 2, boardY + y - 1)
            if board[y][x] ~= 0 then
                term.setBackgroundColor(shapeColors[board[y][x]])
                term.write("  ")
            else
                term.setBackgroundColor(colors.black)
                term.write("  ")
            end
        end
    end
    
    -- Draw current piece
    if not gameOver then
        local shape = getShape()
        term.setBackgroundColor(shapeColors[currentType])
        for y, row in ipairs(shape) do
            for x, cell in ipairs(row) do
                if cell == 1 then
                    local dy = currentY + y - 1
                    local dx = currentX + x - 1
                    if dy >= 1 then
                        term.setCursorPos(boardX + (dx - 1) * 2, boardY + dy - 1)
                        term.write("  ")
                    end
                end
            end
        end
    end
    
    -- Draw info
    term.setBackgroundColor(colors.black)
    term.setTextColor(colors.white)
    term.setCursorPos(2, 2)
    term.write("TETRIS")
    term.setCursorPos(2, 4)
    term.write("Score:")
    term.setCursorPos(2, 5)
    term.write(tostring(score))
    term.setCursorPos(2, 7)
    term.write("Level:")
    term.setCursorPos(2, 8)
    term.write(tostring(level))
    term.setCursorPos(2, 10)
    term.write("Lines:")
    term.setCursorPos(2, 11)
    term.write(tostring(lines))
    term.setCursorPos(2, h - 1)
    term.write("[Q] Quit")
end

-- Game over screen
local function showGameOver()
    term.setBackgroundColor(colors.black)
    term.setTextColor(colors.red)
    term.setCursorPos(boardX + 2, boardY + 7)
    term.write("GAME OVER")
    term.setTextColor(colors.white)
    term.setCursorPos(boardX, boardY + 9)
    term.write("ENTER=Restart")
end

-- Move piece
local function movePiece(dx, dy)
    local shape = getShape()
    if not checkCollision(shape, currentX + dx, currentY + dy) then
        currentX = currentX + dx
        currentY = currentY + dy
        return true
    end
    return false
end

-- Rotate piece
local function rotatePiece()
    local oldRotation = currentRotation
    currentRotation = currentRotation + 1
    local shape = getShape()
    if checkCollision(shape, currentX, currentY) then
        currentRotation = oldRotation
    end
end

-- Drop piece
local function dropPiece()
    while movePiece(0, 1) do end
    lockPiece()
    clearLines()
    spawnPiece()
end

-- Main game loop
local function run()
    initBoard()
    spawnPiece()
    score = 0
    level = 1
    lines = 0
    gameOver = false
    speed = 0.5
    
    while true do
        draw()
        
        if gameOver then
            showGameOver()
            while true do
                local event, key = os.pullEvent("key")
                if key == keys.enter then
                    initBoard()
                    spawnPiece()
                    score = 0
                    level = 1
                    lines = 0
                    gameOver = false
                    speed = 0.5
                    break
                elseif key == keys.q then
                    return
                end
            end
        end
        
        local timer = os.startTimer(speed)
        
        while true do
            local event, p1 = os.pullEvent()
            
            if event == "key" then
                if p1 == keys.left then
                    movePiece(-1, 0)
                    draw()
                elseif p1 == keys.right then
                    movePiece(1, 0)
                    draw()
                elseif p1 == keys.down then
                    movePiece(0, 1)
                    draw()
                elseif p1 == keys.up then
                    rotatePiece()
                    draw()
                elseif p1 == keys.space then
                    dropPiece()
                    break
                elseif p1 == keys.q then
                    return
                end
            elseif event == "timer" and p1 == timer then
                break
            end
        end
        
        if not gameOver then
            if not movePiece(0, 1) then
                lockPiece()
                clearLines()
                spawnPiece()
            end
        end
    end
end

run()