CCCPaste

Minesweeper

-- Minesweeper Game for SimpleOS
-- CC: Tweaked compatible

local w, h = term.getSize()

-- Game settings
local gridWidth = 9
local gridHeight = 9
local mineCount = 10
local startX = math.floor((w - gridWidth * 2) / 2)
local startY = 3

-- Game state
local grid = {}
local revealed = {}
local flagged = {}
local gameOver = false
local gameWon = false
local cursorX, cursorY = 1, 1
local firstClick = true

-- Initialize grid
local function initGrid()
    grid = {}
    revealed = {}
    flagged = {}
    for y = 1, gridHeight do
        grid[y] = {}
        revealed[y] = {}
        flagged[y] = {}
        for x = 1, gridWidth do
            grid[y][x] = 0
            revealed[y][x] = false
            flagged[y][x] = false
        end
    end
end

-- Place mines (avoiding first click)
local function placeMines(avoidX, avoidY)
    local placed = 0
    while placed < mineCount do
        local x = math.random(1, gridWidth)
        local y = math.random(1, gridHeight)
        if grid[y][x] ~= -1 and not (x == avoidX and y == avoidY) then
            grid[y][x] = -1
            placed = placed + 1
        end
    end
    
    -- Calculate numbers
    for y = 1, gridHeight do
        for x = 1, gridWidth do
            if grid[y][x] ~= -1 then
                local count = 0
                for dy = -1, 1 do
                    for dx = -1, 1 do
                        local nx, ny = x + dx, y + dy
                        if nx >= 1 and nx <= gridWidth and ny >= 1 and ny <= gridHeight then
                            if grid[ny][nx] == -1 then
                                count = count + 1
                            end
                        end
                    end
                end
                grid[y][x] = count
            end
        end
    end
end

-- Count flags
local function countFlags()
    local count = 0
    for y = 1, gridHeight do
        for x = 1, gridWidth do
            if flagged[y][x] then count = count + 1 end
        end
    end
    return count
end

-- Check win condition
local function checkWin()
    for y = 1, gridHeight do
        for x = 1, gridWidth do
            if grid[y][x] ~= -1 and not revealed[y][x] then
                return false
            end
        end
    end
    return true
end

-- Reveal cell
local function reveal(x, y)
    if x < 1 or x > gridWidth or y < 1 or y > gridHeight then return end
    if revealed[y][x] or flagged[y][x] then return end
    
    revealed[y][x] = true
    
    if grid[y][x] == -1 then
        gameOver = true
        -- Reveal all mines
        for my = 1, gridHeight do
            for mx = 1, gridWidth do
                if grid[my][mx] == -1 then
                    revealed[my][mx] = true
                end
            end
        end
        return
    end
    
    if grid[y][x] == 0 then
        -- Flood fill
        for dy = -1, 1 do
            for dx = -1, 1 do
                reveal(x + dx, y + dy)
            end
        end
    end
    
    if checkWin() then
        gameWon = true
    end
end

-- Draw game
local function draw()
    term.setBackgroundColor(colors.black)
    term.clear()
    
    -- Title
    term.setTextColor(colors.yellow)
    term.setCursorPos(math.floor(w/2) - 5, 1)
    term.write("MINESWEEPER")
    
    -- Info
    term.setTextColor(colors.white)
    term.setCursorPos(2, 2)
    term.write("Mines: " .. mineCount .. " Flags: " .. countFlags())
    term.setCursorPos(w - 10, 2)
    term.write("[Q] Quit")
    
    -- Draw grid
    local numberColors = {
        colors.blue, colors.green, colors.red, colors.purple,
        colors.brown, colors.cyan, colors.gray, colors.black
    }
    
    for y = 1, gridHeight do
        for x = 1, gridWidth do
            local screenX = startX + (x - 1) * 2
            local screenY = startY + y - 1
            term.setCursorPos(screenX, screenY)
            
            local isSelected = (x == cursorX and y == cursorY)
            
            if revealed[y][x] then
                if grid[y][x] == -1 then
                    term.setBackgroundColor(colors.red)
                    term.setTextColor(colors.black)
                    term.write("* ")
                elseif grid[y][x] == 0 then
                    term.setBackgroundColor(colors.lightGray)
                    term.write("  ")
                else
                    term.setBackgroundColor(colors.lightGray)
                    term.setTextColor(numberColors[grid[y][x]] or colors.black)
                    term.write(grid[y][x] .. " ")
                end
            elseif flagged[y][x] then
                term.setBackgroundColor(isSelected and colors.yellow or colors.gray)
                term.setTextColor(colors.red)
                term.write("F ")
            else
                term.setBackgroundColor(isSelected and colors.yellow or colors.gray)
                term.setTextColor(colors.white)
                term.write("# ")
            end
        end
    end
    
    -- Controls
    term.setBackgroundColor(colors.black)
    term.setTextColor(colors.gray)
    term.setCursorPos(2, startY + gridHeight + 1)
    term.write("Arrow keys: Move  SPACE: Reveal  F: Flag")
end

-- Game over screen
local function showGameOver()
    term.setTextColor(colors.red)
    term.setCursorPos(math.floor(w/2) - 4, startY + gridHeight + 3)
    term.write("GAME OVER!")
    term.setTextColor(colors.white)
    term.setCursorPos(math.floor(w/2) - 8, startY + gridHeight + 4)
    term.write("ENTER=Restart Q=Quit")
end

-- Win screen
local function showWin()
    term.setTextColor(colors.lime)
    term.setCursorPos(math.floor(w/2) - 4, startY + gridHeight + 3)
    term.write("YOU WIN!")
    term.setTextColor(colors.white)
    term.setCursorPos(math.floor(w/2) - 8, startY + gridHeight + 4)
    term.write("ENTER=Restart Q=Quit")
end

-- Main game loop
local function run()
    initGrid()
    gameOver = false
    gameWon = false
    firstClick = true
    cursorX, cursorY = math.floor(gridWidth/2), math.floor(gridHeight/2)
    
    while true do
        draw()
        
        if gameOver then
            showGameOver()
        elseif gameWon then
            showWin()
        end
        
        local event, key = os.pullEvent("key")
        
        if gameOver or gameWon then
            if key == keys.enter then
                initGrid()
                gameOver = false
                gameWon = false
                firstClick = true
                cursorX, cursorY = math.floor(gridWidth/2), math.floor(gridHeight/2)
            elseif key == keys.q then
                return
            end
        else
            if key == keys.up then
                cursorY = math.max(1, cursorY - 1)
            elseif key == keys.down then
                cursorY = math.min(gridHeight, cursorY + 1)
            elseif key == keys.left then
                cursorX = math.max(1, cursorX - 1)
            elseif key == keys.right then
                cursorX = math.min(gridWidth, cursorX + 1)
            elseif key == keys.space then
                if not flagged[cursorY][cursorX] then
                    if firstClick then
                        placeMines(cursorX, cursorY)
                        firstClick = false
                    end
                    reveal(cursorX, cursorY)
                end
            elseif key == keys.f then
                if not revealed[cursorY][cursorX] then
                    flagged[cursorY][cursorX] = not flagged[cursorY][cursorX]
                end
            elseif key == keys.q then
                return
            end
        end
    end
end

run()