Skip to content

Instantly share code, notes, and snippets.

@Krutoy242
Last active September 6, 2022 16:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Krutoy242/db63637d605c2c247bc95e939c7f7ddd to your computer and use it in GitHub Desktop.
Save Krutoy242/db63637d605c2c247bc95e939c7f7ddd to your computer and use it in GitHub Desktop.
LostUser - template robot BIOS for multiuse
--[[
Lost User - EEPROM for simpliest robot usage
]]
local initProgram = [[
'Constants'
-n([r.iSz]*)
'Essentials'
-\[r.use]
-/[r.swn]
-|[r.plc]
-t[r.tur]
-m[r.mov]
'Inventory'
-^[r.slt]
-#[r.cnt]
-@[r.suc]
-r[r.drp]
-d[r.dur]
'Inv. controller'
-&[ic.equip]
-y[ic.gInvSize]
'Other'
-e{function(s)error(s,0)end}
-p[print]
-z[sleep]
-b[cpr.bep]
'Aliases'
~X"[os.exit]*"
~M"m3"
~R"t{true}"
~L"t{false}"
]]
-- Complicated functions and aliases
..[[-s(!'?{<#i>>0}`^i`*')]] -- Select non-empty slot (fromSlot, toSlot)
..[[-S(!'?{<#i><=0}`^i@1*`*')]] -- Suck from top (fromSlot, toSlot)
..[[-E(!'?{<#i>>0}`^ir0*`*')]] -- Empty all down (fromSlot, toSlot)
..[[~%"?{<a>==nil}"]] -- Is a nil
..[[~N"-a{not <a>}"]] -- Negate a
..[[~Z"%`~F'ta'N` ?M*'F?M`FN``RRMN`'"]] -- Zig-Zag move
..[[~C"?(y0)'E{13}nS1{12}''^{13}/0s1{12}|0'Z"]] -- Ferrous-juniper farming
-----------------------------------------------------------------
-----------------------------------------------------------------
-- If we run from OpenOS
if require then
_G.component = require'component'
_G.computer = require'computer'
else
print = function()end
end
_G.proxy = function(name)
local p = component.list(name)()
return p and component.proxy(p) or nil
end
_G.r = proxy"robot"
_G.ic = proxy"y_c"
local CMD, PROG
local ALS,VARS,logLvl = {},{},0
local tab = ''
local function l(n)
if type(n)=="boolean" then
if n then tab = tab..' '
else tab = tab:sub(1, -3) end
else
return function (...)
if logLvl >= n then
local s = ''
for k,v in pairs(table.pack(...)) do
if k~='n' then
s=s..(s==''and''or' ')..tostring(v)
end
end
print(tab..s)
end
return select(2,...)
end
end
end
_G.sleep = os and os.sleep or function(t)
local u = computer.uptime
local d = u() + (t or 0)
repeat computer.pullSignal(d - u())
until u() >= d
end
-- Lambda-function maker
local function L(f, ...)
local defaults = table.pack(...)
if defaults.n == 0 then
return f
end
local fArgIndex = 1
local fArgs = {}
local function appendNextArg()
if fArgIndex > defaults.n then
return f(table.unpack(fArgs, 1, defaults.n))
end
return function(...)
local fArgsParts = table.pack(...)
if fArgsParts.n == 0 then
if defaults and defaults[fArgIndex] ~= nil then
fArgs[fArgIndex] = defaults[fArgIndex]
else
fArgs[fArgIndex] = nil
end
fArgIndex = fArgIndex + 1
else
for i = 1, fArgsParts.n do
if fArgsParts[i]~=nil then
fArgs[fArgIndex] = fArgsParts[i]
else
if defaults and defaults[fArgIndex] ~= nil then
fArgs[fArgIndex] = defaults[fArgIndex]
else
fArgs[fArgIndex] = nil
end
end
fArgIndex = fArgIndex + 1
end
end
return appendNextArg()
end
end
return appendNextArg()
end
-- Get first object field key by shortand
local function getKey(short, obj)
local t,rgx = {},'^'..short:gsub('.','%1.*')
for k in pairs(obj)do
if k:match(rgx)then table.insert(t,k) end
end
table.sort(t)
return t[1]
end
-- Get value from global
-- Example: api('robt.use') would return robot.use as function
local function api(s)
local p,t,k = _G, {}, nil
for c in s:gmatch'[^.]+' do
if p==nil then break end
k = getKey(c, p)
p = p[k]
t[#t+1] = k
end
return p, table.concat(t,'.')
end
-- Load lua code but replace some code with LostUser program result
local luaRgx = '<([^>]+)>'
local function loadLua(str)
local k,t = 1,{}
str:gsub(luaRgx, function(s) t[k]=s; k=k+1 end)
for i,v in pairs(t) do t[i] = tostring(PROG(v)) end
k=0
local raw = str:gsub(luaRgx, function()
k=k+1
return t[k]
end)
l(2)('Lua:', '"'..raw..'"')
return load('return '..raw)()
end
-- Run program
PROG = function(str)
if str==nil or str=='' then return end
l(1)('PROGRAM', '"'..tostring(str)..'"','{')
l(true)
local I, c, last = str:gmatch'.', nil, nil
repeat
if type(last)=="function" or type(last)=="table" then
last = last(CMD(I, c))
else
last = CMD(I, c)
end
c = I()
until c==nil
l(false)
l(1)('} return', last)
return last
end
-- Run single-char command
-- consume more characters if required
CMD = function(I, c)
if c==nil then c = I() end
if c==nil or c=='*' then return end
local num = tonumber(c)
if num then return num end
if VARS[c]~=nil then l(2)('VAR',c,'==','"'..tostring(VARS[c])..'"') return VARS[c] end
if ALS[c] then l(2)('ALIAS',c,'==','"'..tostring(ALS[c])..'"') return PROG(ALS[c]) end
local function getString(endChar)
local s,i = '', I()
while i~=nil and i~=endChar do
s,i = s..tostring(i), I()
end
return s
end
if false then
-- Other
elseif c=='-' then local k=I() return L(function(v)
l(2)('-',k,v)
VARS[k]=v
end, true)
elseif c=='~' then local k=I() return L(function(v)
l(2)('~',k,v)
ALS[k]=v
end, '')
-- Operators
elseif c=='?' then return L(function(p,t,e)
l(2)('? if',p,'then','"'..tostring(t)..'"','else','"'..tostring(e)..'"')
if p then return PROG(t) end return PROG(e)
end, false,'','')
elseif c=="'" then local s = getString"'" l(2)("'",s,"'") return s -- Raw String
elseif c=='"' then local s = getString'"' l(2)('"',s,'"') return s
elseif c=='`' then local s = getString'`' l(2)('`',s,'`') return s
elseif c=='(' then local s = getString')' l(2)('(',s,')') return PROG(s) -- Raw Program
elseif c=='{' then local s = getString'}' l(2)('{',s,'}') return loadLua(s)
elseif c=='[' then
local str = getString']'
local F, full = api(str)
l(2)('api:', str, full)
return F, full
elseif c=='!' then
return L(function(prg,a,b)
l(2)('loop: for i =',tostring(a)..',',tostring(b)..', do',prg)
for i=a, b, 1 do
VARS.i = i
local res = PROG(prg)
if res then return res end
end
end, '', 1, math.maxinteger)
end
end
local args = {...}
local program = args[1] or r.name()
-- Play music
for s in program:gmatch"%S" do
computer.beep(200 + s:byte() * 10, 0.05)
end
local argLvl = tonumber(args[2])
if type(argLvl)=='number' and argLvl > 2 then logLvl = argLvl end
-- Init
PROG(initProgram)
logLvl = tonumber(args[2]) or logLvl
while true do
PROG(program)
end
local a=[[
'Constants'
-n([r.iSz]*)
'Essentials'
-\[r.use]
-/[r.swn]
-|[r.plc]
-t[r.tur]
-m[r.mov]
'Inventory'
-^[r.slt]
-#[r.cnt]
-@[r.suc]
-r[r.drp]
-d[r.dur]
'Inv. controller'
-&[ic.equip]
-y[ic.gInvSize]
'Other'
-e{function(s)error(s,0)end}
-p[print]
-z[sleep]
-b[cpr.bep]
'Aliases'
~X"[os.exit]*"
~M"m3"
~R"t{true}"
~L"t{false}"
]]..[[-s(!'?{<#i>>0}`^i`*')]]..[[-S(!'?{<#i><=0}`^i@1*`*')]]..[[-E(!'?{<#i>>0}`^ir0*`*')]]..[[~%"?{<a>==nil}"]]..[[~N"-a{not <a>}"]]..[[~Z"%`~F'ta'N` ?M*'F?M`FN``RRMN`'"]]..[[~C"?(y0)'E{13}nS1{12}''^{13}/0s1{12}|0'Z"]]if require then _G.component=require'component'_G.computer=require'computer'else print=function()end end
_G.proxy=function(b)local c=component.list(b)()return c and component.proxy(c)or nil end
_G.r=proxy"robot"_G.ic=proxy"y_c"local d,e
local f,g,h={},{},0
local i=''local function j(k)if type(k)=="boolean"then if k then i=i..' 'else i=i:sub(1,-3)end else return function(...)if h>=k then local l=''for m,n in pairs(table.pack(...))do if m~='n'then l=l..(l==''and''or' ')..tostring(n)end end
print(i..l)end
return select(2,...)end end end
_G.sleep=os and os.sleep or function(o)local p=computer.uptime
local q=p()+(o or 0)repeat computer.pullSignal(q-p())until p()>=q end
local function s(t,...)local u=table.pack(...)if u.n==0 then return t end
local v=1
local w={}local function x()if v>u.n then return t(table.unpack(w,1,u.n))end
return function(...)local y=table.pack(...)if y.n==0 then if u and u[v]~=nil then w[v]=u[v]else w[v]=nil end
v=v+1 else for z=1,y.n do if y[z]~=nil then w[v]=y[z]else if u and u[v]~=nil then w[v]=u[v]else w[v]=nil end end
v=v+1 end end
return x()end end
return x()end
local function A(B,C)local o,D={},'^'..B:gsub('.','%1.*')for m in pairs(C)do if m:match(D)then table.insert(o,m)end end
table.sort(o)return o[1]end
local function E(l)local c,o,m=_G,{},nil
for F in l:gmatch'[^.]+'do if c==nil then break end
m=A(F,c)c=c[m]o[#o+1]=m end
return c,table.concat(o,'.')end
local G='<([^>]+)>'local function H(I)local m,o=1,{}I:gsub(G,function(l)o[m]=l
m=m+1 end)for z,n in pairs(o)do o[z]=tostring(e(n))end
m=0
local J=I:gsub(G,function()m=m+1
return o[m]end)j(2)('Lua:','"'..J..'"')return load('return '..J)()end
e=function(I)if I==nil or I==''then return end
j(1)('PROGRAM','"'..tostring(I)..'"','{')j(true)local K,F,L=I:gmatch'.',nil,nil
repeat if type(L)=="function"or type(L)=="table"then L=L(d(K,F))else L=d(K,F)end
F=K()until F==nil
j(false)j(1)('} return',L)return L end
d=function(K,F)if F==nil then F=K()end
if F==nil or F=='*'then return end
local M=tonumber(F)if M then return M end
if g[F]~=nil then j(2)('VAR',F,'==','"'..tostring(g[F])..'"')return g[F]end
if f[F]then j(2)('ALIAS',F,'==','"'..tostring(f[F])..'"')return e(f[F])end
local function N(O)local l,z='',K()while z~=nil and z~=O do l,z=l..tostring(z),K()end
return l end
if false then elseif F=='-'then local m=K()return s(function(n)j(2)('-',m,n)g[m]=n end,true)elseif F=='~'then local m=K()return s(function(n)j(2)('~',m,n)f[m]=n end,'')elseif F=='?'then return s(function(c,o,P)j(2)('? if',c,'then','"'..tostring(o)..'"','else','"'..tostring(P)..'"')if c then return e(o)end
return e(P)end,false,'','')elseif F=="'"then local l=N"'"j(2)("'",l,"'")return l elseif F=='"'then local l=N'"'j(2)('"',l,'"')return l elseif F=='`'then local l=N'`'j(2)('`',l,'`')return l elseif F=='('then local l=N')'j(2)('(',l,')')return e(l)elseif F=='{'then local l=N'}'j(2)('{',l,'}')return H(l)elseif F=='['then local I=N']'local Q,R=E(I)j(2)('api:',I,R)return Q,R elseif F=='!'then return s(function(S,T,U)j(2)('loop: for i =',tostring(T)..',',tostring(U)..', do',S)for z=T,U,1 do g.i=z
local V=e(S)if V then return V end end end,'',1,math.maxinteger)end end
local W={...}local X=W[1]or r.name()for l in X:gmatch"%S"do computer.beep(200+l:byte()*10,0.05)end
local Y=tonumber(W[2])if type(Y)=='number'and Y>2 then h=Y end
e(a)h=tonumber(W[2])or h
while true do e(X)end

Lost User - simpliest robot

Robot BIOS program for Minecraft OpenComputers mod.

Why?

OC robots are very difficult to assemble and program. This program for the BIOS will help to use robots as "users" and in many other ways.

Setup

Assemble

Assemble the robot in the minimum configuration:

  • Case
  • CPU
  • RAM

E2E-E

If you play Enigmatica 2: Expert - Extended, modpack have predefined recipe of EEPROM.
Just find it in JEI and craft. It would have colored shining.

If you crafted it, you can skip next step Write program on EEPROM.

Write program on EEPROM.

You need a working OC computer to write the BIOS. See this tutorial to assemble your first computer.

  1. Download file from the internet (need ), run from command line:
wget https://gist.githubusercontent.com/Krutoy242/db63637d605c2c247bc95e939c7f7ddd/raw/lostuser.min.lua
  1. To write on existing EEPROM run:
flash -q lostuser.min.lua LostUser

Insert in robot

Take EEPROM from computer case and merge with robot.

Combining robot with EEPROM

Usage

Robot programmed by renaming it. You must rename Robot on or with (from Integrated Dynamics item).

Name your Robot \3, place on ground, turn on, and see how its clicking blocks in front.

Syntax

TL;DR

If you don't want to learn Lua and you need the robot to right/left click, a few simple names for the robot and the result:

  • \3z The robot will right click on the block on the front each second.
  • /3z The robot will swing with a sword or break the block in front of it.

Naming mechanic

  • Each symbol means command

    Progran run from left to right. Each symbol executed and return its result forward. For example:

    \3z - This program would call robot.use(3) then call robot.move(3)

  • Some actions have parameters

    Parameters can be any value.
    All 1-digit numbers parsed as numbers. Usually its sides.

    |0|1m3 - Place blocks under robot (| is alias for robot.place), then over the robot, then move forward.

  • Commands return values

    This values can be used for other functions as parameters.

    ^(#1) - Select slot equal number of items in first slot. Robot must have Inventory Upgrade

    Program here run first command ^ (robot.select), but it needs a param, so it try to get param from next command. # is alias for robot.count, so its return number used as param for ^ command.

    Notice that without the brackets ^#1, the robot.select function would get the robot.count function as a parameter, which would cause an error.

  • Constants

    There is few constants:

    • n - number of inventory slots. Equal to executing robot.inventorySize()
    • i - if you are inside for i loop, or was in it, return last i
    • * - alias for nil

    #n - Select last slot of robot, if it have inventory upgrade.

Operators

Operators is hardcoded symbols that control program flow.

All parameters have default values. You can use defaul values by calling operators with nil instead parameters.

Symbol Params Description Example
- value=true Write value into variable with symbol right after -. -a5 - writes 5 into variable with name a.
~ program='' Define a symbol right after ~ as alias with code in parameter program. This code would run when alias symbol occur. ~M'm1' MMM - define symbol M as program m1 (means robot.move(1)), and then execute it 3 times.
? condition=false
onTruthy=''
onFalthy=''
if condition then return onTruthy() else return onFalthy() end ?M"R"'L' - If succesfully moved forward, turn right, or turn left otherwise.
?{<#5>>0}'^i'* - select slot 5 if its non-empty. Do nothing otherwise.
! program=''
from='1'
to='maxinteger'
for i=from,to,1 do program() end
Break loop when program() return truthy value
!"?{<#i>>0}'^i'*"1n - Select first non-empty slot.
Symbol Description Example
' " ` Takes all text until next quote and return as string. -a"one'two'" - writes string one'two' into variable a
(code) Run code inside parenthesis and return its value.(¹)
Note that capture is not recursive. (a(b)) would capture (a(b)
z(#1) - sleeps for number of seconds equal to number of items in first slot.
{lua} Return as lua evaluated expression.(²)(³) t{true} - turn right.
^{12} - select 12th slot.
{proxy'piston'.push}3 - push block in front (if piston upgrade installed)
[pointer] Return pointer to globals. Can use shortands. First letter is mandatory, other can content any symbols between. [cpr] or [computer] - return global variable computer
[cpr.bep] - return computer.beep

¹ : Only last result would be returned.

-a1 -b2 ^(ab) - Would select second slot.

² : You can use < > inside lua code to execute program between < > as commands.

-a{not <a>} - Negate variable a.

³ : There is some predefined globals:

  • proxy
  • r = proxy"robot"
  • ic = proxy"y_c"

Predefined

There is many predefined symbols. See them at the beginning of source file.

Debug

Debugging with error()

Robots without screen and GPU cant show messages. So, there is predefined function e that could throw an error that would be visible by right-clicking Analyzer.

e[r.cT] - Error with robot.compareFluidTo documentation.

Debugging from advanced robot

If you want a deeper level of debugging, load the program on a robot with a complete package - , etc.

Download program on robot:

wget https://gist.githubusercontent.com/Krutoy242/db63637d605c2c247bc95e939c7f7ddd/raw/d63a80a7ec6393bad8a44ef6803de9895eec3d43/lostuser.lua

The program can accept 2 commands

  • The program text to execute (instead of the robot's name)
  • Logging output level [1-3]
    1. Programs and subprograms only
    2. All commands
    3. Include initialization commands in the debug

Since the robot screen is very small, I suggest redirecting the output to a file.

Example:

Run this from shell. Robot would move forward and then stop program.

lostuser.lua "MX" 2 > out

Rich debug info would be output into out file:

PROGRAM "MX" {
  ALIAS M == "m3"
  PROGRAM "m3" {
    VAR m == "function(direction:number):boolean -- Move in the specified direction."
  } return true
  ALIAS X == "[os.exit]*"
  PROGRAM "[os.exit]*" {
    api: os.exit os.exit

Examples

IC2 crops

We would use this robot to breeding Industrial Craft 2 crops.

To do this, you need to plant the seeds in a checker order, and put cross sticks between them. Also, the robot has to run along the bed and right-click Weeding Trowel to pick up the weeds.

Ferrous-Juniper farm

In this example, the robot runs a complex program: ?(y0)'E9nS18''^9/0s18|0'Z.

This program:

  1. Tosses items from slots 9-16 down
  2. Picks up items in slots 1-8 from top
  3. Moves in a zig-zag pattern, breaks the block underneath and puts a new one

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment