123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- local level_config = {
- ['Small'] = { w = 9, h = 9, bomb = 10, icon_size = 0.9 },
- ['Small hard'] = { w = 9, h = 9, bomb = 35, icon_size = 0.9},
- ['Midsize'] = { w = 16, h = 16, bomb = 40, icon_size = 0.7 },
- ['Midsize hard'] = { w = 16, h = 16, bomb = 99, icon_size = 0.7},
- ['Big'] = { w = 24, h = 20, bomb = 99, icon_size = 0.58 },
- ['Big hard'] = { w = 24, h = 20, bomb = 170, icon_size = 0.58},
- }
- local sweeper_class = {}
- sweeper_class.__index = sweeper_class
- function sweeper_class:init(level)
- self.data.level = level
- if not level_config[level] then print('ERROR: WRONG LEVEL', level) end
- local config = level_config[level]
- -- build board
- self.data.board = {}
- self.data.open_all = config.w * config.h - config.bomb
- self.data.open_count = 0
- self.data.bomb_all = config.bomb
- self.data.bomb_count = 0
- local board = self.data.board
- for w = 1, config.w do
- board[w] = {}
- for h = 1, config.h do
- board[w][h] = { count = 0, is_bomb = false, is_revealed = false }
- end
- end
- -- fill board with bombs
- local placed = 0
- while placed < config.bomb do
- local rnd_w = math.random(config.w)
- local rnd_h = math.random(config.h)
- local rndfield = board[rnd_w][rnd_h]
- if not rndfield.is_bomb then
- rndfield.is_bomb = true
- placed = placed + 1
- for w = rnd_w - 1, rnd_w + 1 do
- for h = rnd_h - 1, rnd_h + 1 do
- if board[w] and board[w][h] then
- board[w][h].count = board[w][h].count + 1
- end
- end
- end
- end
- end
- end
- function sweeper_class:get(sel_w, sel_h)
- local board = self.data.board
- if board[sel_w] then
- return board[sel_w][sel_h]
- end
- end
- function sweeper_class:reveal(sel_w, sel_h)
- local board = self.data.board
- local sel = self:get(sel_w, sel_h)
- -- unmark bomb
- if sel.bomb_marked then
- self:toggle_bomb_mark(sel_w, sel_h)
- end
- sel.is_revealed = true
- if sel.is_bomb then
- -- Bomb found
- self.data.bomb_count = self.data.bomb_count + 1
- else
- -- No bomb, count empty fields
- self.data.open_count = self.data.open_count + 1
- if sel.count == 0 then
- for w = sel_w - 1, sel_w + 1 do
- for h = sel_h - 1, sel_h + 1 do
- local chk_sel = self:get(w,h)
- if chk_sel and
- not chk_sel.is_revealed and
- not chk_sel.bomb_marked then
- self:reveal(w,h)
- end
- end
- end
- end
- end
- end
- function sweeper_class:toggle_bomb_mark(sel_w, sel_h)
- local sel = self:get(sel_w, sel_h)
- if sel.bomb_marked then
- self.data.bomb_count = self.data.bomb_count - 1
- sel.bomb_marked = nil
- else
- self.data.bomb_count = self.data.bomb_count + 1
- sel.bomb_marked = true
- end
- end
- local function get_sweeper(data)
- local self = setmetatable({}, sweeper_class)
- self.data = data
- return self
- end
- laptop.register_app("tntsweeper", {
- app_name = "TNT Sweeper",
- app_icon = "laptop_tnt.png",
- app_info = "Avoid hitting TNT",
- formspec_func = function(app, mtos)
- local data = mtos.bdev:get_app_storage('ram', 'tntsweeper')
- local sweeper = get_sweeper(data)
- if not sweeper.data.level then
- sweeper:init('Midsize')
- end
- local config = level_config[sweeper.data.level]
- local formspec = ""
- for w = 1, config.w do
- for h = 1, config.h do
- local pos = (w*config.icon_size*0.8)..','..(h*config.icon_size*0.85)
- local field = sweeper.data.board[w][h]
- if not field.is_revealed then
- if field.bomb_marked then
- formspec = formspec .. "image_button["..pos..";"..config.icon_size..","..config.icon_size..";"..mtos.theme.minor_button.."^"..mtos.theme:get_texture("laptop_tnt.png")..";field:"..w..":"..h..";]"
- else
- formspec = formspec .. "image_button["..pos..";"..config.icon_size..","..config.icon_size..";"..mtos.theme.minor_button..";field:"..w..":"..h..";]"
- end
- elseif field.is_bomb then
- formspec = formspec .. "image["..pos..";"..config.icon_size..","..config.icon_size..";"..mtos.theme:get_texture("laptop_boom.png").."]"
- elseif field.count > 0 then
- local lbpos = ((w+0.4)*config.icon_size*0.8)..','..((h+0.1)*config.icon_size*0.85)
- formspec = formspec .. mtos.theme:get_label(lbpos, field.count)
- end
- end
- end
- formspec = formspec .. "background[12,0.5;3,1;"..mtos.theme.contrast_background..']'..
- mtos.theme:get_label("12,0.5", "Open fields: "..sweeper.data.open_count.."/"..sweeper.data.open_all, "contrast")..
- mtos.theme:get_label("12,1", "Bomb: "..sweeper.data.bomb_count.."/"..sweeper.data.bomb_all, "contrast")..
- mtos.theme:get_button('12.5,2;1.5,0.8', 'major', 'reset', 'Small')..
- mtos.theme:get_button('12.5,3;1.5,0.8', 'major', 'reset', 'Small hard')..
- mtos.theme:get_button('12.5,4;1.5,0.8', 'major', 'reset', 'Midsize')..
- mtos.theme:get_button('12.5,5;1.5,0.8', 'major', 'reset', 'Midsize hard')..
- mtos.theme:get_button('12.5,6;1.5,0.8', 'major', 'reset', 'Big')..
- mtos.theme:get_button('12.5,7;1.5,0.8', 'major', 'reset', 'Big hard')
- if data.mark_mode then
- formspec = formspec .. mtos.theme:get_button('12.5,9;1.5,0.8', 'minor', 'mark_mode', 'mark', 'change to reveal mode')
- else
- formspec = formspec .. mtos.theme:get_button('12.5,9;1.5,0.8', 'minor', 'mark_mode', 'reveal', 'change to mark mode')
- end
- return formspec
- end,
- receive_fields_func = function(app, mtos, sender, fields)
- local data = mtos.bdev:get_app_storage('ram', 'tntsweeper')
- local sweeper = get_sweeper(data)
- local config = level_config[sweeper.data.level]
- for field, _ in pairs(fields) do
- if field:sub(1,6) == 'field:' then
- local sel_w, sel_h
- for str in field:gmatch("([^:]+)") do
- if str ~= 'field' then
- if not sel_w then
- sel_w = tonumber(str)
- else
- sel_h = tonumber(str)
- end
- end
- end
- --if sender:get_player_control().sneak then -- TODO: test if https://github.com/minetest/minetest/issues/6353
- if data.mark_mode then
- sweeper:toggle_bomb_mark(sel_w, sel_h)
- else
- sweeper:reveal(sel_w, sel_h)
- end
- end
- end
- if fields.reset then
- sweeper:init(minetest.strip_colors(fields.reset))
- elseif fields.mark_mode then
- if data.mark_mode then
- data.mark_mode = nil
- else
- data.mark_mode = true
- end
- end
- end
- })
|