summaryrefslogtreecommitdiff
path: root/module/tex/context/third/simpleslides/automata/automata-eca.lua
blob: 4dcf3c7fa1c185ba35f852fa7b34d4b959b34888 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
--
--------------------------------------------------------------------------------
--         FILE:  automata-eca.lua
--  DESCRIPTION:  drawing elementary cellular automata
-- REQUIREMENTS:  ConTeXt MkIV with Simple Slides module
--         BUGS:  uncountable minus the few I found
--       AUTHOR:  Philipp Gesang (Phg), <megas.kapaneus@gmail.com>
--      VERSION:  1.0
--      CREATED:  14/08/10 19:43:35 CEST
--------------------------------------------------------------------------------
--

if context then
    environment.loadluafile( "automata-life" )
else
    require "automata-life"
end

local help = gol.helpers

local C, Cs, Ct, P, R, S, match = lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S, lpeg.match

eca = {}

function eca.parse_file (fname)
    local f = assert(io.open(fname, "r"), "No such file: "..fname..".")
    local init = f:read("*all")
    f:close()

    return help.strip(init)
end

function eca.to_base(number, base)
    local alphabet, result, cnt, remainder = "0123456789abcdef", "", 0                   
    while number > 0 do
        cnt = cnt + 1 
        number, remainder = math.floor(number / base), (number % base) + 1 
        result = string.sub(alphabet, remainder, remainder) .. result
    end 
    return result
end

function eca.gen_rule(nr)
    local rules = {}
    local states = { "111", "110", "101", "100", "011", "010", "001", "000" }
    
    nr = string.format("%8s",eca.to_base(nr, 2)):gsub(" ", "0")

    local n = 1
    while n <= #states  do
        rules[states[n]] = nr:sub(n,n)
        n = n + 1
    end

    return rules
end

function eca.next_line(from, rule)
    local new = ""
    from = "0"..from.."0"  -- assume dead borders
    --from = string.format("0%s0", from) -- too slow

    local cell = C(S"01")
    local cells= Ct(cell * #(cell * cell)) / function (t) -- I ♡ LPEG
        local three = t[1]..t[2]..t[3]
        new = new .. rule[three]
    end
    lpeg.match(cells^1, from)
    return new
end

function eca.stripcells (str, dir, cnt)
    if     dir == "left"  then
        return str:sub( cnt )
    elseif dir == "right" then
        return str:sub( 0, str:len() - cnt )
    else -- assume ambilateral clipping
        return str:sub( cnt, str:len() - cnt )
    end
end

function eca.gen_frame(from, lines, rule)

    local cnt = 1
    local c = mplife.setup.current

    local new = { [1] = eca.stripcells(from, c.clip, c.diff or 0 ) }

    repeat
        from = eca.next_line(from, rule)
        table.insert( new, eca.stripcells(from, c.clip, c.diff or 0) )
        cnt = cnt + 1
    until cnt == lines
    return eca.next_line(from, rule), new
end

function eca.successive (current)
    local thisframe
    current.from, thisframe = eca.gen_frame(current.from, current.framesize, current.rule)
    for _,j in ipairs(thisframe) do 
        io.write(j:gsub("0","·"):gsub("1","O").."\n") 
    end
    return 0
end

return eca