Has 3 Difficulty Levels!
Plans to support non-colored computers in the future.
No support for monitors yet, requires advanced computer.
F1, F2, F3 for Easy Medium Hard difficulty.
Left click to sweep the tile, Right click to toggle the flag.
Shows how long you've been playing each round, so you know how fast you are!
Yes Gopher made a Minesweeper recently, No I didn't rip off his, just the idea :P/>
Code for easy viewing:
Spoiler
local minemap = {}
local viewport = {}
-- Unknown mark
local FLAG = -2
-- Still Unknown
local COVER = -1
-- Empty space
local EMPTY = 0
local mapWidth = 0
local mapHeight = 0
local alive = true
local win = false
local gameStarted = false
local startTime = nil
local sDifficulty = "easy"
local center = false
if not term.isColor() then
term.setTextColor = function(...) end
term.setBackgroundColor = term.setTextColor
end
local difficulty = {
stupid = { 30, 16, 0.1 },
easy = { 10,10, 0.2},
medium = { 16,16, 0.32},
hard = { 30,16, 0.4}
}
local function inBounds(x,y)
if x > 0 or y > 0 or x < mapWidth +1 or y < mapHeight +1 then
return true
end
end
local function getKey(x,y)
return (x.."x"..y)
end
local function isMine(x,y)
if not inBounds(x,y) then
return false
end
return minemap[getKey(x,y)] == true
end
local function isMineOrNumber(x,y)
if not inBounds(x,y) then
return false
end
return minemap[getKey(x,y)]
end
local function setMine(x,y)
if not inBounds(x,y) then
return false
end
minemap[getKey(x,y)] = true
end
local function clearMine(x,y)
if not inBounds(x,y) then
return false
end
minemap[getKey(x,y)] = nil
end
local function clearMap()
minemap = {}
end
local point = {}
local pointPool = {}
function point.equals(self, point)
if self.x ~= nil and self.y ~= nil and
point.x ~= nil and point.y ~= nil then
return self.x == point.x and self.y == point.y
end
return false
end
function table.containsPoint(self, point)
for _, tPoint in pairs(self) do
if tPoint.equals and self.equals and self:equals(tPoint) then
return true
end
end
return false
end
function point.new(x,y)
local p = {}
p.x = x
p.y = y
setmetatable(p, {
__index = point
})
return p
end
local function getNeighbours(x,y)
local neighbours = {}
setmetatable(neighbours, { __index = table })
for dx = -1, 1 do
for dy = -1, 1 do
if inBounds(x + dx, y + dy) and
not ( dx == 0 and dy == 0) then
neighbours:insert( point.new(x+dx, y+dy))
end
end
end
return neighbours
end
local function populateNumbers()
for y = 1, mapHeight do
for x = 1, mapWidth do
if not isMine(x,y) then
local neighbours = getNeighbours(x,y)
local pointValue = 0
for _, neighbour in pairs(neighbours) do
if isMine(neighbour.x,neighbour.y) then
pointValue = pointValue + 1
end
end
pointValue = math.floor(pointValue)
if pointValue ~= 0 then
minemap[getKey(x,y)] = pointValue
end
end
end
end
end
local function createMap(w,h,frequency)
clearMap()
mapWidth = w
mapHeight = h
if frequency == 0 then return end
local split = 1/frequency
for x = 1, mapWidth do
for y = 1, mapHeight do
local rnd = math.random()
rnd = rnd * split
if rnd < 0.5 then
setMine(x,y)
end
end
end
populateNumbers()
end
local function createMapAtLevel(level)
if difficulty[level] then
local levelControllers = difficulty[level]
createMap(unpack(levelControllers))
return true
end
return false
end
local function printMine(withOverlay)
local h = fs.open("mine", "w")
for y = 1, mapHeight do
for x = 1, mapWidth do
if withOverlay and
viewport[getKey(x,y)] == COVER then
h.write("#")
else
if isMine(x,y) then
h.write("*")
elseif minemap[getKey(x,y)] then
h.write(string.sub(tostring(minemap[getKey(x,y)]),1,1))
else
h.write("-")
end
end
end
h.write("\r\n")
end
h.close()
end
local function clearViewport()
for x = 1, mapWidth do
for y = 1, mapHeight do
viewport[getKey(x,y)] = COVER
end
end
end
local function flag(x,y)
if not inBounds(x,y) then return false end
if viewport[getKey(x,y)] == COVER then
viewport[getKey(x,y)] = FLAG
return true
end
return false
end
local function unflag(x,y)
if not inBounds(x,y) then return false end
if viewport[getKey(x,y)] == FLAG then
viewport[getKey(x,y)] = COVER
return true
end
return false
end
local function toggleFlag(x,y)
if not inBounds(x,y) then return false end
if viewport[getKey(x,y)] == FLAG then
return unflag(x,y)
else
return flag(x,y)
end
end
local function floodFill(x,y)
local fill = {}
table.insert(fill, {x,y})
while #fill > 0 do
local x,y = unpack(table.remove(fill, 1))
if viewport[getKey(x,y)] == COVER and not isMine(x,y) then
viewport[getKey(x,y)] = EMPTY
local neighbours = getNeighbours(x,y)
for _, neighbour in pairs(neighbours) do
if not isMineOrNumber(x,y) then
table.insert(fill, {neighbour.x, neighbour.y})
end
end
end
end
end
local function checkWin()
for y =1, mapHeight do
for x=1, mapWidth do
if not isMine(x,y) and viewport[getKey(x,y)] ~= EMPTY then
return false
end
end
end
for y =1, mapHeight do
for x=1, mapWidth do
if isMine(x,y) then
viewport[getKey(x,y)] = FLAG
end
end
end
return true
end
local function dig(x,y)
if not inBounds(x,y) then return false end
if isMine(x,y) then
-- BOOM!
alive = false
for y =1, mapHeight do
for x=1, mapWidth do
if isMine(x,y) and viewport[getKey(x,y)] ~= FLAG then
viewport[getKey(x,y)] = EMPTY
end
end
end
return true
else
if viewport[getKey(x,y)] == COVER and not isMineOrNumber(x,y) then
floodFill(x,y)
else
viewport[getKey(x,y)] = EMPTY
end
win = checkWin()
end
end
local function renderMap(offX,offY)
offX = offX or 0
offY = offY or 0
for y = 1, mapHeight do
for x =1, mapWidth do
term.setBackgroundColor(colors.green)
term.setTextColor(colors.lime)
term.setCursorPos(offX+x,offY+y)
if viewport[getKey(x,y)] == COVER then
term.setBackgroundColor(colors.green)
term.write("^")
elseif viewport[getKey(x,y)] == FLAG then
term.setBackgroundColor(colors.red)
term.setTextColor(colors.white)
term.write("!")
elseif isMine(x,y) then
term.setBackgroundColor(colors.yellow)
term.setTextColor(colors.red)
term.write("X")
term.setBackgroundColor(colors.green)
term.setTextColor(colors.lime)
elseif viewport[getKey(x,y)] == EMPTY and isMineOrNumber(x,y) then
term.setBackgroundColor(colors.gray)
local number = isMineOrNumber(x,y)
if number == 1 then
term.setTextColor(colors.lightBlue)
elseif number == 2 then
term.setTextColor(colors.lime)
elseif number == 3 then
term.setTextColor(colors.yellow)
elseif number == 4 then
term.setTextColor(colors.orange)
elseif number == 5 then
term.setTextColor(colors.red)
elseif number > 5 then
term.setTextColor(colors.orange)
term.setBackgroundColor(colors.red)
end
term.write(string.sub(tostring(isMineOrNumber(x,y)),1,1))
else
term.setBackgroundColor(colors.black)
term.write(" ")
term.setBackgroundColor(colors.green)
end
end
end
end
function game()
local tick = nil
while true do
local termWidth = term.getSize()
xOff = 0
if center then
xOff = math.ceil(termWidth / 2 - mapWidth / 2)
renderMap(xOff, 2)
else
renderMap(0,2)
end
if not alive then
term.setBackgroundColor(colors.black)
term.setTextColor(colors.red)
if center then
term.setCursorPos(math.ceil(termWidth / 2 - string.len("you dead") / 2), 2)
else
term.setCursorPos(1,2)
end
term.write("KA BOOM!")
return true
elseif win then
term.setBackgroundColor(colors.black)
term.setTextColor(colors.red)
if not alive then
term.setCursorPos(math.ceil(termWidth / 2 - string.len("you win") / 2), 2)
else
term.setCursorPos(1,2)
end
term.write("VICTORY")
return true
end
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
local tyme = "0"
if gameStarted then
tyme = tostring(math.floor(os.clock() - startTime))
end
term.setCursorPos(mapWidth + xOff - string.len(tyme) + 1, 1)
term.write( tyme)
local event = { os.pullEvent() }
if not gameStarted and event[1] == "mouse_click" then
gameStarted = true
startTime = os.clock()
end
if not tick then
tick = os.startTimer(0.5)
end
if event[1] == "mouse_click" then
x,y = event[3], event[4] -2
if center then
x,y = event[3] - xOff, event[4] - 2
end
if event[2] == 1 and inBounds(x,y) then
dig(x, y)
elseif event[2] == 2 then
toggleFlag(x, y)
end
elseif event[1] == "timer" and event[2] == tick then
tick = os.startTimer(0.5)
elseif event[1] == "key" then
if event[2] == 59 then
sDifficulty = "easy"
return false
elseif event[2] == 60 then
sDifficulty = "medium"
return false
elseif event[2] == 61 then
sDifficulty = "hard"
return false
end
end
end
end
function newGame()
term.clear()
term.setCursorPos(1,1)
createMapAtLevel(sDifficulty)
clearViewport()
gameStarted = false
--printMine(true)
win = false
alive = true
end
while true do
newGame()
if game() then
sleep(3)
end
end
Code for easy downloading: http://pastebin.com/PggXhm4i
Have fun, Please comment with suggestions or critiques.