Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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
Advertisement
Add Comment
Please, Sign In to add comment