Permalink
Cannot retrieve contributors at this time
| --- elementary cellular automata | |
| -- @module elca | |
| -- @alias CA | |
| local CA = {} | |
| CA.__index = CA | |
| CA.NUM_STATES = 128 | |
| CA.BOUND_LOW = 0 | |
| CA.BOUND_HIGH = 1 | |
| CA.BOUND_WRAP = 2 | |
| -- constructor | |
| function CA.new() | |
| local ca = setmetatable({}, CA) | |
| ca.state = {} | |
| for i=1,CA.NUM_STATES do | |
| ca.state[i] = 0 | |
| end | |
| ca.bound_mode_l = BOUND_LOW | |
| ca.bound_mode_r = BOUND_LOW | |
| ca.bound_l = 1 | |
| ca.bound_r = 128 | |
| ca.rule = 34 | |
| ca.offset = 0 | |
| return ca | |
| end | |
| -- update all state | |
| function CA:update() | |
| local newState = {} | |
| for i=1,CA.NUM_STATES do | |
| local l, c, r = self:neighbors(i) | |
| local code = CA.code(l, c, r) | |
| if (self.rule & (1 << code)) > 0 then newState[i] = 1 | |
| else newState[i] = 0 end | |
| end | |
| self.state = newState | |
| end | |
| --- helper: return three values to use for neighbor code | |
| --- @return tuple of left, right, center | |
| function CA:neighbors(i) | |
| local l | |
| local r | |
| if i <= self.bound_l then | |
| if self.bound_mode_l == CA.BOUND_LOW then l = 0 | |
| elseif self.bound_mode_l == CA.BOUND_HIGH then l = 1 | |
| else l = self.state[self.bound_r] end | |
| else | |
| l = self.state[i-1] | |
| end | |
| -- right neighbor | |
| if i >= CA.NUM_STATES then | |
| if self.bound_mode_r == CA.BOUND_LOW then r = 0 | |
| elseif self.bound_mode_r == CA.BOUND_HIGH then r = 1 | |
| else r = self.state[self.bound_l] end | |
| else | |
| r = self.state[i+1] | |
| end | |
| -- print("get_neighbors ", i, ":", l, self.state[i], r) | |
| return l, self.state[i], r | |
| end | |
| --- get binary code for value given cell and neighbors | |
| function CA.code(l, c, r) | |
| local n = 0 | |
| if l > 0 then n = n | 4 end | |
| if c > 0 then n = n | 2 end | |
| if r > 0 then n = n | 1 end | |
| return n | |
| end | |
| --- return 8 cells at current offset | |
| --- @return table with 8 binary values | |
| function CA:window(n) | |
| if n == nil then n = CA.NUM_STATES end | |
| local w = {} | |
| for i=1,n do | |
| w[i] = self.state[i + self.offset] | |
| end | |
| return w | |
| end | |
| -- change current state at index, | |
| --- and update the rule to that which would have produced the new state | |
| function CA:set_rule_by_state(val, l, c, r) | |
| local code = CA.code(l, c, r) | |
| print("code: ", code) | |
| if val > 0 then self.rule = self.rule | (1<<code) | |
| else self.rule = self.rule & (~(1<<code)) end | |
| end | |
| function CA:clear() | |
| for i=1,CA.NUM_STATES do self.state[i] = 0 end | |
| end | |
| -- TODO: maybe setter methods that clamp stuff | |
| return CA |