#!/usr/bin/luajit --[[Iterated function system ASCII art animation. GPT-4 output when asked to translate wing.pl, edited. I’ve fixed it, but I think that was more work than just writing the code from scratch, because like GPT-4’s English, its Lua is a lot better at looking right than at being right. The original GPT-4 code had the following problems, which I fixed: - It didn’t use the process ID; instead it used os.time() or os.clock(), which aren’t the same thing and aren’t useful here. GPT-4 claimed you couldn’t getpid() in Lua, and it's true that it's not in the default `os` module; but I’m using LuaJIT, not PUC Lua, so I can call it through the FFI, and anyway `(require 'posix').getpid().pid` works, though it’s clumsier. - It required treating 0 as false, like Perl and Python, but Lua treats it as true. So (t-1 and 40 or 10) didn’t have the desired effect; it was always 40, so the IFS only had two transforms instead of 3. - It had `x` and `y` reversed in the iteration assignments. - It wasn’t using the previous values in the iteration assignments, instead mistakenly indexing into `a`: x,y = a[1][2]/2, a[2][1]/2+(t-1 and 40 or 10) - Relatedly, it had declared `x` and `y` inside the loop, which meant there was no possible way to use their previous values; they would expire at the end of the loop body. - That also meant there was no way to initialize them, but it didn’t try. - It wasn’t rounding `x` and `y` to integers to index into the table, which is implicit in Perl. - It was multiplying column numbers by 2 for some reason: local val = (a[c*2] and (a[c*2][r*2] or 0) or 0) + ... - It had forgotten to multiply one of the numbers fetched from the array in that formula by 2, so it could get 0, 1, or 2, but not 3. - It was using those 0-based numbers to index into the string, but string indices in Lua are 1-based, like table indices. - It was randomizing the PRNG with only os.time(), which only changes once a second, with the result that if you ran it multiple time in a second, it would generate the same random numbers, which was visible as a noise pattern changing once a second with `watch -n .1 ./wing.lua`. So, 11 bugs in all, which is a lot of bugs for the 21 lines of code it came up with. Example output (still frame): ..:::'':::::':::::::'::::::''::::::'':::::''::::::'::::::':::''' ..:::::: ' ':: '::::: '''::..:::::. ''':: '::::: ''':: ' ::::''::::: ' '::::: :::'':::::: ' ':::.: ' . ......:::::..::.. '::. ::::'' ':.. ':. .:::::'':::::.::.' '' '' ':.... '' '' ':::': '':::.:::: ':::::::' ' :::::::::' '::: ':::. ':::::' ''::' ''::' '::' ':: ':: '::::.... ''::::' ........ ':::::::'::'' ':::::'' '':.... ':::::::' '::: ''::: ':: ]] local posix = require 'posix' function getpid() return posix.getpid().pid end math.randomseed(os.time()-getpid()) local a, x, y = {}, 0, 0 for i = 1, 9999 do local t = math.floor(math.random() * 3) if t == 0 then y, x = .3*x - .4*y + 12, .4*x + (.2 + math.abs(getpid()%99/99-.5))*y else y, x = y/2, x/2 + (t==1 and 10 or 40) end local xi, yi = math.floor(x), math.floor(y) if a[xi] == nil then a[xi] = {} end a[xi][yi] = 1 end local str = " .':" for r = 0, 18 do for c = 0, 79 do local i = 0 if a[c] then i = 2*(a[c][r*2] or 0) + (a[c][r*2+1] or 0) end io.write(string.sub(str, i+1, i+1)) end print() end