local result = {]
- ComputerCraft | Programmable Computers for Minecraft
- → LBPHacker's Content
LBPHacker's Content
There have been 40 items by LBPHacker (Search limited from 10-February 22)
#256063 attempt to concatenate nil and string
Posted by
LBPHacker
on 13 July 2016 - 07:26 AM
in
Ask a Pro
#256026 attempt to concatenate nil and string
Posted by
LBPHacker
on 12 July 2016 - 01:22 PM
in
Ask a Pro
EDIT: Oh, forgot the second part. You could try this to insert commas:
local function insertCommas(number)
local result = {}
for chars in tostring(number):reverse():gmatch("..?.?") do
table.insert(result, chars)
end
return table.concat(result, ","):reverse()
end
#255993 Lua identifier
Posted by
LBPHacker
on 11 July 2016 - 07:37 PM
in
Ask a Pro
local command, arguments = command_line:match("^%s*(.-) (.*)%s*$")This way only the first chunk of non-whitespace characters is stored in command and the rest in arguments, for '-' matches the least possible number of characters. Yes, it could match an empty string had the leading spaces not been already matched by %s*, thus leaving only non-spaces for (.-) to match.
#255988 Lua identifier
Posted by
LBPHacker
on 11 July 2016 - 06:46 PM
in
Ask a Pro
#255753 LUAC binary files and CC
Posted by
LBPHacker
on 08 July 2016 - 10:20 AM
in
Ask a Pro
If you "compile" a Lua source with luac, it'll dump bytecode compatible with the Lua library it was built with. The last time I checked, the bytecode of the official implementation of the Lua library is incompatible with LuaJ's bytecode, so that might be why you get Java-level errors. I get a NullPointerException when I try to loadstring("\27Lua"), so it's not too well protected, you can easily get it to throw a Java-level error with invalid bytecode.
#255701 Checking how much memory is used
Posted by
LBPHacker
on 07 July 2016 - 09:55 AM
in
Ask a Pro
CrazyPyroEagle, on 07 July 2016 - 08:53 AM, said:
#255424 Calculating Bytes in a AE2 Storage Cell on CC
Posted by
LBPHacker
on 03 July 2016 - 08:56 PM
in
Ask a Pro

