Log In  

It seems I'm using these a lot, so here they are:

-----------------
-- table as string
-----------------

function tab2str(t)
    local s="("
    for i,v in pairs(t) do
        if type(i)=="number" then
            s=s.."["..i.."]="
        else
            s=s..i..'='
        end
        if type(v)=="boolean" then 
            s=s..(v and "true" or "false")
        elseif type(v)=="table" then
            s=s..tab2str(v)
        else
            s=s..v
        end
        s=s..','
    end
    s=sub(s,1,#s-1)--remove last comma
    return s..')'
end

----------
-- example
----------

l={1,2,4,5,s=5}
print(tab2str(l))
----------------
-- clone a table
----------------

function clone(t)
    local c={}
    for i,v in pairs(t) do
        c[i]=type(v)=="table" and clone(v) or v
    end
    return c
end
---------------------------------------------------
-- sort a table (insertion sort)
-- cmp(a,b) should return true when a,b are ordered
---------------------------------------------------

function insort(t,cmp)
    for n=2,#t do
        local i=n
        while i>1 and not cmp(t[i-1],t[i]) do
            t[i],t[i-1]=t[i-1],t[i]
            i-=1
        end
    end
end

----------
-- example
----------

function ascending_y(a,b) 
    return a.y<=b.y 
end

t={}
for i=1,5 do 
    add(t,{i=i,y=rnd(10)}) 
    print(i..': '..t[i].i..' '..t[i].y)
end
print("----")
insort(t,ascending_y)
for i=1,#t do 
    print(i..': '..t[i].i..' '..t[i].y)
end
-- note: better version by kittenm4ster, read below
------------------
-- shuffle a table
------------------

function shuffle(t)
    for n=1,#t*2 do -- #t*2 times seems enough
        local a,b=flr(1+rnd(#t)),flr(1+rnd(#t))
        t[a],t[b]=t[b],t[a]
    end
    return t
end

----------
-- example
----------

t={1,2,3,4}
for i=1,#t do 
    print(i..': '..t[i])
end
print("----")
shuffle(t)
for i=1,#t do 
    print(i..': '..t[i])
end
------------------------------
-- random element from a table
------------------------------

function trand(t) return t[flr(1+rnd(#t))] end

----------
-- example
----------

l={1,2,3,4}
print(trand(l))
-- note: a little overkill token-wise, read below (thanks felice!)
-----------------------------------
-- stack (lifo: last in, first out)
-----------------------------------

lifo={
    new = function() return setmetatable({d={}},lifo) end,
    clear = function(m) m.d={} end,
    len = function(m) return #m.d end,
    empty = function(m) return #m.d==0 end,
    push = function(m,v) m.d[#m.d+1]=v end,
    pop = function(m)
        local v=m.d[#m.d]
        m.d[#m.d]=nil
        return v
    end
} lifo.__index=lifo

----------
-- example
----------

stack = lifo.new()
stack:push(10)
stack:push(20)
stack:push(30)
while(not stack:empty()) do
    print(stack:pop())
end

I think some of these would be handy as part of the pico8 api (clone,sort,shuffle...)

feel free to criticize, comment, correct mine, post yours...

P#49081 2018-02-08 08:32 ( Edited 2018-02-09 01:53)

:: Felice

Wouldn't it be easier just to create a stack as a direct table and use two functions like this?

function pop(s)
    local v=s[#s]
    s[#s]=nil
    return v
end
push=add

mystack={}
push(mystack,"first")
push(mystack,"second")
push(mystack,"third")

> print(#mystack)
3
> print(pop(mystack))
third
> print(pop(mystack))
second
> print(pop(mystack))
first
> print(pop(mystack))
[nil]

Granted, it's not OO, but it's much simpler and less overhead. Heck, you don't really even need push, it's just syntactic sugar.

(I'd love it if @zep included a push/pop like this in the api, but I won't hold my breath. ;) )


I like the trand() idea btw. I do that a lot by hand and never thought to add a helper for it.

P#49085 2018-02-08 11:32 ( Edited 2018-02-08 16:35)

fisher-yates is a better algorithm for shuffling; you only have to run it once and you get a statically unbiased shuffle, apparently (actually I know experientially; I ran a test one time ^u^)

function shuffle(t)
  -- do a fisher-yates shuffle
  for i = #t, 1, -1 do
    local j = flr(rnd(i)) + 1
    t[i], t[j] = t[j], t[i]
  end
end
P#49093 2018-02-08 15:32 ( Edited 2018-02-08 21:10)

@Felice
I agree! most of those methods are quite mundane anyway. makes code more readable but a little overkill in the token scarce pico8 world.

@zep: adding pop() (return and remove last table element) and get() (return and remove first table element) would be ace!

function pop(s)
    local v=s[#s]
    s[#s]=nil
    return v
end

function get(s)
    local v=s[1]
    for i=2,#s do s[i-1]=s[i] end
    s[#s]=nil
    return v
end

stack = {}
add(stack,10)
add(stack,20)
add(stack,30)
while(#stack!=0) do
    print(pop(stack))
end

list = {}
add(list,10)
add(list,20)
add(list,30)
while(#list!=0) do
    print(get(list))
end

btw I'm quite appalled that I've been mindlessly using a stack with "put/get" instead of "push/pop".
maybe I derived this code from a fifo? I have no idea. correcting at once, introspection pending...

@kittenmaster
thanks a lot! I've been copy/pasting those 45 seconds worth of brainstorming for a while :D

P#49105 2018-02-08 20:36 ( Edited 2018-02-09 01:36)

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2020-08-09 19:21 | 0.032s | 4194k | Q:19