Lua's standard library has a pair of handy functions called "tonumber()" and "tostring()", but they don't seem to be present with Pico8, which is unfortunate. I realized that you can get a lot more storage space by using strings, rather than sprite byte encoding, but passing it back into usable number data is challenging.
At best, I've got this so far:
function str2hex(str) local dd={} dd["0"] = 0 dd["1"] = 1 dd["2"] = 2 dd["3"] = 3 dd["4"] = 4 dd["5"] = 5 dd["6"] = 6 dd["7"] = 7 dd["8"] = 8 dd["9"] = 9 dd["a"] = 10 dd["b"] = 11 dd["c"] = 12 dd["d"] = 13 dd["e"] = 14 dd["f"] = 15 local obj={} for i=1,#str do obj[i]=dd[sub(str,i,i)] end return obj end |
Basically, for each character, convert it to a number (and then build a second result set where values are actually hexadecimal)
Is there a better way I'm not aware of?
A neat trick of Lua is that you can mix numbers and numberical representations in strings and given that it's a valid number contained in the string, the arithmetic will work.
> "42"+0 42 > "0x64"+0 100 |
While that approach works, having to preface each hex value with "0x" wastes a lot of character and token space. I could of course use a longer value like "0xFFFFFFFF" but that just evaluates to a single number, -1.
Since I'm trying to use to it store data, I would ideally just have a long string of data eg "BACF8409C84BF032", which it would then convert to an array of byte values. It looks like I might have to do my own converter, which is fine I guess, since this will pay off in the long run.
How about 46 tokens instead of 103? #codegolf :
function str2hex(str) local obj={} for i=1,#str do for k=1,16 do if (sub(str,i,i)==sub("0123456789abcdef",k,k)) obj[i]=k-1 break end end return obj end |
I have no idea whether it's faster or slower but at least it takes less tokens and checks for valid characters.
As you said, you can get a lot more storage space by using strings, so why not use one here too n_n
If you're going to use strings to store data, you can get more than 4 bits per character. Use 64 printable characters and you can get 3 bytes per 4 characters.
Something like this, which I've used to encode 6 bits into a character:
--ascii 32..95 with some higher --chars replacing troublesome --string chars like: space \ " uint6_to_char={ "!",'}',"#","$","%","&","'", "(",")","*","+",",","-",".","/", "0","1","2","3","4","5","6","7", "8","9",":",";","<","=",">","?", "@","a","b","c","d","e","f","g", "h","i","j","k","l","m","n","o", "p","q","r","s","t","u","v","w", "x","y","z","[","~","]","^","_"} --lua 1-based arrays are annoying uint6_to_char[0]="{" |
(I don't use the space character just because spaces can get funky if I happen to post sample code to the forum. Because webpages.)
Note that I use 1-char strings instead of a single string because when I say:
out = out..sub(uint6_to_char,v,v) |
I don't want to have lua do this under the hood:
duplicate uint6_to_char[v] into a temporary string append temporary string to out discard temporary string |
Because it'll do that for every single six bits I need to store, and there's no point thrashing the garbage collector while I encode. Which doesn't matter if you're doing the storing during offline tool work, but if it actually happens during gameplay, it might. The downside here is that 64 strings in a list will take more space than a single string. It's your call.
function hex2num(str) local obj={} for i=1,#str do obj[i]=("0x"..sub(str,i,i))+0 end return obj end |
30 tokens.
Green is not a creative color. Don't be green.
That converts a string to a list of nybble values. I'm not sure that's what the OP was looking for.
It's probably more useful to unpack bytes direct to memory:
FUNCTION UNHEX(MEM,HEX) FOR I=1,#HEX,2 DO POKE(MEM,"0X"..SUB(HEX,I,I+1)) MEM+=1 END END |
28 tokens. Note that Lua will auto-convert the 0Xhh string to number in this case, no need to add 0.
Where would you write to memory, though? I mean obviously you'd just write to the address where the resource you wanted was... but in my case I'm creating objects / entries in a table array, so it makes sense to just keep it within Lua's program memory rather than commit it to cart ram (especially since there's no apparent memory cap in this way)
Oh, you're right, I totally forgot that part of your code. Disregard. My solution would be more for storing sprites or maps in strings. My bad.
Still appreciated, I'm sure someone might need help doing that at some point.
Yeah, the thing I was talking about was more about the garbage collection activity than the ram usage.
I'm not sure how much that impacts performance, though, since app performance is largely artificial, based on operation count vs. the virtual cpu's clock, and not on the actual binary app's performance. Garbage collection is probably not counted against your cycle budget. The true application performance is probably more than sufficient even on limited hardware like pocketchip. Simulating a few Mhz worth of operations is really a drop in the bucket for even a one-core embedded processor these days.
Oh I was just responding to Danjen's parenthetical about program memory vs. cart RAM. I agree that Lua RAM is a roomy place to put things, and addressable memory is best for generating/unpacking graphics and sound data to be memcpy()'d into regions used by the built-in functions, and less useful for arbitrary runtime data. (I can't think of another use for the "user data" region of RAM that isn't equally met with Lua data structures. Ideas welcome.) But once you start getting into crazy data manipulation stuff, it's easy to get out-of-memory errors with Lua. This is probably limited to pathological cases, but it's good to know there's a limit. (https://www.lexaloffle.com/bbs/?tid=2776)
[Please log in to post a comment]