diff --git a/init.lua b/init.lua index 8ebadf1..82d5047 100644 --- a/init.lua +++ b/init.lua @@ -79,7 +79,7 @@ function getSandboxEnv (name) backward = function(item, inventory) return commands.insert_item(name,item, inventory,4) end, down = function(item, inventory) return commands.insert_item(name,item, inventory,6) end, up = function(item, inventory) return commands.insert_item(name,item, inventory,5) end, - forward_down = function() return commands.insert_item(name,item, inventory,7) end, + forward_down = function(item, inventory) return commands.insert_item(name,item, inventory,7) end, }, take = { -- takes item from inventory and puts it in robot inventory @@ -99,7 +99,7 @@ function getSandboxEnv (name) backward = function(itemname, inventory,i) return commands.check_inventory(name,itemname, inventory,i,4) end, down = function(itemname, inventory,i) return commands.check_inventory(name,itemname, inventory,i,6) end, up = function(itemname, inventory,i) return commands.check_inventory(name,itemname, inventory,i,5) end, - forward_down = function(item, inventory) return commands.check_inventory(name,itemname, inventory,i,7) end, + forward_down = function(item, inventory,i) return commands.check_inventory(name,itemname, inventory,i,7) end, self = function(itemname, inventory,i) return commands.check_inventory(name,itemname, inventory,i,0) end, }, @@ -425,10 +425,8 @@ function getSandboxEnv (name) }, colorize = core.colorize, - tonumber = tonumber, - pairs = pairs, - ipairs = ipairs, - error = error, + tonumber = tonumber, pairs = pairs, + ipairs = ipairs, error = error, type=type, --_ccounter = basic_robot.data[name].ccounter, -- counts how many executions of critical spots in script diff --git a/scripts/avl_tree~.lua b/scripts/avl_tree~.lua new file mode 100644 index 0000000..595ba86 --- /dev/null +++ b/scripts/avl_tree~.lua @@ -0,0 +1,175 @@ +-- 1. MEMORY MANAGEMENT using array with addresses +-- note: this is all done "automatic" in c with malloc + +mem = {}; +mem.size = 10; -- how many available addresses in memory for each of internally used arrays +mem.freestk = {}; -- stack of free addresses in memory +mem.stkidx = mem.size; +for i = 1,mem.size do mem.freestk[i]=mem.size-i+1 end -- so: freestk = {memsize, memsize-1,...., 2, 1 } and head is at last one + +mem.allocate = function() -- pop free spot from stack + if mem.stkidx>0 then + mem.stkidx = mem.stkidx -1 + return mem.freestk[mem.stkidx+1] + end +end + +mem.free = function(addr) -- release spot and mark it as free + if mem.stkidx>=mem.size then -- cant release anymore, all is free + return + end + mem.stkidx = mem.stkidx +1; + mem.freestk[mem.stkidx ] = addr; +end + + +-- 2. BALANCED BINARY SEARCH TREES USING POINTERS created with above MEMORY MANAGEMENT + +idx = mem.allocate(); + +tree = {}; +tree.data = { root = 0, count = 0, -- current root, element count + left = {0}, parent = {0}, right = {0}, -- links + key = {0}, -- value + heightl = {0}, heightr = {0} -- needed for balancing + }; +-- root: idx of root element, count: how many elements in tree +-- 6 arrays with data for node stored at address i in memory: +-- left[i] == left child, right[i] = right child, parent[i] = parent, key[i] = stored value, if value left[i]== 0 then no left child... +-- heightl[i] = height of left subtree, heightr[i] = height of right subtree +-- NOTE: initially a root node is added + +tree.insert = function (value) + local data = tree.data; + local idx = data.root; + if data.count == 0 then data.key[idx] = key; data.count = 1 return true end -- just set root key and exit + + local key; + local cidx; -- child idx + + + while (true) do -- insert into tree by walking deeper and doing comparisons + + key = data.key[idx]; + if valuedata.heightr[idx]+1 then + vidx = idx; vdir = 1 + elseif data.heightr[idx]>data.heightl[idx]+1 then + vidx = idx; vdir = 2 + end + + cidx = idx; -- set new child + idx = data.parent[idx]; -- set new parent + end + if vidx~=0 then + say("violation vidx " .. vidx .. " direction " .. vdir) + -- TO DO: apply internal tree rotation to restore balance + if vdir == 1 then -- left violation + --[[ need to reconnect 3 nodes: + D <- vidx C + / \ / \ + C E => A D + / \ / \ + A B B E + CHANGES: + C: new parent is old parent of D, new children are A,D + B: new parent D, + D: new parent is C, new children are B,E + --]] + local Didx = vidx; local Dpar = data.parent[Didx]; + local Cidx = data.left[Didx]; + local Bidx = data.right[Cidx]; + local Aidx = data.left[Cidx]; + + data.parent[Cidx] = Dpar;data.left[Cidx] = Aidx;data.right[Cidx] = Didx; + data.parent[Bidx] = Didx; + data.parent[Didx] = Cidx;data.left[Didx] = Bidx; + + + else -- right violation + --[[ need to reconnect 3 nodes: + B <-vidx C + / \ / \ + A C => B E + / \ / \ + D E A D + CHANGES: + B: new parent C, new children A,D + C: new parent is old parent of B, new children are B,E + D: new parent is B + --]] + local Bidx = vidx; local Bpar = data.parent[Bidx]; + local Cidx = data.right[Bidx]; + local Didx = data.left[Cidx]; + + data.parent[Bidx] = Cidx;data.right[Bidx] = data.left[Cidx] + data.parent[Cidx] = Bpar;data.left[Cidx] = Bidx; + data.parent[Didx] = Bidx; + end + end + + else + -- we go deeper + idx = cidx; + end + + end + + tree.find = function(value) + local idx = data.root; + while (idx~=0) do + key = data.key[idx]; + if key == value then return idx end + if valuem+1 or j<0 or j>n+1 then return 0 end; count = 0 + for k = -1,1 do for l = -1,1 do + if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end + end end + return count + end + chk_mines = function() + local count = minescount; + for i=1,m do for j=1,n do + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then + count=count-1 + end + end end + return count + end + + greeting = function() + _G.minetest.chat_send_all(colorize("red","#BATTLE MINESWEEPER : two player battle in minesweeper. say join to play.\nRules: 1. each player has 5 second turn to make a move 2. if you dont make move you lose\n3. if you make move in other player turn you lose. 4. if you hit bomb or mark bomb falsely you lose")) + end + + player_lost = function () + for i=1,#players do + local player = _G.minetest.get_player_by_name(players[i]); + if player then player:setpos({x=spawnpos.x,y=spawnpos.y+10,z=spawnpos.z}) end + end + state = INTERMISSION; t = 0 + end + + function change_turn() + if turn == 1 then + _G.minetest.sound_play("default_break_glass",{pos=spawnpos, max_hear_distance = 100}) + else + _G.minetest.sound_play("note_a",{pos=spawnpos, max_hear_distance = 100}) + end + + if paused == false then + say(players[turn] .. " lost : didn't make a move"); + player_lost() + else + if turn == 1 then turn = 2 else turn = 1 end + self.label("turn " .. turn .. " " .. players[turn]) + t=0 + paused = false + end + end + + init_game() + greeting() + self.listen(1) +end + +if state == SIGNUP then + speaker,msg = self.listen_msg() + if speaker then + if msg == "join" then + players[#players+1] = speaker; + local plist = ""; for i=1,#players do plist = plist .. players[i] .. ", " end + _G.minetest.chat_send_all("BATTLE MINESWEEPER, current players : " .. plist) + + if #players >= 2 then + state = GAME + change_turn(); + keyboard.get(); t=0; + for i = 1, #players do + local player = _G.minetest.get_player_by_name(players[i]); + if player then player:setpos({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z}) end + end + _G.minetest.chat_send_all(colorize("red","BATTLE MINESWEEPER " .. m .. "x" ..n .. " with " .. minescount .. " mines.\n" .. players[turn] .. " its your move!")) + end + + end + end + +elseif state == GAME then + + t = t + 1; + if t>5 then -- change of turn + change_turn() + end + + event = keyboard.get(); + if event and event.type == 2 and not paused then + if event.puncher == players[turn] then + local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; + if x<1 or x>m or z<1 or z>n then + else + local ppos = player.getpos(event.puncher) + if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine + if data[x] and data[x][z] == 1 then + if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then + keyboard.set({x=event.x,y=event.y,z=event.z},2) + else + keyboard.set({x=event.x,y=event.y,z=event.z},3) + end + else + say(event.puncher .. " lost : marked a bomb where it was none! "); + player_lost() + end + else + if data[x] and data[x][z]==1 then + _G.minetest.sound_play("tnt_boom",{pos=spawnpos, max_hear_distance = 100}) + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3) + say(event.puncher .. " lost : punched a bomb! "); + player_lost() + else + local count = get_mine_count(x,z); + if count == 0 then keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4) + else keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},7+count) end + end + end + end + paused = true + else + say(event.puncher .. " lost : played out of his/her turn"); player_lost() + end + end + +elseif state == INTERMISSION then + t=t+1; if t> 15 then state = SIGNUP;players = {}; paused = true; init_game(); greeting() end +end \ No newline at end of file diff --git a/scripts/blackbox.lua b/scripts/blackbox.lua new file mode 100644 index 0000000..d7f0d1c --- /dev/null +++ b/scripts/blackbox.lua @@ -0,0 +1,195 @@ +--black box by rnd, 03/18/2017 +--https://en.wikipedia.org/wiki/Black_Box_(game) + +if not data then + m=8;n=8;turn = 0; + attempts = 1; + + self.spam(1);t0 = _G.minetest.get_gametime(); + spawnpos = self.spawnpos() + data = {}; + for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end + + for i=1,4 do -- put in 4 atoms randomly + data[math.random(m)][math.random(n)] = 1 + end + + render_board = function(mode) -- mode 0 : render without solution, 1: render solution + for i = 1,m do for j = 1,n do -- render game + if mode == 0 or data[i][j] == 0 then + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2) + end + else + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3) + end + end end + end + + get_dirl = function(dir) + local dirl; -- direction left + if dir[1] > 0.5 then dirl = {0,-1} + elseif dir[1] < -0.5 then dirl = {0,1} + elseif dir[2] > 0.5 then dirl = {-1,0} + elseif dir[2] < -0.5 then dirl = {1,0} + end + return dirl + end + + read_pos = function(x,z) + if x<1 or x>m or z<1 or z>n then return nil end + return data[x][z] + end + + newdir = function(x,z,dir) -- where will ray go next + local retdir = {dir[1],dir[2]}; + local xf = x+dir[1]; local zf = z+dir[2] -- forward + local dirl = get_dirl(dir) + + local nodef = read_pos(xf,zf) + local nodel = read_pos(xf + dirl[1],zf + dirl[2]) + local noder = read_pos(xf - dirl[1],zf - dirl[2]) + if nodef == 1 then + retdir = {0,0} -- ray hit something + elseif nodel == 1 and noder ~= 1 then + retdir = {-dirl[1],-dirl[2]} + elseif nodel ~= 1 and noder == 1 then + retdir = {dirl[1],dirl[2]} + elseif nodel == 1 and noder == 1 then + retdir = {-dir[1],-dir[2]} + end + return retdir + end + + shootray = function(x,z,dir) + --say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2]) + local xp = x; local zp = z; + local dirp = {dir[1],dir[2]}; + local maxstep = m*n; + + for i = 1,maxstep do + dirp = newdir(xp,zp,dirp); + if dirp[1]==0 and dirp[2]==0 then return -i end -- hit + xp=xp+dirp[1];zp=zp+dirp[2]; + if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out + end + return 0 -- hit + end + + count = 0; -- how many letters were used up + border_start_ray = function(x,z) + local rdir + if x==0 then rdir = {1,0} + elseif x == m+1 then rdir = {-1,0} + elseif z == 0 then rdir = {0,1} + elseif z == n+1 then rdir = {0,-1} + end + if rdir then + local result,out = shootray(x,z,rdir); + if result >= 0 then + + if out then + if out[1]==x and out[2]==z then -- got back where it originated, reflection + keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1); + else + if result<=1 then + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off + else + local nodename = "default:obsidian_letter_"..string.char(97+count) .. "u"; + _G.minetest.set_node( + {x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]}, + {name = nodename, param2 = 1}) + _G.minetest.set_node( + {x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z}, + {name = nodename, param2 = 1}) + count = count + 1; + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4); + keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4); + end + end + end + elseif result<0 then + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit + end + end + end + + -- initial border loop and marking + + --render blue border + for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+0},5) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},5) end + for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},5) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},5) end + + for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+0},0) keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+n+1},0) end + for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end + + + z=0 -- bottom + for x = 1,m do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + x=m+1 -- right + for z = 1,n do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + z=n+1 -- top + for x = m,1,-1 do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + x=0 -- left + for z = n,1,-1 do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + check_solution = function() + for i = 1,m do + for j = 1,n do + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonFF8080" then -- red + if data[i][j]~=1 then return false end + else + if data[i][j]~=0 then return false end + end + end + end + return true + end + + --render board + render_board(0) + keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},5) + +end + +event = keyboard.get(); +if event then + local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; + if x<1 or x>m or z<1 or z>n then + if event.type == 5 then + if check_solution() then + say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove() + else + say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.") + attempts = attempts+1 + end + end + else -- interior punch + nodetype = 2; + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then + nodetype = 3 + end + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype); + end + +end +::END:: \ No newline at end of file diff --git a/scripts/blackbox_game.lua b/scripts/blackbox_game.lua new file mode 100644 index 0000000..d7f0d1c --- /dev/null +++ b/scripts/blackbox_game.lua @@ -0,0 +1,195 @@ +--black box by rnd, 03/18/2017 +--https://en.wikipedia.org/wiki/Black_Box_(game) + +if not data then + m=8;n=8;turn = 0; + attempts = 1; + + self.spam(1);t0 = _G.minetest.get_gametime(); + spawnpos = self.spawnpos() + data = {}; + for i = 1,m do data[i]={}; for j = 1,n do data[i][j]=0 end end + + for i=1,4 do -- put in 4 atoms randomly + data[math.random(m)][math.random(n)] = 1 + end + + render_board = function(mode) -- mode 0 : render without solution, 1: render solution + for i = 1,m do for j = 1,n do -- render game + if mode == 0 or data[i][j] == 0 then + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2) + end + else + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},3) + end + end end + end + + get_dirl = function(dir) + local dirl; -- direction left + if dir[1] > 0.5 then dirl = {0,-1} + elseif dir[1] < -0.5 then dirl = {0,1} + elseif dir[2] > 0.5 then dirl = {-1,0} + elseif dir[2] < -0.5 then dirl = {1,0} + end + return dirl + end + + read_pos = function(x,z) + if x<1 or x>m or z<1 or z>n then return nil end + return data[x][z] + end + + newdir = function(x,z,dir) -- where will ray go next + local retdir = {dir[1],dir[2]}; + local xf = x+dir[1]; local zf = z+dir[2] -- forward + local dirl = get_dirl(dir) + + local nodef = read_pos(xf,zf) + local nodel = read_pos(xf + dirl[1],zf + dirl[2]) + local noder = read_pos(xf - dirl[1],zf - dirl[2]) + if nodef == 1 then + retdir = {0,0} -- ray hit something + elseif nodel == 1 and noder ~= 1 then + retdir = {-dirl[1],-dirl[2]} + elseif nodel ~= 1 and noder == 1 then + retdir = {dirl[1],dirl[2]} + elseif nodel == 1 and noder == 1 then + retdir = {-dir[1],-dir[2]} + end + return retdir + end + + shootray = function(x,z,dir) + --say("ray starts " .. x .. " " .. z .. " dir " .. dir[1] .. " " .. dir[2]) + local xp = x; local zp = z; + local dirp = {dir[1],dir[2]}; + local maxstep = m*n; + + for i = 1,maxstep do + dirp = newdir(xp,zp,dirp); + if dirp[1]==0 and dirp[2]==0 then return -i end -- hit + xp=xp+dirp[1];zp=zp+dirp[2]; + if xp<1 or xp>m or zp<1 or zp>n then return i,{xp,zp} end -- out + end + return 0 -- hit + end + + count = 0; -- how many letters were used up + border_start_ray = function(x,z) + local rdir + if x==0 then rdir = {1,0} + elseif x == m+1 then rdir = {-1,0} + elseif z == 0 then rdir = {0,1} + elseif z == n+1 then rdir = {0,-1} + end + if rdir then + local result,out = shootray(x,z,rdir); + if result >= 0 then + + if out then + if out[1]==x and out[2]==z then -- got back where it originated, reflection + keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},1); + else + if result<=1 then + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},6); -- immediate bounce off + else + local nodename = "default:obsidian_letter_"..string.char(97+count) .. "u"; + _G.minetest.set_node( + {x=spawnpos.x+out[1],y=spawnpos.y+1,z=spawnpos.z+out[2]}, + {name = nodename, param2 = 1}) + _G.minetest.set_node( + {x=spawnpos.x+x,y=spawnpos.y+1,z=spawnpos.z+z}, + {name = nodename, param2 = 1}) + count = count + 1; + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4); + keyboard.set({x=spawnpos.x+out[1],y=spawnpos.y,z=spawnpos.z+out[2]},4); + end + end + end + elseif result<0 then + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3); -- hit + end + end + end + + -- initial border loop and marking + + --render blue border + for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+0},5) keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+n+1},5) end + for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y,z=spawnpos.z+j},5) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y,z=spawnpos.z+j},5) end + + for i = 1,m do keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+0},0) keyboard.set({x=spawnpos.x+i,y=spawnpos.y+1,z=spawnpos.z+n+1},0) end + for j = 1,n do keyboard.set({x=spawnpos.x+0,y=spawnpos.y+1,z=spawnpos.z+j},0) keyboard.set({x=spawnpos.x+m+1,y=spawnpos.y+1,z=spawnpos.z+j},0) end + + + z=0 -- bottom + for x = 1,m do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + x=m+1 -- right + for z = 1,n do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + z=n+1 -- top + for x = m,1,-1 do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + x=0 -- left + for z = n,1,-1 do + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button8080FF" then + border_start_ray(x,z) + end + end + + check_solution = function() + for i = 1,m do + for j = 1,n do + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}) == "basic_robot:buttonFF8080" then -- red + if data[i][j]~=1 then return false end + else + if data[i][j]~=0 then return false end + end + end + end + return true + end + + --render board + render_board(0) + keyboard.set({x=spawnpos.x,y=spawnpos.y,z=spawnpos.z-1},5) + +end + +event = keyboard.get(); +if event then + local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; + if x<1 or x>m or z<1 or z>n then + if event.type == 5 then + if check_solution() then + say("#BLACKBOX : CONGRATULATIONS! " .. event.puncher .. " found all atoms after " .. attempts .. " tries."); self.remove() + else + say("#BLACKBOX : " .. event.puncher .. " failed to detect atoms after " .. attempts .. " attempts.") + attempts = attempts+1 + end + end + else -- interior punch + nodetype = 2; + if keyboard.read({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z}) == "basic_robot:button808080" then + nodetype = 3 + end + keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},nodetype); + end + +end +::END:: \ No newline at end of file diff --git a/scripts/hash_table_implementation.lua b/scripts/hash_table_implementation.lua new file mode 100644 index 0000000..e2af33d --- /dev/null +++ b/scripts/hash_table_implementation.lua @@ -0,0 +1,108 @@ +if not get_hash then + + get_hash = function(s,p) + if not s then return end + local h = 0; local n = string.len(s);local m = 4; -- put 4 characters together + local r = 0;local i = 0; + while i maxlen then maxlen = length; maxidx = i end + count = count + 1 + end + end + + if maxlen>0 then + local data = hashdb[maxidx]; + say("number of used hash entries is " .. count .. ", average " .. (step/count) .. " entries per hash, ".. + " max length of list is " .. maxlen .. " at hash ".. maxidx )--.. " : " .. + --string.gsub(_G.dump(data),"\n","") ) + + end + end + + -- LOAD DICTIONARY WORDS into hashtable + + lang = "german" + + fname = "F:\\games\\rpg\\minetest-0415server\\mods\\basic_translate\\"..lang; + local f = _G.assert(_G.io.open(fname, "r"));local dicts = f:read("*all");f:close() + + step = 0; maxwords = 10000; + i=0 + dict = {}; -- for comparison + + while(stepmsgsize then return "messages space exceeded" end + text = text .. "\n"..os.date() .. " " .. sender .. ": " .. msg; + book.write(1,"messages",text) + end + +end + +--textarea[X,Y;W,H;name;label;default] +--button[X,Y;W,H;name;label] +if s == 0 then + players = find_player(4); + if players and players[1] then + s=1 + local form = "size[8,4.5]" .. + "textarea[0,0;9,4.5;msg;MESSAGE FOR ADMIN;]".. + "button_exit[-0.5,4.15;2,1;send;send]" + self.show_form(players[1],form) + end +elseif s==1 then + sender,fields = self.read_form(); + if sender then + if fields.send then + msg = fields.msg; + if msg and msg~="" then + write_msg(sender,msg);activate.up(1) + _G.minetest.chat_send_player(sender,"#mailbot: message has been stored") + end + end + self.remove() + end +end \ No newline at end of file diff --git a/scripts/minesweeper.lua b/scripts/minesweeper.lua new file mode 100644 index 0000000..c34cd71 --- /dev/null +++ b/scripts/minesweeper.lua @@ -0,0 +1,72 @@ +if not data then + m=10;n=10; minescount = 32; + + t0 = _G.minetest.get_gametime(); + data = {}; spawnpos = self.spawnpos() -- place mines + for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end + if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area + data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0; + + minescount = 0; + for i = 1,m do for j = 1,n do -- render game + if data[i] and data[i][j] == 1 then minescount = minescount + 1 end + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2) + end + end end + keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},4) -- safe start spot + get_mine_count = function(i,j) + if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0 + for k = -1,1 do for l = -1,1 do + if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end + end end + return count + end + chk_mines = function() + local count = minescount; + for i=1,m do for j=1,n do + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then + count=count-1 + end + end end + return count + end + say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ") + self.label("find all hidden mines! mark mine by standing on top of block and punch,\notherwise it will uncover the block (and possibly explode).") + +end + +event = keyboard.get(); +if event then + local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; + if x<1 or x>m or z<1 or z>n then + if x == 0 and z == 1 then + local count = chk_mines(); + if count == 0 then + t0 = _G.minetest.get_gametime() - t0; + say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s") + _G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.itemstack("default:diamond 5")) -- diamond reward + else + say("FAIL! " .. count .. " mines remaining ") + end + self.remove() + end + elseif event.type == 2 then + local ppos = player.getpos(event.puncher) + if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine + if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then + keyboard.set({x=event.x,y=event.y,z=event.z},2) + else + keyboard.set({x=event.x,y=event.y,z=event.z},3) + end + else + if data[x] and data[x][z]==1 then + say("boom! "..event.puncher .. " is dead ");keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3);self.remove() + else + local count = get_mine_count(x,z); + if count == 0 then keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4) + else keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},7+count) end + end + end + end +end \ No newline at end of file diff --git a/scripts/minesweeper_game.lua b/scripts/minesweeper_game.lua new file mode 100644 index 0000000..c34cd71 --- /dev/null +++ b/scripts/minesweeper_game.lua @@ -0,0 +1,72 @@ +if not data then + m=10;n=10; minescount = 32; + + t0 = _G.minetest.get_gametime(); + data = {}; spawnpos = self.spawnpos() -- place mines + for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end + if not data[1] then data[1] = {} end if not data[2] then data[2] = {} end -- create 2x2 safe area + data[1][1] = 0;data[1][2] = 0;data[2][1] = 0;data[2][2] = 0; + + minescount = 0; + for i = 1,m do for j = 1,n do -- render game + if data[i] and data[i][j] == 1 then minescount = minescount + 1 end + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})~="basic_robot:button808080" then + keyboard.set({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j},2) + end + end end + keyboard.set({x=spawnpos.x+1,y=spawnpos.y,z=spawnpos.z+1},4) -- safe start spot + get_mine_count = function(i,j) + if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0 + for k = -1,1 do for l = -1,1 do + if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end + end end + return count + end + chk_mines = function() + local count = minescount; + for i=1,m do for j=1,n do + if keyboard.read({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j})=="basic_robot:buttonFF8080" and data[i] and data[i][j]==1 then + count=count-1 + end + end end + return count + end + say("minesweeper " .. m .. "x" ..n .. " with " .. minescount .. " mines ") + self.label("find all hidden mines! mark mine by standing on top of block and punch,\notherwise it will uncover the block (and possibly explode).") + +end + +event = keyboard.get(); +if event then + local x = event.x - spawnpos.x;local y = event.y - spawnpos.y;local z = event.z - spawnpos.z; + if x<1 or x>m or z<1 or z>n then + if x == 0 and z == 1 then + local count = chk_mines(); + if count == 0 then + t0 = _G.minetest.get_gametime() - t0; + say("congratulations! " .. event.puncher .. " discovered all mines in " .. t0 .. " s") + _G.minetest.add_item({x=spawnpos.x,y=spawnpos.y+1,z=spawnpos.z},_G.itemstack("default:diamond 5")) -- diamond reward + else + say("FAIL! " .. count .. " mines remaining ") + end + self.remove() + end + elseif event.type == 2 then + local ppos = player.getpos(event.puncher) + if ppos and math.abs(ppos.x-event.x)<0.5 and math.abs(ppos.z-event.z)<0.5 then -- just mark mine + if keyboard.read({x=event.x,y=event.y,z=event.z})~="basic_robot:button808080" then + keyboard.set({x=event.x,y=event.y,z=event.z},2) + else + keyboard.set({x=event.x,y=event.y,z=event.z},3) + end + else + if data[x] and data[x][z]==1 then + say("boom! "..event.puncher .. " is dead ");keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},3);self.remove() + else + local count = get_mine_count(x,z); + if count == 0 then keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},4) + else keyboard.set({x=spawnpos.x+x,y=spawnpos.y,z=spawnpos.z+z},7+count) end + end + end + end +end \ No newline at end of file diff --git a/scripts/radix_sort.lua b/scripts/radix_sort.lua new file mode 100644 index 0000000..6e3462b --- /dev/null +++ b/scripts/radix_sort.lua @@ -0,0 +1,104 @@ +if not integer_sort then + -- sorts input according to keys, changes ordering to permutation corresponding to new order + integer_sort = function(input, keys, ordering,temp_ordering, m) -- input, keys same length n, m = how many keys, O(2*n+m) + + local n = #input; + local freq = {} -- frequencies of keys + local kpos = {} -- position of keys in sorted array + + for i=1,n do -- count how many occurences - O(n) + local key = keys[ordering[i]]+1; + freq[key]=(freq[key] or 0)+1 + temp_ordering[i]=ordering[i]; + end + + local curpos = 1;kpos[1]=1; + for i =1,m-1 do -- determine positions of keys in final sorted array - O(m) + curpos = curpos + (freq[i] or 0); + kpos[i+1]=curpos -- {2=3, 3 = 6,..., n-1 = 321} + end + + -- actually place values here + for i = 1,n do -- O(n) + local key = keys[temp_ordering[i]]+1; + local pos = kpos[key]; + ordering[pos] = temp_ordering[i]; + kpos[key]=kpos[key]+1; -- move to next spot for that key place + end + end + + permutate = function(input,ordering) + local output = {}; + for i =1,#input do + output[i] = input[ordering[i]] + end + return output + end + + get_digits = function(Num,d,base) -- number, how many digits, what base + local digits = {}; + local num = Num; + local r; + for i = 1, d do + r = num % base; + digits[#digits+1] = r; + num = (num-r)/base + end + return digits + end + + dumparr = function(array) + if _G.type(array) ~= "table" then return array end + local ret = "{"; + for i =1,#array-1 do + ret = ret .. dumparr(array[i]) .. "," + end + ret = ret .. dumparr(array[#array]) + return ret .. "}" + end + + + radix_sort = function(input,d,base) -- array of numbers; base is also number of keys = m, d = how many steps of sorting = number of digits for single number + + out = out .."\nRADIX SORT\n\narray to be sorted " .. dumparr(input) + + local n = #input; + local ordering = {}; local temp_ordering = {}; for i = 1, n do ordering[i]=i end + local keys = {}; + local keylist = {}; + for i = 1,n do + keylist[i] = get_digits(input[i],d,base) + end + + + out = out .."\nlist of keys - ".. d .. " digits of base " .. base .. " expansion of numbers : \n" .. + dumparr(keylist) + + for step = 1, d do + for i =1,n do + keys[i] = keylist[i][step]; + end + integer_sort(input, keys, ordering, temp_ordering, base) + + out = out .."\n"..step .. ". pass integer_sort : " .. dumparr(permutate(input,ordering)) + end + + out = out .. "\nradix sort final result : " .. dumparr(permutate(input,ordering)) + + end + + + --input = {"a","b","c","d","e"} + --keys = {5,3,4,1,2} + --ordering = {}; temp_ordering = {}; for i = 1, #input do ordering[i]=i end + --m=5; + + --integer_sort(input, keys, ordering, temp_ordering,m); + --say(string.gsub(_G.dump(ordering),"\n","")) + --say(string.gsub(_G.dump(permutate(input,ordering)),"\n","")) + out = ""; self.label("") + + input = {23,42,15,8,87}; + radix_sort(input,5,3) -- d, base + self.display_text(out,60,3) +end \ No newline at end of file diff --git a/scripts/serialization.lua b/scripts/serialization.lua new file mode 100644 index 0000000..806ff08 --- /dev/null +++ b/scripts/serialization.lua @@ -0,0 +1,90 @@ +if not itemlist then + inv2string = function(name) + local inv = _G.minetest.get_player_by_name(name):get_inventory() + local list = "" + + for i = 1,32 do + local item = inv:get_stack("main", i):to_string() + list = list .. item .. "," + end + return name .. "," .. list + end + + string2inv = function(str) + local i = string.find(str,","); + local name = string.sub(str,1,i-1); + local step = 0 + local invlist = {}; + while i and step < 33 do + step = step +1 + local i1 = string.find(str,",",i+1) + if not i1 then break end + invlist[#invlist+1]=string.sub(str,i+1,i1-1) + i=i1 + end + return name, invlist + end + + array2string = function(array) + if _G.type(array) ~= "table" then return array end + local ret = "{"; + for i =1,#array-1 do + ret = ret .. array2string(array[i]) .. "," + end + ret = ret .. array2string(array[#array]) + return ret .. "}" + end + + string2array = function(str) + if not string.find(str,"{") then return str end + local lvl = 1; local n = string.len(str); + local i1,i2,count; + count = 0; --1 = {}, 2 = , + local arr = {}; i1 = 2; + for i =2,n do + local c = string.sub(str,i,i); + if c == "{" then + lvl = lvl+1 + elseif c == "}" then + lvl = lvl -1 + elseif c == "," and lvl == 1 then + i2 = i; + count = count+1 + arr[count] = string2array(string.sub(str,i1,i2-1)); i1 = i2+1 + end + end + if i1< n then count = count+1 ; arr[count] = string2array(string.sub(str,i1,n-1)) end + return arr + end + + local arr = {{1,{2,4}},{3,4},{0,{2}},-2}; + --local arr = {1,2,3} + self.spam(1) + say("original array : ".. string.gsub(_G.dump(arr),"\n","") ) + local str = array2string(arr); + say("array2string : " .. str) + local arr1 = string2array(str); + say("string2array: " .. string.gsub(_G.dump(arr1),"\n","")) + + player = find_player(2); + itemlist = {}; + if player then + local list = inv2string(player[1]) + local name,invlist = string2inv(list) + list = "UNIT TEST inv2string\n"..list .. "\nUNIT TEST string2inv\n".. "name = " .. name .."\n".. string.gsub(_G.dump(invlist),"\n","") + form = "size[8,8.5]" .. + "textarea[0,0;7.75,7.5;list;list;" .. list .. "]"; + self.show_form(player[1],form) + end +end + +sender,fields = self.read_form(); +if sender then + if fields.list then + if string.sub(fields.list,1,3) == "DCL" then + local sel = tonumber(string.sub(fields.list,5)) or 1 + say("you selected item " .. itemlist[sel]) + end + end + if fields.quit then self.remove() end +end \ No newline at end of file diff --git a/scripts/shop.lua b/scripts/shop.lua new file mode 100644 index 0000000..d520cf9 --- /dev/null +++ b/scripts/shop.lua @@ -0,0 +1,142 @@ +if not s then + s=0;item = 1; price =""; buyer = "" + _G.minetest.forceload_block(self.pos(),true) + _G.basic_robot.data[self.name()].obj:set_properties({nametag = ""}) + self.listen(1);self.spam(1) + shoplist = {}; + --scan shops: + pos = self.pos(); pos.y=pos.y-5; pos.x=pos.x-6 + pos1 = {x=pos.x-8,y=pos.y-2,z=pos.z-8};pos2 = {x=pos.x+8,y=pos.y+2,z=pos.z+8}; + local shoppos = _G.minetest.find_nodes_in_area(pos1, pos2, "shop:shop"); + --say("scanning... i found " .. #shoppos .. " shops "); + count = 0 + for _,p in pairs(shoppos) do + local inv = _G.minetest.get_meta(p):get_inventory() + local s = inv:get_list("sell");local b = inv:get_list("buy") + local k = s[1]:to_string(); + local v = b[1]:to_string(); + if (k and k~="") and (v and v~="") then count = count +1 shoplist[count] = {k,v} end + end + + local f_sort = function(a,b) return a[1]0 and ci<=count then + if shoplist[ci] then + iname = shoplist[ci][1];local p=string.find(iname,":"); if p then iname = string.sub(iname,p+1) end + sname = shoplist[ci][2];p=string.find(sname,":"); if p then sname = string.sub(sname,p+1) end + ctext = "#SHOP ".. ci .."\n" ..iname .. "\nPRICE\n" .. sname + end + ci=ci+1 + elseif ci == count+1 then ci=0 + elseif ci == 0 then ci=1 + end + + text = "SHOP ROBOT"..os.date("%x") .." " .. os.date("%H:%M:%S").. "\n\n"..ctext + self.display_text(text,10,3); +end + +speaker,msg = self.listen_msg() +if msg then + if s == 0 then + if string.sub(msg,1,5)=="#shop" then + if msg == "#shop" then + --say("say #shop command, where command is list OR armor OR item number. Example: #shop list or #shop 1") + + local list = "1,2,3"; + local form = "size[8,8.5]" .. + "label[0.,0.5;ID]".. + "label[0.4,0.5;BUY]".. + "label[3.,0.5;SELL]" .. + "field[7.2,0.25;1.,1;count;count;".. 1 .."]".. + "button[5.,-0.05;2.,1;ARMOR;ARMOR]".. + "textlist[0,1;7.75,7.5;list;" .. itemlist .. "]"; + self.show_form(speaker,form) + end + end + elseif s == 1 then + if string.sub(msg,1,3)~="buy" then + t=t+1; if t>1 then say("timeout. trade cancelled."); s = 0 end + else + + + s=0 + end + end +end + +sender,fields = self.read_form() +if sender then + local sel = fields.list; --"CHG:3" + --say( string.gsub(_G.dump(fields),"\n","")) + if sel and string.sub(sel,1,3) == "DCL" then + local quantity = tonumber(fields.count) or 1; + local select = tonumber(string.sub(sel,5) or "") or 1; + local item, price + + if shoplist[select] then + item,price = shoplist[select][1],shoplist[select][2]; + end + + local player = _G.minetest.get_player_by_name(sender); + if player and item and price then + + local inv = player:get_inventory(); + if quantity > 99 then quantity = 99 end + if quantity > 1 then + local k = 1; + local i = string.find(price," "); + if i then + k = tonumber(string.sub(price,i+1)) or 1 + price = string.sub(price,1,i-1).. " " .. k*quantity + else + price = price.. " " .. quantity + end + + k=1;i = string.find(item," "); + if i then + k = tonumber(string.sub(item,i+1)) or 1 + item = string.sub(item,1,i-1).. " " .. k*quantity + else + item = item .. " " .. quantity + end + end + + if inv:contains_item("main", price ) then + inv:remove_item("main",price) + inv:add_item("main",item) + _G.minetest.chat_send_player(sender,"#SHOP ROBOT: " .. item .. " sold to " .. sender .. " for " .. price) + else + _G.minetest.chat_send_player(sender,"#SHOP ROBOT: you dont have " .. price .. " in inventory ") + end + end + elseif fields.ARMOR then + local player = _G.minetest.get_player_by_name(sender); + if player then + local inv = player:get_inventory(); + if inv:contains_item("main",_G.ItemStack("default:diamond 30")) then + player:set_armor_groups({fleshy = 50}) + _G.minetest.chat_send_player(sender,"#SHOP ROBOT: you bought 50% damage reduction.") + else + _G.minetest.chat_send_player(sender,"#SHOP ROBOT: you need 30 diamonds to get armor effect") + end + end + end +end \ No newline at end of file diff --git a/scripts/simple_layout_gen.lua b/scripts/simple_layout_gen.lua new file mode 100644 index 0000000..802e3a3 --- /dev/null +++ b/scripts/simple_layout_gen.lua @@ -0,0 +1,24 @@ +if not data then + m=50;n=50; minescount = m*n/10; + + t0 = _G.minetest.get_gametime(); + data = {}; spawnpos = self.spawnpos(); + for i = 1, minescount do local i = math.random(m); local j = math.random(n); if not data[i] then data[i] = {} end; data[i][j] = 1; end + + get_mine_count = function(i,j) + if i<0 or i>m+1 or j<0 or j>n+1 then return 0 end; count = 0 + for k = -1,1 do for l = -1,1 do + if data[i+k] and data[i+k][j+l] == 1 then count = count +1 end + end end + return count + end + + for i = 1,m do for j = 1,n do + if get_mine_count(i,j) > 0 or (data[i] and data[i][j] == 1) then + _G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "basic_robot:buttonFFFFFF"}) + else + _G.minetest.swap_node({x=spawnpos.x+i,y=spawnpos.y,z=spawnpos.z+j}, {name = "default:dirt"}) + end + end end +end +self.remove() \ No newline at end of file