Implement the Matrix Digital Rain visual effect from the movie "The Matrix" as described in Wikipedia.

Provided is a reference implementation in Common Lisp to be run in a terminal.




--
-- demo\rosetta\Matrix_Digital_Rain.exw
--
with javascript_semantics
sequence sushii = {},   -- w x h of unicode char strings
         colours,       --  """  of their fading colours
         droplets       -- w column droplets, or zeroes

include pGUI.e

Ihandle dlg, canvas, timer
cdCanvas cddbuffer, cdcanvas

procedure rain(integer w,h)
    for x=1 to w do
        integer y = droplets[x]
        if y or rand(40)=1 then
            if y<h then
                droplets[x] = y+1
                sushii[y+1][x] = utf32_to_utf8({0x30A0 + rand(96)})
                colours[y+1][x] = CD_WHITE
            end if
            if y then
                bool clear_droplet = true
                if colours[y][x]=CD_WHITE then
                    colours[y][x] = #00F800 -- (CD_GREEN to nearest #800)
                    clear_droplet = false
                    y -= 1
                end if
                while y>=1 do
                    integer cy = colours[y][x]
                    if cy=0 then exit end if
                    clear_droplet = false
                    cy -= #000800
                    colours[y][x] = cy
                    y -= 1
                end while
                if clear_droplet then
                    droplets[x] = 0
                end if
            end if
        end if
    end for
end procedure

function redraw_cb(Ihandle /*ih*/, integer /*posx*/, /*posy*/)
    integer {w,h} = IupGetIntInt(canvas, "DRAWSIZE"),
            {dx,dy} = cdCanvasGetTextSize(cddbuffer, "W")
    w = max(1,floor(w/dx))
    h = max(1,floor(h/dy))
    if length(sushii)!=h
    or length(sushii[1])!=w then
        sushii = repeat(repeat(" ",w),h)
        colours = repeat(repeat(CD_BLACK,w),h)
        droplets = repeat(0,w)
    end if
    cdCanvasActivate(cddbuffer)
    cdCanvasClear(cddbuffer)
    rain(w,h)
    for x=1 to w do
        for y=1 to h do
            if colours[y][x] then
                cdCanvasSetForeground(cddbuffer, colours[y][x])
                cdCanvasText(cddbuffer,x*dx, (h-y)*dy, sushii[y][x]) 
            end if
        end for
    end for
    cdCanvasFlush(cddbuffer)
    return IUP_DEFAULT
end function

function timer_cb(Ihandle /*ih*/)
    IupUpdate(canvas)
    return IUP_IGNORE
end function

function map_cb(Ihandle ih)
    cdcanvas = cdCreateCanvas(CD_IUP, ih)
    cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
    cdCanvasSetBackground(cddbuffer, CD_BLACK)
    return IUP_DEFAULT
end function

procedure main()
    IupOpen()
    IupSetGlobal("UTF8MODE","YES") 

    canvas = IupCanvas("RASTERSIZE=640x480")
    IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"),
                             "ACTION", Icallback("redraw_cb")})

    timer = IupTimer(Icallback("timer_cb"), 50)

    dlg = IupDialog(canvas,`TITLE="Matrix Digital Rain"`)

    IupShow(dlg)
    IupSetAttribute(canvas, "RASTERSIZE", NULL)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()