Well, in that case ...
local cell = 327680
local KILO = 1024
local units = {"B", "KiB", "MiB", "GiB", "TiB"}
local magnitude = math.floor(math.log(cell) / math.log(KILO))
local str = tostring(cell / KILO ^ magnitude):match("^(%d+%.?%d?%d?)%d*0*$") .. units[magnitude + 1]
print(str) -- or something
#255420 Implementing High Score?
Posted by
LBPHacker
on 03 July 2016 - 08:11 PM
in
Ask a Pro
#255417 Calculating Bytes in a AE2 Storage Cell on CC
Posted by
LBPHacker
on 03 July 2016 - 08:00 PM
in
Ask a Pro
This is how you end up with 298 GB of space on a 320 GB external HDD. It's 320 business gigabytes, which translates to 298.02 gibibytes = something around 320000000000 bytes. Pretty awful, I know.
#255411 send a script through rednet to be executed on the other side
Posted by
LBPHacker
on 03 July 2016 - 07:16 PM
in
Ask a Pro
The second argument to both load and loadstring is the so called chunkname. This is what you see in an error message before the line number.
local program_string = ... -- receive the string through rednet, whatever local program_function, load_error = load(program_string, "came-through-rednet") -- you could also send the chunkname over rednet -- beware, program_function might be nil, which means that program_string wasn't a valid Lua source; -- in that case load_error will hold the error message program_function()
You could even send the arguments to the program over rednet. You'd have to pass them to program_function.
#255410 Calculating Bytes in a AE2 Storage Cell on CC
Posted by
LBPHacker
on 03 July 2016 - 07:06 PM
in
Ask a Pro
local cell = 327680
local KILO = 1024
local units = {"B", "KiB", "MiB", "GiB", "TiB"}
local magnitude = math.floor(math.log(cell) / math.log(KILO))
local str = ("%.2f"):format(cell / KILO ^ magnitude):gsub("%.?0+$", "") .. units[magnitude + 1]
print(str) -- or something
#255399 Calculating Bytes in a AE2 Storage Cell on CC
Posted by
LBPHacker
on 03 July 2016 - 04:07 PM
in
Ask a Pro
local cell = 327680
local KILO = 1024
local prefixes = {"", "Ki", "Mi", "Gi", "Ti"}
local magnitude = math.floor(math.log(cell) / math.log(KILO))
local str = ("%.2f %sB"):format(cell / KILO ^ magnitude, prefixes[magnitude + 1])
print(str) -- or something
The only interesting thing in there is the double-math.log trick, the "Change of base formula", explained here.
#255385 events lost in my coroutine manager
Posted by
LBPHacker
on 03 July 2016 - 11:29 AM
in
Ask a Pro
Schedulers (or planifiers, whatever) IRL are used to balance resources, such as keeping a process that requested, for example, a file from the disk frozen until said file can be read from memory, while giving CPU time to other processes that need no files or have already loaded whatever files they're operating with and are actually doing useful work. They might also decide which processes are to be given more CPU time than others, depending on their priority.
In CC there are not too many resources you can balance, and the event model and the environment make it even more difficult to find these things. You can't really balance CPU load, since Lua multitasking is cooperative, not preemptive, so coroutines themselves decide when to yield, not the scheduler. The only other thing that can get coroutines to yield in CC is a piece of code in Java throwing "too long without yielding" errors, but that's pretty much deus ex machina. You can't balance I/O load either since the filesystem functions are blocking as it is. You can't balance events because it makes no sense to do so. What else is there then?
The only use I can see for prioritized scheduling in CC is to ensure that some low level processes (such as a GUI framework driver) get the events before userspace applications do, thus eliminating any chance if the framework falling behind and returning old data when queried by the userspace applications. This could be implemented using a simple well-organized array, which you probably already have anyway in a coroutine manager. Or you could just have multiple arrays, grouping coroutines by priority and resuming the coroutines in the highest priority array first, etc. But this would still just pass an event to every coroutine as soon as possible.
TL;DR: It is possible, but probably not the way you imagined.
#255380 How to split a string at specified character
Posted by
LBPHacker
on 03 July 2016 - 10:36 AM
in
Ask a Pro
#255378 How to split a string at specified character
Posted by
LBPHacker
on 03 July 2016 - 10:27 AM
in
Ask a Pro
Here's one with string.gmatch (read about it here):
local words = {}
for word in str:gmatch("%S+") do
table.insert(words, word)
end
The above code splits str into words not containing anything that matches the character class "%s" (remeber, not containing, hence the "%S" with the uppercase S), which would be space, newline, tabs and form feed, if I recall correctly. It also ignores empty matches, so splitting
"a b" -- note the double spacewould result in
{"a", "b"}, not in {"a", "", "b"}.You could use "[^ ]+" instead of "%S" to allow anything but space in the resulting words, or also anything else, for example "[^;]+" would split str along semicolons.
Since you're planning to parse command lines with this, I must add that this solution is a bit complicated to extend to allow commands with quotes or backslashes to escape spaces, such as
program arg1 arg2 "this is arg3" program arg1 arg2 this\ is\ arg3
#255232 Help with elevator program
Posted by
LBPHacker
on 01 July 2016 - 08:03 AM
in
Ask a Pro
I suggest two changes:
- Make it all event driven: don't poll the input, wait for "redstone" events instead
- Use tables: store the floors and relevant data in tables, iterate those tables when a redstone event occurs
local side = "left"
local direction = {
up = colors.green,
down = colors.red
}
local floors = {
[1] = {
call = colors.black,
here = colors.white
},
[2] = {
call = colors.gray,
here = colors.lightGray
},
[3] = {
call = colors.blue,
here = colors.cyan
}
}
local function waitForChange()
os.pullEvent("redstone")
end
while true do
waitForChange()
local targetFloor, currentFloor
-- This iterates through the floor objects defined above
-- and checks if any of their call lines is asserted.
for ix = 1, #floors do
if rs.testBundledInput(side, floors[ix].call) then
targetFloor = ix
end
if rs.testBundledInput(side, floors[ix].here) then
currentFloor = ix
end
end
-- It's guaranteed that currentFloor is set, because
-- at this point the elevator must be on a floor. Unless
-- the program somehow crashed while the elevator was going,
-- in which case you'd have to fix the elevator anyway.
-- It's not guaranteed that targetFloor ever gets set.
-- In case it doesn't, we just skip over the move code.
if targetFloor then
print("Called from floor " .. targetFloor .. ", currently on " .. currentFloor)
if targetFloor < currentFloor then
print(" Going down")
rs.setBundledOutput(side, direction.down)
elseif targetFloor > currentFloor then
print(" Going up")
rs.setBundledOutput(side, direction.up)
else
print(" Going nowhere")
end
while true do
waitForChange()
if rs.testBundledInput(side, floors[targetFloor].here) then
break
end
end
rs.setBundledOutput(side, 0)
end
endCode works and is tested. It should give you an idea of how I think it should work.
How do the green and red wires work though? Does the elevator just move by itself when they are asserted? Is there a circuit generating the pulses needed by the frame motors? I assumed there is one, so the above code does too.
#255107 How to count people inside the sensor radius
Posted by
LBPHacker
on 29 June 2016 - 05:00 PM
in
Ask a Pro
In any case, you'd count the targets the same way you iterate them, except you'd increment a counter instead of checking their names.
local target_count = 0 for name, basicDetails in pairs(targets) do target_count = target_count + 1 end
Then you'd only let through anyone if target_count was 1.
There's also room for optimization in your code. You could just have a table at the top that'd hold all the players to whom access is to be granted, and the infinite loop should iterate over that table and check its entries against targets.
#255105 read() add string into read before writing
Posted by
LBPHacker
on 29 June 2016 - 04:51 PM
in
Ask a Pro
Re-implementing read in a way that it accepts a 4th parameter which defaults to an empty string if not passed is an option. You'd probably end up with more code than sense, though. For example, the history code is completely useless here.
local function read( _sReplaceChar, _tHistory, _fnComplete, initial_sLine ) -- note the new parameter initial_sLine term.setCursorBlink( true ) local sLine = initial_sLine or "" -- empty string used if initial_sLine is not passed (or it's nil/false) ... -- the rest of read() as seen in bios.lua end read(nil, nil, nil, "initial text") -- you'd call it like this
local function read( _sReplaceChar, _tHistory, _fnComplete, initial_sLine ) -- not the new parameter initial_sLine term.setCursorBlink( true ) local sLine = initial_sLine or "" -- empty string used if initial_sLine is not passed (or it nil/false) local nHistoryPos local nPos = 0 if _sReplaceChar then _sReplaceChar = string.sub( _sReplaceChar, 1, 1 ) end local tCompletions local nCompletion local function recomplete() if _fnComplete and nPos == string.len(sLine) then tCompletions = _fnComplete( sLine ) if tCompletions and #tCompletions > 0 then nCompletion = 1 else nCompletion = nil end else tCompletions = nil nCompletion = nil end end local function uncomplete() tCompletions = nil nCompletion = nil end local w = term.getSize() local sx = term.getCursorPos() local function redraw( _bClear ) local nScroll = 0 if sx + nPos >= w then nScroll = (sx + nPos) - w end local cx,cy = term.getCursorPos() term.setCursorPos( sx, cy ) local sReplace = (_bClear and " ") or _sReplaceChar if sReplace then term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) ) else term.write( string.sub( sLine, nScroll + 1 ) ) end if nCompletion then local sCompletion = tCompletions[ nCompletion ] local oldText, oldBg if not _bClear then oldText = term.getTextColor() oldBg = term.getBackgroundColor() term.setTextColor( colors.white ) term.setBackgroundColor( colors.gray ) end if sReplace then term.write( string.rep( sReplace, string.len( sCompletion ) ) ) else term.write( sCompletion ) end if not _bClear then term.setTextColor( oldText ) term.setBackgroundColor( oldBg ) end end term.setCursorPos( sx + nPos - nScroll, cy ) end local function clear() redraw( true ) end recomplete() redraw() local function acceptCompletion() if nCompletion then -- Clear clear() -- Find the common prefix of all the other suggestions which start with the same letter as the current one local sCompletion = tCompletions[ nCompletion ] sLine = sLine .. sCompletion nPos = string.len( sLine ) -- Redraw recomplete() redraw() end end while true do local sEvent, param = os.pullEvent() if sEvent == "char" then -- Typed key clear() sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) nPos = nPos + 1 recomplete() redraw() elseif sEvent == "paste" then -- Pasted text clear() sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) nPos = nPos + string.len( param ) recomplete() redraw() elseif sEvent == "key" then if param == keys.enter then -- Enter if nCompletion then clear() uncomplete() redraw() end break elseif param == keys.left then -- Left if nPos > 0 then clear() nPos = nPos - 1 recomplete() redraw() end elseif param == keys.right then -- Right if nPos < string.len(sLine) then -- Move right clear() nPos = nPos + 1 recomplete() redraw() else -- Accept autocomplete acceptCompletion() end elseif param == keys.up or param == keys.down then -- Up or down if nCompletion then -- Cycle completions clear() if param == keys.up then nCompletion = nCompletion - 1 if nCompletion < 1 then nCompletion = #tCompletions end elseif param == keys.down then nCompletion = nCompletion + 1 if nCompletion > #tCompletions then nCompletion = 1 end end redraw() elseif _tHistory then -- Cycle history clear() if param == keys.up then -- Up if nHistoryPos == nil then if #_tHistory > 0 then nHistoryPos = #_tHistory end elseif nHistoryPos > 1 then nHistoryPos = nHistoryPos - 1 end else -- Down if nHistoryPos == #_tHistory then nHistoryPos = nil elseif nHistoryPos ~= nil then nHistoryPos = nHistoryPos + 1 end end if nHistoryPos then sLine = _tHistory[nHistoryPos] nPos = string.len( sLine ) else sLine = "" nPos = 0 end uncomplete() redraw() end elseif param == keys.backspace then -- Backspace if nPos > 0 then clear() sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 ) nPos = nPos - 1 recomplete() redraw() end elseif param == keys.home then -- Home if nPos > 0 then clear() nPos = 0 recomplete() redraw() end elseif param == keys.delete then -- Delete if nPos < string.len(sLine) then clear() sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 ) recomplete() redraw() end elseif param == keys["end"] then -- End if nPos < string.len(sLine ) then clear() nPos = string.len(sLine) recomplete() redraw() end elseif param == keys.tab then -- Tab (accept autocomplete) acceptCompletion() end elseif sEvent == "term_resize" then -- Terminal resized w = term.getSize() redraw() end end local cx, cy = term.getCursorPos() term.setCursorBlink( false ) term.setCursorPos( w + 1, cy ) print() return sLine end
EDIT: You can just call it with the last result it returned if you want it to remember the input.
local last while ... -- some loop last = read(nil, nil, nil, last) end
- ComputerCraft | Programmable Computers for Minecraft
- → LBPHacker's Content


