11 March 2023

This is the source for my Wireworld 1K binary adder. I used Golly to build and save the component in a RLE encoded format, a text-friendly format used directly in the code. See references at the bottom for the format. I commented the source after the Jam. I would not have satisfied the 1K limitation otherwise :)

Image of the binary adder as implemented in Golly

Commented Source

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
pico-8 cartridge // http://www.pico-8.com
version 37
__lua__

w,h=100,15                      -- constant: size of the adder.
ini=split"32,26,20,14,8,2"      -- a lookup table of the x-positions for each of the input bits.
oui=split"91,85,79,73,67,61"    -- a mystery line that never got used, left for your amusement.

function bits(n,y,i)            -- function: set bits ON for input Y given number N.
                                -- this travels through each bit in a number and sets
                                -- the CA cell to an electron if the bit is on.
 i=1                            -- * start at first bit.
    while n>0 do                -- * while number is positive.
     r=n%2                      -- * get modulo 2 of number (even numbers yield 0).
     n=(n-r)/2                  -- * reduce number by result of above, then halve it.
     if r==1 then               -- * if number is odd.
      x=ini[i]                  -- * lookup the x position for this bit.
      ww[y][x]=12               -- * set electron head.
      ww[y][x-1]=7              -- * set electron tail.
     end
     i+=1                       -- * move to next bit.
    end
end

function _init()                -- program entry.
 poke(0x5f5c,30)                -- set custom keypress delay to 30 ticks,
 poke(0x5f5d,30)                -- repeat for key-repeat.
 ww={}                          -- storage for the wireworld cells.
 tf={a=12,b=7,c=9}              -- there are three states in wireworld:
                                -- * copper wire (orange:9)
                                -- * electron tail (white:7)
                                -- * electron head (blue:12)
                                -- a fourth color (green:3) is our insulator.
                                
                                -- next up we have our binary adder in RLE form.
                                -- the split function returns a table of values
                                -- split at commas (these demarcate the rows).
 r=split"2c4.2c4.2c4.2c4.2c4.2c15.6c,46.c6.c5.2c4.2c4.2c4.2c4.2c4.2c4.2c,37c5.4c2.2c2.4c,37.c3.c5.c2.b.c2.42c,4c2.c.c4.2c3.c.c3.2c5.c4.4c.c3.c.2ca2.4c,.c.c2.c.2c3.2c3.3c4.c5.c4.c2.2c.5c6.c3.c.c.c2.4c3.c.c4.2c3.c.c3.2c5.c,2c.2c.c.2c3.2c5.c4.2c4.c4.4c.c3.c.c4.c4.5c3.c.c3.c.2c3.2c3.3c4.c5.c,37.c3.c5.c3.c5.2c2.c2.2c.2c2.c.2c3.2c5.c4.2c4.c,38c2.3c3.3c.c,38.c2.c5.c2.c,2c4.2c4.2c4.2c4.2c4.2c6.c.c.c3.c.2c,38.c.c.c3.c.c,39.c2.c2.3c,42.c3.c,43.3c"

 for y=1,#r do                  -- this loop decodes the RLE:
  ww[y]={}                      -- add a new row to ww.
  d=r[y]                        -- store this row string in d.
  m=""
  for x=1,#d do                 -- process each character in d.
   v=d[x]
   if tonum(v) then             -- concat numbers together.
    m..=v
   else
    p=tonum(m) or 1             -- parse numbers, defaults to 1.
    for n=1,p do                -- lookup value v in tf (defaults to insulator 3)
     add(ww[y],tf[v] or 3)      -- then add it p-times to the world.
    end
    m=""
   end
  end
 end
 tm=1                           -- set a timer.
 fx=1                           -- set state (1: wait for button press)
 st=""                          -- clear status text.
end

