-- -------------------------------------------------------------------------------- -- 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), -- 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