@Felice: Thanks a lot, this is great! Although, did you forget to put in the actual padding code in that second function there? I don't get any padding when I called that function.

I think I've done a logical error somewhere else when making the numbers to convert, though, since all the passwords I generate are invalid :P I'm pretty sure I'm messing up with the endianness somewhere, haha. But I'll probably figure it out.

It's interesting that PICO-8 as a fantasy console has the restriction that all numbers are 16:16 fixed point, and that it's hard to do unsigned int arithmetic. It's the opposite of the restriction I'm used to from actual retro consoles like Game Boy, where all numbers are 8-bit and anything else is really hard to do, haha. (There's some very basic 16-bit arithmetic built in there though, since memory addresses are 16-bit.)

Of course I've kept looking at it after I said I would go to bed. Mine was wrong because I forgot 0 is true in Lua, and yours was wrong only when padding was off and the last digit was 2 because v would become 0 and terminate the loop before the 2 got added on. I copied over your padding and reversing code and now the two versions always agree.

function my_u32dec(v,pad,rev)
local s,c,n="",0,v<0
v=band(v,0x7FFF.FFFF)
repeat
c+=v%0x.000a/0x.0001+(n and 8 or 0)
s=rev and s..c%10 or c%10 ..s
c=flr(c/10)
v/=10
if n then
v+=0xccc.cccc + (c>0 and 0x.0001 or 0)
c=0
n=false
end
until #s==10 or not pad and v==0
return s
end
_offset_80000000={8,4,6,3,8,4,7,4,1,2}
_offset_00000000={0,0,0,0,0,0,0,0,0,0}
function u32dec(v,pad,rev)
local s,c,i,d="",0,0
if v<0 then
v-=0x8000
d=_offset_80000000
else
d=_offset_00000000
end
repeat
i+=1
c+=d[i]+v%0x.000a/0x.0001
s=rev and s..(c%10) or (c%10)..s
c=flr(c/10)
v/=10
until i==10 or not pad and v==0 and d~=_offset_80000000
return s
end
function _init()
-- printh(my_u32dec(0xc06c.71a0))
local tests = 100
local mismatches = 0
for i = 1, tests do
local v = rnd(0x7FFF)
if rnd() < 0.5 then
v *= -1
end
local theirs = u32dec(v)
local mine = my_u32dec(v)
if theirs ~= mine then
mismatches += 1
printh("mismatch "..tostr(v, true))
printh("theirs "..theirs)
printh("mine "..mine)
end
end
printh(tostr(mismatches).." mismatches")
end

I noticed I could do an unsigned /10 with a logical shift right and a /5, so that cured the signed division problem, and your note about everything being okay after the first divide made me realize that I could solve the signed modulo problem by offsetting the initial carry value properly when negative.

Also, the issue you noted above is better-solved by checking not just the value for zero, but also the carry.

function u32dec(v,pad,rev)
local s,i,c="",0,(v>=0 or v==0x8000) and 0 or v%0x.000a<0x.0004 and 6 or -4
repeat
i+=1
c+=v%0x.000a/0x.0001
s=rev and s..(c%10) or (c%10)..s
c=flr(c/10)
v=lshr(v,1)/5 -- unsigned /10
until i==10 or not pad and v==0 and c==0
return s
end

Tested at length against a reference version, with both specific and random numbers. Seems good.

Please confirm my results, though. :)

Side note: Interesting discovery: PICO-8 treats 0x8000 as -32768 for division, but +32768 for modulo.

I did get it to work!! The last version from @mrjorts worked, I got it up and running just a couple of hours ago - I had to seek out and squash some bugs in my own code first where I generated the actual bytes to convert with your algorithms, where I'd used the wrong endianness. If you're interested, this is the algorithm: https://jroatch.xyz/2011/blog/polarium-password-encoding (and the game is Picolarium, which has been posted here on the BBS already).

I'll put in the new version from @Felice, and then I'll also have to implement a nicer UI for the level editor, hehe. But the level editor works and exports levels correctly! I'll still have to import levels based on the 32-bit numbers, but I'll probably manage that myself now. Thanks a bunch, both of you!

If anyone's just itching for more challenges like this one, how about the reverse algorithm?

In other words, given 10 digits (either as a zero-padded string of length 10 or, for simplicity's sake, just a sequence of ints that we can assume are positive numbers <= 9), convert it to an unsigned 32-bit integer.