function _update()              -- update loop.
 tm-=1/2                        -- reduce timer.
 if fx==0 and tm<0 then         -- test if in running state.
  print"\ac1g"                  -- bip-bip-bip.
  tm=btn()>0 and 0 or 1         -- speed up simulation by holding button.
  ti+=1                         -- step CA generation.
  cp={}                         -- storage for next generation.
  for y=1,h do                  -- evolve each cell in wire world:
   cp[y]={}                     -- * new row.
   for x=1,w do                 -- * next column.
    cp[y][x]=tnb(x,y,ww[y][x])  -- * transform and store new cell value via tnb call.
   end                          -- I don't recall what tnb means.
  end                           -- let's go with tasty new bananas. that works.
  ww=cp                         -- persist the new generation.
  if ti==66 then                -- the calculation is complete, show the answer.
     fx=1                       -- 66 is the number of generations to solve the problem.
     ans="="..a+b
  end
 elseif btnp()>0 then           -- button pressed.
  if fx==1 then                 -- in waiting state.
   ans=nil                      -- reset calculation state.
   ti=0                         -- ...
   fx=2                         -- ...
   a=flr(rnd(63))               -- pick random number "a".
   b=nil                        -- empty "b".
   bits(a,3)                    -- set a-bits.
   st="rolling dice"
  elseif fx==2 then
   fx=3                         -- ...
   b=flr(rnd(63))               -- pick random number "b".
   bits(b,9)                    -- set b-bits.
  elseif fx==3 then             -- end of calculation state.
   st=""                        -- ... 
   fx=0                         -- ...
  end
 end
end

function _draw()                -- render loop.
 cls(3)                         -- ...
 print("\^pwireworld",1,1,10)
 print("binary adder",74,5,11)
 print("\^ipico-1k jam 2022",30,14,15)
 print(st,4,122,7)
 for y=1,h do                   -- plot the current state of wire world cells.
  for x=1,w do
   pset(x+13,y+60,ww[y][x] or 3)
  end
 end
 print(a or "",5,59,14)         -- not much else to see here,
 if(a)print("+",2,64,14)        -- unless you love reading
 print(b or "",5,69,14)         -- "print" and "or".
 print(ans or "",112,61,11)
 if fx==0 and flr(time())%2==0 then print("working",4,122,10)end
end

function tnb(x,y,o,c)           -- function: evolves a wireworld cell.
                                -- this is the crux of wireworld, the
                                -- brevity of this function is exemplary
                                -- to the simplicity of this CA.
                                -- the rest of the code is only
                                -- data-and-state management.
                                -- the arguments are:
                                -- * x,y: cell coordinate.
                                -- * o: current value.
                                -- * c: not passe1 (variable optimization).

 if o==12 then return 7         -- head turns to tail.
 elseif o==7 then return 9      -- tail turns to copper.
 elseif o~=9 then return o end  -- non-copper (insulator) stays as-is.

 c=0                            -- this code is only reached for copper (9):
 for a=-1,1 do                  -- it counts the number of
     for b=-1,1 do              -- electron heads in the moore-neighborhood region
      if ww[y+a] and ww[y+a][x+b]==12 then
       c+=1
      end
  end
 end

 return c>0 and c<3 and 12 or o -- turn into electron head if
end                             -- the cell has 1 or 2 neighbors,
                                -- otherwise it stays as-is.

Here is the Golly version saved as RLE:

#CXRLE Pos=-50,-7
x = 97, y = 15, rule = WireWorld:P100,15
2C4.2C4.2C4.2C4.2C4.2C15.6C$46.C6.C5.2C4.2C4.2C4.2C4.2C4.2C4.2C$37C5.
4C2.2C2.4C$37.C3.C5.C2.B.C2.42C$4C2.C.C4.2C3.C.C3.2C5.C4.4C.C3.C.2CA
2.4C$.C.C2.C.2C3.2C3.3C4.C5.C4.C2.2C.5C6.C3.C.C.C2.4C3.C.C4.2C3.C.C3.
2C5.C$2C.2C.C.2C3.2C5.C4.2C4.C4.4C.C3.C.C4.C4.5C3.C.C3.C.2C3.2C3.3C4.
C5.C$37.C3.C5.C3.C5.2C2.C2.2C.2C2.C.2C3.2C5.C4.2C4.C$38C2.3C3.3C.C$
38.C2.C5.C2.C$2C4.2C4.2C4.2C4.2C4.2C6.C.C.C3.C.2C$38.C.C.C3.C.C$39.C
2.C2.3C$42.C3.C$43.3C!

References


Journal

Date Title
11 Mar 2023 source code