Log In  

Howdy! I'm new to Pico8 and have really enjoyed getting up to speed at creating carts.
An early project that I'm interested in tackling is a Raspberry Pi installation that scrapes the twitter account @Pico8bot and uses the attached functions to recreate the gifs on that account directly in Pico-8.
Looking at the account's github, it's clear that the bot is written entirely in javascript, only utilizing the RGB values of the pico palette and translating the math functions used back into Lua syntax before posting. The gifs are also created at a higher resolution: 320x320.

I've got the skeleton of a cart that re-creates one of the gifs on that account. I'm wondering if I have faithfully recreated the logic of the javascript in Lua, and if there are any tricks I can use to allow my carts to align closer to the source material.

Here is an example of a Pico8bot tweet, and the cart I made that re-creates it (possible seizure warning):

Cart #wepijuzoju-0 | 2018-12-23 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Here is the code used in the above cart:

--using sample function from https://twitter.com/pico8bot/status/1076636083989798912
function getval(x,y,t) return max(t*t, 6.07+t)*sin(9.14)+sqrt(y)*abs(x+3.05)  end
--mod result of function down to pico color space
function getcol(v) return abs(flr(v)) % 16 end

cls()
w, h = 128,128 --real bot uses 320x320, which is not possible in Pico
t = 0

function _draw()
    for i = -w/2, w/2,1 do --x coordinate
        for j = -h/2,h/2,1 do --y coordinate
            val = getcol(getval(i,j,t))
            --js bot draws rectangles instead of setting pixel color values directly
            rectfill(i+w/2,j+h/2,i+w/2+1,j+h/2+1,val) 
        end
    end
    --bot produces gif that loops over t = [0,19]
    t += 1
    if t == 20 then t = 0 end
end

Thanks!

P#60296 2018-12-23 16:45 ( Edited 2018-12-23 16:56)

quick update: I've tweaked the lua code a little bit, and also made a python script to scrape the pico8bot twitter for the functions used. I think I'm all ready to go on setting up an always-on raspberry pi to show weird, glitch-y math.

Here is the python script used to generate the lua file and run pico-8 (i placed this in the folder above where pico-8 lives, and this runs on linux). I'll also put a sample of what one of the generated pico scripts looks like below that:

import subprocess as sp
import time
import requests
from bs4 import BeautifulSoup

p1 = '''pico-8 cartridge // http://www.pico-8.com
version 16
__lua__
'''
p2 = '''function getcol(v) return abs(flr(v)) % 16 end

cls()
w, h = 128,128 --real bot uses 320x320, which is not possible in Pico
t = 0 --time value of functions, [0,19]
l = 0 --number of times t is looped, 6
fi = 1 --what function to use to draw the screen
flag = 0 --checks for blank frames, moves to next function after 5 consecutive ones

function dscreen(f)
    cs = 0
    for i = -w/2, w/2,1 do --x coordinate
            for j = -h/2,h/2,1 do --y coordinate
                val = getcol(f(i,j,t))
                rectfill(i+w/2,j+h/2,i+w/2+1,j+h/2+1,val) 
                cs += val
            end
    end
    return cs
end

function _draw()
    tes = dscreen(fns[fi])
    t += 1
    if tes == 0 then
        if flag < 5 then flag += 1
        else flag = 0 t = 0 l = 0 fi += 1 cls() 
        end
    else flag = 0 
    end
    if t == 20 then t = 0 l += 1 
    end
    if l == 6 then l = 0 fi += 1 flag = 0 cls() 
    end
    if fi > #fns then fi = 1 
    end
end'''

an = './pico-8/pico8'
wn = '-windowed 0'
rn = '-run'

def makefile(l):
    with open(l,'w') as fobj:
        fobj.write(sout)

def runpico(l):
    cm = ' '.join([an,wn,rn,l])
    sp.Popen(cm,shell=True)

def killpico():
    pid = int(sp.check_output(["pidof","-s",an]))
    sp.call(['kill',str(pid)])

def getfun():
    r = requests.get('https://twitter.com/pico8bot')
    soup = BeautifulSoup(r.content,'html.parser')
    ts = soup.find_all('p',class_="TweetTextSize TweetTextSize--normal js-tweet-text tweet-text")
    fns = [i.get_text().split(' #DZY')[0] for i in ts]
    return fns

def makefuns(ls):
    fst = []
    for i in range(len(fns)):
        f1 = 'function '
        f2 = 'gv'+str(i)
        f3 = '(x,y,t) return '
        f4 = fns[i]
        f5 = ' end'
        fst.append(f1+f2+f3+f4+f5)
    return '\n'.join(fst)
