256 lines
7.8 KiB
Lua
256 lines
7.8 KiB
Lua
-- nonogram game, created in 1hr 40 min by rnd
|
|
|
|
-- INIT
|
|
if not grid then
|
|
n=9
|
|
solved = false -- do we render solution or blank?
|
|
-- _G.math.randomseed(3)
|
|
|
|
self.spam(1)
|
|
|
|
|
|
init_score = function(levels, tops, default_value) -- [level] = {{name,score}, ...}
|
|
local data = {} for i = 1, levels do data[i] = {} for j = 1,tops do data[i][j] = {"-",default_value} end end return data
|
|
end
|
|
|
|
add_score = function(data,name,score,level)
|
|
local datal = data[level]; local tops = #datal; local j;for i = 1,tops do
|
|
if score>datal[i][2] then j = i break end end
|
|
if not j then return false end; for i=tops,j+1,-1 do datal[i][1] = datal[i-1][1];datal[i][2] = datal[i-1][2] end
|
|
datal[j] = {name,score} return true
|
|
end
|
|
|
|
_,scores_string = book.read(1); scores = minetest.deserialize(scores_string)
|
|
if not scores then scores = init_score(n-1,n-1,-999) end -- 5 levels, 5 top records
|
|
|
|
t0 = _G.minetest.get_gametime()
|
|
local intro ="numbers at beginning of each row (coloumn) tell how many\nred blocks are together in each row ( coloumn )." ..
|
|
"\npunch gray blocks to toggle them and reveal hidden red blocks.\npunch green to check solution. If you give up punch blue.";
|
|
self.label(intro)
|
|
|
|
grid = {}
|
|
spawnpos = self.spawnpos();
|
|
offsetx = 10 - math.ceil(n/2); offsetz = math.floor(n/2);
|
|
spawnpos.x = spawnpos.x - offsetx; spawnpos.z = spawnpos.z - offsetz;
|
|
spawnpos.y = spawnpos.y+3
|
|
|
|
for i=1,n do
|
|
grid[i]={};
|
|
for j=1,n do
|
|
grid[i][j]=math.random(2)-1
|
|
end
|
|
end
|
|
|
|
getcounts = function(grid)
|
|
local rowdata = {};
|
|
for i=1,n do
|
|
rowdata[i]={}; local data = rowdata[i];
|
|
local s=0;local c=0;
|
|
for j = 1, n do
|
|
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
|
if s == 1 then
|
|
if grid[i][j]==1 then
|
|
c=c+1
|
|
if j == n then data[#data+1]=c end
|
|
else
|
|
data[#data+1]=c; s=0
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
local coldata = {};
|
|
for j=1,n do
|
|
coldata[j]={}; local data = coldata[j];
|
|
local s=0;local c=0;
|
|
for i = 1, n do
|
|
if s == 0 and grid[i][j]==1 then s=1;c=0 end
|
|
if s == 1 then
|
|
if grid[i][j]==1 then
|
|
c=c+1
|
|
if i == n then data[#data+1]=c end
|
|
else
|
|
data[#data+1]=c; s=0
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
return rowdata,coldata
|
|
end
|
|
|
|
read_field = function()
|
|
local grid = {};
|
|
for i = 1, n do
|
|
grid[i]={};
|
|
for j = 1,n do
|
|
local typ = keyboard.read({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+i});
|
|
if typ == "basic_robot:buttonlight_grey" then grid[i][j] = 0 else grid[i][j] = 1 end
|
|
end
|
|
end
|
|
return grid
|
|
end
|
|
|
|
rowdata,coldata = getcounts(grid)
|
|
|
|
check_solution = function()
|
|
local rdata,cdata;
|
|
rdata,cdata = getcounts(read_field())
|
|
for i = 1,#rdata do
|
|
if #rdata[i]~=#rowdata[i] then return false end
|
|
for j = 1, #rdata[i] do
|
|
if rdata[i][j]~=rowdata[i][j] then return false end
|
|
end
|
|
end
|
|
|
|
for i = 1,#cdata do
|
|
if #cdata[i]~=#coldata[i] then return false end
|
|
for j = 1, #rdata[i] do
|
|
if cdata[i][j]~=coldata[i][j] then return false end
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
get_difficulty = function()
|
|
local easy = 0;
|
|
for k = 1, n do
|
|
local sum=0
|
|
for i = 1,#rowdata[k]-1 do
|
|
sum = sum + rowdata[k][i]+1;
|
|
end
|
|
if #rowdata[k]>0 then sum = sum + rowdata[k][#rowdata[k]] else sum = n end
|
|
if sum == n then easy = easy + 1 end
|
|
end
|
|
|
|
for k = 1, n do
|
|
local sum=0
|
|
for i = 1,#coldata[k]-1 do
|
|
sum = sum + coldata[k][i]+1;
|
|
end
|
|
if #coldata[k]>0 then sum = sum + coldata[k][#coldata[k]] else sum = n end
|
|
if sum == n then easy = easy + 1 end
|
|
end
|
|
easy = n-1-easy;
|
|
if easy < 0 then easy = 0 end
|
|
return easy
|
|
end
|
|
|
|
-- render game
|
|
for i=1,n do
|
|
for j =1,n do
|
|
keyboard.set({x=spawnpos.x-n+j,y=spawnpos.y,z=spawnpos.z+i},0) -- clear
|
|
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+2*n-i+1},0) -- clear
|
|
local typ;
|
|
if grid[j][i]==0 then typ = 13 else typ = 2 end
|
|
if not solved then typ = 13 end
|
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ) --board
|
|
end
|
|
end
|
|
|
|
--render counts rows
|
|
for i=1,n do
|
|
length = #rowdata[i]
|
|
for k = 1,length do
|
|
keyboard.set({x=spawnpos.x-length+k,y=spawnpos.y,z=spawnpos.z+i},rowdata[i][k]+17)
|
|
end
|
|
end
|
|
--render counts coloumns
|
|
for j=1,n do
|
|
length = #coldata[j]
|
|
for k = 1,length do
|
|
keyboard.set({x=spawnpos.x+j,y=spawnpos.y,z=spawnpos.z+k+n},coldata[j][k]+17)
|
|
end
|
|
end
|
|
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},9) -- game check button
|
|
keyboard.set({x=spawnpos.x+2,y=spawnpos.y,z=spawnpos.z},7) -- game check button
|
|
|
|
local players = find_player(6,spawnpos)
|
|
if not players then error("nonogram: no players near") end
|
|
local pname = players[1];
|
|
|
|
self.listen_punch(self.pos()) -- attach punch listener
|
|
|
|
--self.label()
|
|
|
|
--self.label(string.gsub(_G.dump(read_field()),"\n","") )
|
|
difficulty = get_difficulty()
|
|
reward = 0; limit = 0;
|
|
|
|
if difficulty == 5 then limit = 120 reward = 10
|
|
elseif difficulty == 4 then limit = 115 reward = 9 -- 60s
|
|
elseif difficulty == 3 then limit = 100 reward = 8
|
|
elseif difficulty == 2 then limit = 80 reward = 7
|
|
elseif difficulty <= 1 then limit = 70 reward = 6
|
|
end
|
|
if not scores[difficulty] then scores[difficulty] = {{"-",-999}} end
|
|
if not scores[difficulty][1] then scores[difficulty][1] = {"-",-999} end
|
|
|
|
minetest.chat_send_player(pname, "nonogram difficulty " .. difficulty .. ". you will get " .. reward .. " gold if you solve it in faster than " .. limit .."s" ..
|
|
". Current record " .. -scores[difficulty][1][2] .. " by " .. scores[difficulty][1][1])
|
|
|
|
|
|
end
|
|
|
|
event = keyboard.get()
|
|
if event then
|
|
if event.y == spawnpos.y and event.z == spawnpos.z then
|
|
if event.x == spawnpos.x+1 then -- check solution
|
|
if check_solution() then
|
|
t = _G.minetest.get_gametime(); t = t- t0;
|
|
local msg = "";
|
|
keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z},2)
|
|
msg = n .. "x" .. n .. " nonogram (difficuly " .. difficulty .. ") solved by " .. event.puncher .. " in " .. t .. " seconds. "
|
|
|
|
if t < limit then
|
|
msg = msg .. " He gets " .. reward .. " gold for quick solve.";
|
|
else
|
|
reward = reward*2*(1-2*(t-limit)/limit)/2; if reward<0 then reward = 0 end
|
|
reward = math.floor(reward);
|
|
msg = msg .. " Your time was more than " .. limit .. ", you get " .. reward .. " gold ";
|
|
end
|
|
|
|
-- highscore
|
|
if add_score(scores,event.puncher,-t,difficulty) then
|
|
say("nonogram difficulty " .. difficulty .. ": new record " .. t .. " s !")
|
|
local sdata = scores[difficulty];
|
|
local out = {"TOP 5 PLAYERS/TIMES: "}; for i=1,#sdata do out[#out+1] = sdata[i][1] .. " " .. -sdata[i][2].."," end say(table.concat(out," "))
|
|
book.write(1,"scores", minetest.serialize(scores))
|
|
end
|
|
|
|
|
|
if reward>0 then
|
|
local player = _G.minetest.get_player_by_name(event.puncher);
|
|
if player then
|
|
local inv = player:get_inventory();
|
|
inv:add_item("main",_G.ItemStack("default:gold_ingot " .. reward))
|
|
end
|
|
end
|
|
minetest.chat_send_player(event.puncher,msg)
|
|
|
|
self.remove()
|
|
|
|
else self.label("FAIL") end
|
|
elseif event.x == spawnpos.x+2 then -- solve
|
|
minetest.chat_send_player(event.puncher,"you gave up on game, displaying solution")
|
|
for i=1,n do
|
|
for j =1,n do
|
|
local typ;
|
|
if grid[j][i]==0 then typ = 13 else typ = 2 end
|
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},typ)
|
|
end
|
|
end
|
|
self.remove()
|
|
end
|
|
else
|
|
local i = event.x-spawnpos.x;local j = event.z-spawnpos.z;
|
|
if i>0 and i<=n and j>0 and j<=n then
|
|
local typ = keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j});
|
|
local newtyp;
|
|
if typ ~= "basic_robot:buttonlight_grey" then newtyp = 13
|
|
else newtyp = 2
|
|
end
|
|
keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},newtyp);
|
|
end
|
|
end
|
|
end |