-- 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()