Log In  

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?

P#23441 2016-06-22 14:33 ( Edited 2016-06-24 00:41)

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
P#23442 2016-06-22 15:05 ( Edited 2016-06-22 19:05)

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.

P#23443 2016-06-22 15:22 ( Edited 2016-06-22 19:22)

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

P#23444 2016-06-22 15:23 ( Edited 2016-06-22 19:23)

Ahh, that's way more elegant. Thank you!

P#23445 2016-06-22 15:33 ( Edited 2016-06-22 19:33)

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.

P#23450 2016-06-22 17:18 ( Edited 2016-06-22 21:18)
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.

P#23451 2016-06-22 17:22 ( Edited 2016-06-22 21:26)

Nice!

P#23452 2016-06-22 20:08 ( Edited 2016-06-23 00:08)

@gamax92:

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.

P#23456 2016-06-22 20:58 ( Edited 2016-06-23 01:04)

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)

P#23475 2016-06-22 22:48 ( Edited 2016-06-23 02:48)

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.

P#23478 2016-06-22 23:00 ( Edited 2016-06-23 03:00)

Still appreciated, I'm sure someone might need help doing that at some point.

P#23484 2016-06-23 00:51 ( Edited 2016-06-23 04:51)

(You get 1 MB of Lua RAM.)

P#23496 2016-06-23 13:29 ( Edited 2016-06-23 17:29)

@dddaaannn:

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.

P#23505 2016-06-23 16:21 ( Edited 2016-06-23 20:23)

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)

P#23516 2016-06-23 20:41 ( Edited 2016-06-24 00:41)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-28 20:37:49 | 0.015s | Q:30