Agh, I have to stop playing around now

// --------------------------------- //
// Project: Totalistic Cellular Automaton
// Start: Tuesday, May 07, 2019
// IDE Version: 15.004
//
// Simple rules paints a picture. Use arrows to change rules and starting data.
// Idea:
// http://mathworld.wolfram.com/CellularAutomaton.html
GLOBAL color_states% = 3
GLOBAL x_max% = 320
GLOBAL y_max% = 220
GLOBAL zoom = 2
GLOBAL x%,y%
GLOBAL seed% = 380 // The top rule number
GLOBAL rule_number%=1 // decimal representation of rule
GLOBAL rule%[]
DIMDATA rule[],1,0,0,1,2,1,0 // rule converted to array
GLOBAL line_pos%[] // Positions where to change rules
GLOBAL line_dir%[] // Moving direction
GLOBAL line_rule%[] // Rule number to run at this line (index into nice_rule[])
GLOBAL nice_rules%[] // Selection of interesting rules
GLOBAL image_data%[]
DIM image_data%[x_max * y_max]
GLOBAL data_grid%[]
DIM data_grid[x_max][y_max]
GLOBAL palette%[]
DIMDATA palette[], 0xFF000000, 0xFF70D0EC, 0xFF435BD9, 0xFF4229C0, 0xFF372454, 0xFF7A7753, 0xFF78D0EC, 0xFF435BD9, 0xFF4229C0
GLOBAL mx, my, b1, b2
SETSCREEN 640, 480, 0
SMOOTHSHADING FALSE // Blocky zoom!
init_lines()
GLOBAL intro = 1
WHILE TRUE
KeyHitUpdate()
buttons()
init_screen()
recreate()
overlay()
SHOWSCREEN
move_lines()
WEND
KEYWAIT
END
FUNCTION buttons:
MOUSESTATE mx, my, b1, b2
LOCAL step_size = 1
IF KeyHit(42)>0 OR KeyHit(54)>0
step_size=10
ELSE
step_size=1
ENDIF
IF KeyHit(57)=2 // Space
DEBUG seed + ","
ENDIF
IF KeyHit(200)>0 THEN seed=seed+step_size
IF KeyHit(208)>0 THEN seed=seed-step_size
IF KeyHit(203)=2 THEN seed=seed-step_size
IF KeyHit(205)=2 THEN seed=seed+step_size
IF KeyHit(78)=2
INC line_rule[0], 1
IF line_rule[0] > LEN(nice_rules[])-1 THEN line_rule[0] = LEN(nice_rules[])-1
ENDIF
IF KeyHit(74)=2
DEC line_rule[0], 1
IF line_rule[0] < 0 THEN line_rule[0] = 0
ENDIF
ENDFUNCTION
FUNCTION recreate:
FOR y = 1 TO y_max-1
IF y = 1 THEN make_rule(seed)
FOR i = 0 TO LEN(line_pos[])-1
IF y = line_pos[i]
make_rule(nice_rules[line_rule[i]])
ENDIF
NEXT
FOR x = 1 TO x_max-2
set(x,y,decide_sum(x,y))
NEXT
NEXT
// Convert data to sprite:
MEM2SPRITE(image_data%[], 1, x_max, y_max)
//DRAWSPRITE 1, 0, 30
STRETCHSPRITE 1, 0, 30, x_max*zoom, y_max*zoom
ENDFUNCTION
FUNCTION move_lines:
IF intro = 1
//380, 38
FOR i = 0 TO LEN(line_pos[])-1
IF line_pos[i] >= y_max-1 OR line_pos[i] <= 1
line_dir[i] = -line_dir[i]
INC line_rule[i], 1
IF line_rule[i] > LEN(nice_rules[])-1 THEN line_rule[i] = 0
ENDIF
INC line_pos[i], line_dir[i]
NEXT
IF KeyHit(57) THEN intro = 0
ELSE
line_pos[0] = my
ENDIF
ENDFUNCTION
FUNCTION init_lines:
DIMDATA line_pos[], 3 // y_max/4 //, y_max/4*3
DIMDATA line_dir[], 1, -1
DIMDATA nice_rules[], 38, 3,10,12,21,24,28,30,31,34,38,43,46,48,49,52,57,65,66,75,83,84,86,92,93,95,96,97,100,102,105,106,109,110,111,113,114,115,128,129,136,137,138,140,141,145,146,147,150,164,170,172,173,177,183,186,194,205,210,219,220,221,224,237,302,308,357,384,422,439,443,497,600,646,804,807,843,844,845,858,867,870,885,888,893,924,925,947
DIMDATA line_rule[], 1, LEN(nice_rules[])/3
ENDFUNCTION
FUNCTION init_screen:
FOR x = 0 TO x_max-1
set (x, 0, 0)
NEXT
set(x_max/2, 0, 1)
ENDFUNCTION
// Foreground layer / instructions
FUNCTION overlay:
IF intro = 1
PRINT "Press SPACE", 50, 10
ELSE
LOCAL str$
PRINT "Change rule with arrowkeys, hold shift for faster change.", 0, 0
PRINT "Mouse Y move up and down, + and - on numpad changes rule.", 0, 10
PRINT "Rules: " + seed + " and " + nice_rules[line_rule[0]], 0, 20
str$=""
FOREACH a IN rule[]
str$ = str$ + a
NEXT
PRINT str$, 0, 30
ENDIF
ENDFUNCTION
FUNCTION decide_sum: x, y
LOCAL sum = 0
LOCAL result = 0
y = y - 1
FOR x1 = x-1 TO x+1
sum = sum + get(x1,y)
NEXT
IF sum >= 0 AND sum < BOUNDS(rule[], 0)
result = rule[sum]
ENDIF
RETURN result
ENDFUNCTION
FUNCTION get: x, y
IF x >= 0 AND x < x_max AND y >= 0 AND y < y_max
RETURN data_grid[x][y]
ELSE
RETURN 0
ENDIF
ENDFUNCTION
FUNCTION set: x, y, color
image_data%[x + y*x_max] = palette[color]
data_grid%[x][y] = color
ENDFUNCTION
FUNCTION make_rule: n%
rule_number% = n%
//rule = dec_to_base(n, color_states)
dec_to_base(n, color_states)
ENDFUNCTION
// ------------------------------------------------------------- //
// --- dec_to_base ---
// ------------------------------------------------------------- //
// Convert decimal to any base system
// Returns array with LSB first
//
FUNCTION dec_to_base: num%, base%
LOCAL a%[]
DIM a%[0]
WHILE (num>0)
DIMPUSH a[], MOD(num, base)
num = INTEGER(num / base)
WEND
rule = a
//RETURN a
ENDFUNCTION
// ------------------------------------------------------------- //
// --- KeyHitUpdate ---
// ------------------------------------------------------------- //
//
// Update keyboard state, call every screen refresh
//
GLOBAL gKeyDown[], gKeyState[]
FUNCTION KeyHitUpdate:
LOCAL k, i
// First Time call, init
IF BOUNDS(gKeyDown[],0)=0
DIM gKeyDown[256]
DIM gKeyState[256]
ENDIF
// For each key
FOR i=0 TO 255
k = KEY(i)
// Key is pressed
IF k
IF gKeyDown[i]
gKeyState[i]=1
ELSE
gKeyDown[i]=1
gKeyState[i]=2
ENDIF
ELSE
// Key is not pressed
// Has key been pressed before?
IF gKeyDown[i]
gKeyDown[i] = 0
gKeyState[i] = -1
ELSE
gKeyState[i]=0
ENDIF
ENDIF
NEXT
ENDFUNCTION
// ------------------------------------------------------------- //
// --- KeyHit ---
// ------------------------------------------------------------- //
// Returns:
// 0 = not pressed
// 2 = just pressed (only triggers on keydown)
// 1 = pressed
// -1 = release event (only triggers on keyup)
//
// nkey = key scancode to check
FUNCTION KeyHit: nkey
RETURN gKeyState[nkey]
ENDFUNCTION
Fun competition :-)