def makelist(ls):
    fl1 = 'fns = {'
    fl2 = ','.join(['gv'+str(i) for i in range(len(fns))])
    fl3 = '}\n'
    return fl1+fl2+fl3

while True:
    fn = 'p8b.p8'
    fns = getfun()
    sout = p1+'\n'+makefuns(fns)+ '\n'+makelist(fns)+p2
    makefile(fn)
    runpico(fn)
    time.sleep(60*10)
    killpico()

Cart #pico8botbot-0 | 2018-12-23 | Code ▽ | Embed ▽ | No License

P#60307 2018-12-23 21:18 ( Edited 2018-12-23 21:21)

One more update:
I've now emulated the construction of the math functions, so I no longer need to scrape the twitter account, allowing this to run fully offline. I've also added pico8 to my ~/.bashrc file, so this python script can now be run anywhere. Finally, I've tweaked the lua code somewhat to draw the colors pixel-by-pixel, instead of doing a full-screen refresh. I found that some iterations were too seizure-y to look at. The scanline approach produces a calmer image and gives it a CRT kind of feel.

I'd like to add support for changing to the next function in the queue via keyboard, and a way of displaying the function used on screen. It'd also be nice to be able to flag a function as a 'favorite' to be saved for future use. The inability for pico-8 to write text files complicates this.

Here's what the python script now looks like:

import subprocess as sp
import time
import re
import random
import math
p1 = '''pico-8 cartridge // http://www.pico-8.com
version 16
__lua__
'''
p2 = '''function getcol(v) return abs(flr(v)) % 16 end
cls()
w, h = 128,128 --real bot uses 320x320, which is not possible in Pico
t = 0 --time value of functions, [0,19]
l = 0 --number of times t is looped, 6
fi = 1 --what function to use to draw the screen
flag = 0 --checks for blank frames, moves to next function after 5 consecutive ones
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
function dscreen(f)
    cs = 0
    for j = -h/2, h/2,1 do --y coordinate
            for i = -w/2,w/2,1 do --x coordinate
                for k = 1,400 do end
                val = getcol(f(i,j,t))
                rectfill(i+w/2,j+h/2,i+w/2+1,j+h/2+1,val) 
                cs += val
            end
    end
    return cs
end
while true do
    tes = dscreen(fns[fi])
    t += 1
    if tes == 0 then
        if flag < 5 then flag += 1
        else flag = 0 t = 0 l = 0 fi += 1 
        end
    else flag = 0 
    end
    if t == 20 then t = 0 l += 1 end
    if l == 2 then l = 0 fi += 1 flag = 0 end
    if fi > #fns then fi = 1 fns = shuffle(fns) end
end'''
an = 'pico8'
wn = '-windowed'
rn = '-run'
funs = ['cos(expr)','sin(expr)','expr-expr','expr*expr','expr+expr','expr%expr','abs(expr)',
        'sqrt(expr)','flr(expr)','max(expr,expr)','min(expr,expr)','atan2(expr,expr)']
var = ['x','y','t']
def sfun(x):
    return random.choice(funs)
def snum(x):
    if random.random() > 0.5:
        return random.choice(var)
    else:
        return str(round(10*random.random(),2))
def getfun():
    fns = []
    for i in range(50):
        s1 = 'expr*expr*expr'
        ll = math.floor(random.random()*80+30)
        iters = 0
        while len(s1) < ll and iters < 50:
            s1 = re.sub('expr',sfun,s1)
            iters += 1
        s1 = re.sub('expr',snum,s1)
        fns.append(s1)
    return fns
def makefile(l):
    with open(l,'w') as fobj:
        fobj.write(sout)     
def runpico(l,fs=1):
    cm = ' '.join([an,wn,str(fs),rn,l])
    sp.Popen(cm,shell=True)  
def killpico():
    pid = int(sp.check_output(["pidof","-s",an]))
    sp.call(['kill',str(pid)])
def makefuns(ls):
    fst = ['function gv'+str(i)+'(x,y,t) return '+fns[i]+' end' for i in range(len(fns))]
    return '\n'.join(fst)
def makelist(ls):
    return 'fns = {'+','.join(['gv'+str(i) for i in range(len(fns))])+'}\n'
while True:
    fn = 'p8b.p8'
    fns = getfun()
    sout = p1+'\n'+makefuns(fns)+ '\n'+makelist(fns)+p2
    makefile(fn)
    runpico(fn)
    time.sleep(60*30)
    killpico()
P#60322 2018-12-24 18:36

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2023-04-01 08:16:04 | 0.035s | Q:16