Skip to content

Instantly share code, notes, and snippets.

@cyberpunk042
Last active December 21, 2024 12:43
Show Gist options
  • Save cyberpunk042/dba9c06d374262a461310d1faf30f492 to your computer and use it in GitHub Desktop.
Save cyberpunk042/dba9c06d374262a461310d1faf30f492 to your computer and use it in GitHub Desktop.
Axiom Orbits is a creative sandbox game where you build and navigate layered orbit-like structures around a single central “O.” Using two perpendicular “axioms,” you populate each layer’s outer ring of cells with characters, creating intricate patterns. You can then visualize your evolving atomic-like model in 3D, experimenting with various fill…
import curses
import logging
import math
import plotly.graph_objects as go
import sys
import random
logging.basicConfig(
filename="layer_axiom_game.log",
filemode="w",
format="%(asctime)s [%(levelname)s] %(message)s",
level=logging.DEBUG
)
logger = logging.getLogger(__name__)
DEFAULT_CHAR = "◦"
CENTER_CHAR = "O"
data = {}
current_layer = 0
current_axiom = 'A'
cursor_x, cursor_y = 0, 0
def layer_dimension(layer):
return 2*layer + 1
def create_layer_axiom(layer, axiom):
dim = layer_dimension(layer)
grid = [[DEFAULT_CHAR for _ in range(dim)] for _ in range(dim)]
read_only = [[False for _ in range(dim)] for _ in range(dim)]
if layer == 0:
grid[0][0] = CENTER_CHAR
read_only[0][0] = False
else:
ensure_layer_axiom(layer-1, axiom)
prev_grid, prev_read_only = data[(layer-1, axiom)]
prev_dim = layer_dimension(layer-1)
offset = (dim - prev_dim) // 2
for py in range(prev_dim):
for px in range(prev_dim):
ch = prev_grid[py][px]
if ch == CENTER_CHAR:
ch = ' '
grid[py+offset][px+offset] = ch
read_only[py+offset][px+offset] = True
data[(layer, axiom)] = (grid, read_only)
def ensure_layer_axiom(layer, axiom):
if (layer, axiom) not in data:
create_layer_axiom(layer, axiom)
def is_within_bounds(x, y):
return (-current_layer <= x <= current_layer and -current_layer <= y <= current_layer)
def is_read_only(x, y):
grid, ro = data[(current_layer, current_axiom)]
center = current_layer
gx = x + center
gy = y + center
return ro[gy][gx]
def jump_across(dx, dy):
global cursor_x, cursor_y
x, y = cursor_x, cursor_y
while True:
nx, ny = x + dx, y + dy
if not is_within_bounds(nx, ny):
return False
if not is_read_only(nx, ny):
cursor_x, cursor_y = nx, ny
return True
x, y = nx, ny
def move_cursor(dx, dy):
if jump_across(dx, dy):
return
def insert_char(ch):
grid, read_only = data[(current_layer, current_axiom)]
center = current_layer
gx = cursor_x + center
gy = cursor_y + center
if not read_only[gy][gx]:
grid[gy][gx] = ch
def go_to_layer_axiom(layer, axiom):
global current_layer, current_axiom, cursor_x, cursor_y
current_layer = layer
current_axiom = axiom
ensure_layer_axiom(current_layer, current_axiom)
cursor_x, cursor_y = -current_layer, -current_layer
def get_outer_ring_cells(layer, axiom):
grid, ro = data[(layer, axiom)]
dim = layer_dimension(layer)
center = layer
if layer == 0:
ch = grid[0][0]
return [(0,0,ch)]
ring = []
N = layer
for y in range(-N, N+1):
for x in range(-N, N+1):
if max(abs(x),abs(y)) == N:
gx = x+center
gy = y+center
ch = grid[gy][gx]
if ch == ' ':
continue
ring.append((x,y,ch))
return ring
def render_3d(filename="matrix_visualization.html"):
# A: (x,y,z) = (N*cosθ, N*sinθ, 0)
# B: (x,y,z) = (0, N*cosθ, N*sinθ)
# C: (x,y,z) = (N*cosθ, 0, N*sinθ)
# D: diagonal
# x = N*cosθ
# y = N*sinθ*(√2/2)
# z = N*sinθ*(√2/2)
x_data_A, y_data_A, z_data_A, text_data_A = [], [], [], []
x_data_B, y_data_B, z_data_B, text_data_B = [], [], [], []
x_data_C, y_data_C, z_data_C, text_data_C = [], [], [], []
x_data_D, y_data_D, z_data_D, text_data_D = [], [], [], []
max_layer = 0
for (layer, axiom) in data.keys():
if layer > max_layer:
max_layer = layer
for (layer, axiom) in data.keys():
ring_cells = get_outer_ring_cells(layer, axiom)
if len(ring_cells) == 0:
if layer == 0 and axiom == 'A':
# just center
x_data_A.append(0)
y_data_A.append(0)
z_data_A.append(0)
text_data_A.append('O')
continue
N = layer
count = len(ring_cells)
ring_cells.sort(key=lambda c: math.atan2(c[1], c[0]))
for i, (ox,oy,ch) in enumerate(ring_cells):
angle = 2*math.pi*i/count
if axiom == 'A':
x = N*math.cos(angle)
y = N*math.sin(angle)
z = 0
x_data_A.append(x)
y_data_A.append(y)
z_data_A.append(z)
text_data_A.append(ch)
elif axiom == 'B':
x = 0
y = N*math.cos(angle)
z = N*math.sin(angle)
x_data_B.append(x)
y_data_B.append(y)
z_data_B.append(z)
text_data_B.append(ch)
elif axiom == 'C':
x = N*math.cos(angle)
z = N*math.sin(angle)
y = 0
x_data_C.append(x)
y_data_C.append(y)
z_data_C.append(z)
text_data_C.append(ch)
else: # D
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = N*cosθ
y = N*sinθ*(math.sqrt(2)/2)
z = N*sinθ*(math.sqrt(2)/2)
x_data_D.append(x)
y_data_D.append(y)
z_data_D.append(z)
text_data_D.append(ch)
fig = go.Figure()
fig.add_trace(go.Scatter3d(
x=x_data_A, y=y_data_A, z=z_data_A,
mode='text',
text=text_data_A,
textfont=dict(size=12, color='red'),
name='A (XY plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_B, y=y_data_B, z=z_data_B,
mode='text',
text=text_data_B,
textfont=dict(size=12, color='blue'),
name='B (YZ plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_C, y=y_data_C, z=z_data_C,
mode='text',
text=text_data_C,
textfont=dict(size=12, color='green'),
name='C (XZ plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_D, y=y_data_D, z=z_data_D,
mode='text',
text=text_data_D,
textfont=dict(size=12, color='purple'),
name='D (Diagonal plane)'
))
fig.update_layout(
scene=dict(
xaxis=dict(title="X", range=[-max_layer, max_layer]),
yaxis=dict(title="Y", range=[-max_layer, max_layer]),
zaxis=dict(title="Z", range=[-max_layer, max_layer]),
camera=dict(
center=dict(x=0, y=0, z=0),
eye=dict(x=1.25, y=1.25, z=1.25)
)
),
title="3D Visualization (Manual Refresh)",
width=1000, height=800
)
fig.write_html(filename)
def draw_interface(stdscr):
stdscr.clear()
stdscr.addstr(0,0,f"Layer: {current_layer}, Axiom: {current_axiom}, Pos=({cursor_x},{cursor_y})")
stdscr.addstr(1,0,"F1=A(XY), F2=B(YZ), F3=C(XZ), F4=D(Diag) | +/-=layers | Arrows=move | Type=insert | Ctrl+D=exit")
stdscr.addstr(2,0,"Refresh matrix_visualization.html manually.")
stdscr.addstr(3,0,"A=XY plane, B=YZ plane, C=XZ plane, D=diagonal plane")
grid, read_only = data[(current_layer, current_axiom)]
dim = layer_dimension(current_layer)
center = current_layer
VIEW_RADIUS = 5
min_xv = max(cursor_x - VIEW_RADIUS, -current_layer)
max_xv = min(cursor_x + VIEW_RADIUS, current_layer)
min_yv = max(cursor_y - VIEW_RADIUS, -current_layer)
max_yv = min(cursor_y + VIEW_RADIUS, current_layer)
offset_line = 5
offset_col = 2
for draw_y in range(min_yv, max_yv+1):
row_chars = []
gy = draw_y + center
for draw_x in range(min_xv, max_xv+1):
gx = draw_x + center
ch = grid[gy][gx]
display_char = ' ' if read_only[gy][gx] else ch
if draw_x == cursor_x and draw_y == cursor_y:
if current_layer == 0 and current_axiom == 'A' and cursor_x == 0 and cursor_y == 0:
char = display_char
else:
char = "▮" if display_char != DEFAULT_CHAR else "○"
else:
char = display_char
row_chars.append(char)
stdscr.addstr(offset_line+(draw_y - min_yv), offset_col, "".join(row_chars))
stdscr.refresh()
def prefill_layers(mode, fillA, fillB, fillC, fillD):
# number of layers = max(len(fillA), len(fillB), len(fillC), len(fillD))
max_layers = max(len(fillA), len(fillB), len(fillC), len(fillD))
random.seed(0)
axioms = ['A','B','C','D']
fills = {'A': fillA, 'B': fillB, 'C': fillC, 'D': fillD}
for layer in range(1, max_layers+1):
for axiom in axioms:
ensure_layer_axiom(layer, axiom)
grid, ro = data[(layer, axiom)]
center = layer
N = layer
ring_coords = []
for y in range(-N, N+1):
for x in range(-N, N+1):
if max(abs(x),abs(y)) == N:
gx = x+center
gy = y+center
if not ro[gy][gx]:
ring_coords.append((gx, gy))
total = len(ring_coords)
if total == 0:
continue
chars_list = fills[axiom]
# Determine what char to use for full/partial, or how to pick random
if layer <= len(chars_list):
base_char = chars_list[layer-1] # single char for this layer
else:
base_char = None
if mode == 'full':
# Need a base_char to fill entire ring
if base_char is not None:
for (gx,gy) in ring_coords:
grid[gy][gx] = base_char
elif mode == 'partial':
# Fill half ring cells with base_char if available
if base_char is not None:
selected = random.sample(ring_coords, total//2)
for (gx,gy) in selected:
grid[gy][gx] = base_char
# else no fill if no base_char
elif mode == 'random':
# Partial logic: half ring cells chosen
# each chosen cell gets random char from chars_list
if len(chars_list) > 0:
selected = random.sample(ring_coords, total//2)
for (gx,gy) in selected:
ch = random.choice(chars_list)
grid[gy][gx] = ch
# if no chars_list empty, no fill
def run(stdscr):
global current_layer, current_axiom
curses.curs_set(0)
stdscr.nodelay(False)
stdscr.keypad(True)
go_to_layer_axiom(0, 'A')
while True:
render_3d()
draw_interface(stdscr)
key = stdscr.getch()
if key == -1:
continue
if key == 4: # Ctrl+D
break
if key == curses.KEY_F1:
go_to_layer_axiom(current_layer, 'A')
elif key == curses.KEY_F2:
go_to_layer_axiom(current_layer, 'B')
elif key == curses.KEY_F3:
go_to_layer_axiom(current_layer, 'C')
elif key == curses.KEY_F4:
go_to_layer_axiom(current_layer, 'D')
elif key == ord('+'):
go_to_layer_axiom(current_layer+1, current_axiom)
elif key == ord('-'):
if current_layer > 0:
go_to_layer_axiom(current_layer-1, current_axiom)
elif key == curses.KEY_LEFT:
move_cursor(-1, 0)
elif key == curses.KEY_RIGHT:
move_cursor(1, 0)
elif key == curses.KEY_UP:
move_cursor(0, -1)
elif key == curses.KEY_DOWN:
move_cursor(0, 1)
elif 32 <= key < 127:
ch = chr(key)
insert_char(ch)
if __name__ == "__main__":
prefill = ('--prefill' in sys.argv)
fillA = ['X']
fillB = ['Y']
fillC = ['X']
fillD = ['Y']
mode = 'full'
for arg in sys.argv:
if arg.startswith('--fillA='):
fillA = arg.split('=')[1].split(',')
elif arg.startswith('--fillB='):
fillB = arg.split('=')[1].split(',')
elif arg.startswith('--fillC='):
fillC = arg.split('=')[1].split(',')
elif arg.startswith('--fillD='):
fillD = arg.split('=')[1].split(',')
elif arg.startswith('--mode='):
mode = arg.split('=')[1]
if prefill:
prefill_layers(mode, fillA, fillB, fillC, fillD)
try:
curses.wrapper(run)
except KeyboardInterrupt:
pass
print("Exited.")
import curses
import logging
import math
import plotly.graph_objects as go
import sys
import random
logging.basicConfig(
filename="layer_axiom_game.log",
filemode="w",
format="%(asctime)s [%(levelname)s] %(message)s",
level=logging.DEBUG
)
logger = logging.getLogger(__name__)
DEFAULT_CHAR = "◦"
CENTER_CHAR = "O"
data = {}
current_layer = 0
current_axiom = 'A'
cursor_x, cursor_y = 0, 0
def layer_dimension(layer):
return 2*layer + 1
def create_layer_axiom(layer, axiom):
dim = layer_dimension(layer)
grid = [[DEFAULT_CHAR for _ in range(dim)] for _ in range(dim)]
read_only = [[False for _ in range(dim)] for _ in range(dim)]
if layer == 0:
grid[0][0] = CENTER_CHAR
read_only[0][0] = False
else:
ensure_layer_axiom(layer-1, axiom)
prev_grid, prev_read_only = data[(layer-1, axiom)]
prev_dim = layer_dimension(layer-1)
offset = (dim - prev_dim) // 2
for py in range(prev_dim):
for px in range(prev_dim):
ch = prev_grid[py][px]
if ch == CENTER_CHAR:
ch = ' '
grid[py+offset][px+offset] = ch
read_only[py+offset][px+offset] = True
data[(layer, axiom)] = (grid, read_only)
def ensure_layer_axiom(layer, axiom):
if (layer, axiom) not in data:
create_layer_axiom(layer, axiom)
def is_within_bounds(x, y):
return (-current_layer <= x <= current_layer and -current_layer <= y <= current_layer)
def is_read_only(x, y):
grid, ro = data[(current_layer, current_axiom)]
center = current_layer
gx = x + center
gy = y + center
return ro[gy][gx]
def jump_across(dx, dy):
global cursor_x, cursor_y
x, y = cursor_x, cursor_y
while True:
nx, ny = x + dx, y + dy
if not is_within_bounds(nx, ny):
return False
if not is_read_only(nx, ny):
cursor_x, cursor_y = nx, ny
return True
x, y = nx, ny
def move_cursor(dx, dy):
if jump_across(dx, dy):
return
def insert_char(ch):
grid, read_only = data[(current_layer, current_axiom)]
center = current_layer
gx = cursor_x + center
gy = cursor_y + center
if not read_only[gy][gx]:
grid[gy][gx] = ch
def go_to_layer_axiom(layer, axiom):
global current_layer, current_axiom, cursor_x, cursor_y
current_layer = layer
current_axiom = axiom
ensure_layer_axiom(current_layer, current_axiom)
cursor_x, cursor_y = -current_layer, -current_layer
def get_outer_ring_cells(layer, axiom):
grid, ro = data[(layer, axiom)]
dim = layer_dimension(layer)
center = layer
if layer == 0:
ch = grid[0][0]
return [(0,0,ch)]
ring = []
N = layer
for y in range(-N, N+1):
for x in range(-N, N+1):
if max(abs(x),abs(y)) == N:
gx = x+center
gy = y+center
ch = grid[gy][gx]
if ch == ' ':
continue
ring.append((x,y,ch))
return ring
def render_3d(filename="matrix_visualization.html"):
# A: (x,y,z) = (N*cosθ, N*sinθ, 0)
# B: (x,y,z) = (0, N*cosθ, N*sinθ)
# C: (x,y,z) = (N*cosθ, 0, N*sinθ)
# D: diagonal
# x = N*cosθ
# y = N*sinθ*(√2/2)
# z = N*sinθ*(√2/2)
x_data_A, y_data_A, z_data_A, text_data_A = [], [], [], []
x_data_B, y_data_B, z_data_B, text_data_B = [], [], [], []
x_data_C, y_data_C, z_data_C, text_data_C = [], [], [], []
x_data_D, y_data_D, z_data_D, text_data_D = [], [], [], []
x_data_E, y_data_E, z_data_E, text_data_E = [], [], [], []
x_data_F, y_data_F, z_data_F, text_data_F = [], [], [], []
x_data_H, y_data_H, z_data_H, text_data_H = [], [], [], []
x_data_I, y_data_I, z_data_I, text_data_I = [], [], [], []
x_data_J, y_data_J, z_data_J, text_data_J = [], [], [], []
max_layer = 0
for (layer, axiom) in data.keys():
if layer > max_layer:
max_layer = layer
for (layer, axiom) in data.keys():
ring_cells = get_outer_ring_cells(layer, axiom)
if len(ring_cells) == 0:
if layer == 0 and axiom == 'A':
# just center
x_data_A.append(0)
y_data_A.append(0)
z_data_A.append(0)
text_data_A.append('O')
continue
N = layer
count = len(ring_cells)
ring_cells.sort(key=lambda c: math.atan2(c[1], c[0]))
for i, (ox,oy,ch) in enumerate(ring_cells):
angle = 2*math.pi*i/count
if axiom == 'A':
x = N*math.cos(angle)
y = N*math.sin(angle)
z = 0
x_data_A.append(x)
y_data_A.append(y)
z_data_A.append(z)
text_data_A.append(ch)
elif axiom == 'B':
x = 0
y = N*math.cos(angle)
z = N*math.sin(angle)
x_data_B.append(x)
y_data_B.append(y)
z_data_B.append(z)
text_data_B.append(ch)
elif axiom == 'C':
x = N*math.cos(angle)
z = N*math.sin(angle)
y = 0
x_data_C.append(x)
y_data_C.append(y)
z_data_C.append(z)
text_data_C.append(ch)
elif axiom == 'D':
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = N*cosθ
y = N*sinθ*(math.sqrt(2)/2)
z = N*sinθ*(math.sqrt(2)/2)
x_data_D.append(x)
y_data_D.append(y)
z_data_D.append(z)
text_data_D.append(ch)
elif axiom == 'E':
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = N*sinθ*(math.sqrt(2)/2)
y = N*cosθ
z = N*sinθ*(math.sqrt(2)/2)
x_data_E.append(x)
y_data_E.append(y)
z_data_E.append(z)
text_data_E.append(ch)
elif axiom == 'F':
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = N*sinθ*(math.sqrt(2)/2)
y = N*sinθ*(math.sqrt(2)/2)
z = N*cosθ
x_data_F.append(x)
y_data_F.append(y)
z_data_F.append(z)
text_data_F.append(ch)
elif axiom == 'H':
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = N*cosθ
y = N*sinθ*(math.sqrt(2)/2)
z = -N*sinθ*(math.sqrt(2)/2)
x_data_H.append(x)
y_data_H.append(y)
z_data_H.append(z)
text_data_H.append(ch)
elif axiom == 'I':
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = -N*sinθ*(math.sqrt(2)/2)
y = N*cosθ
z = N*sinθ*(math.sqrt(2)/2)
x_data_I.append(x)
y_data_I.append(y)
z_data_I.append(z)
text_data_I.append(ch)
else: # J
cosθ = math.cos(angle)
sinθ = math.sin(angle)
x = -N*sinθ*(math.sqrt(2)/2)
y = N*sinθ*(math.sqrt(2)/2)
z = N*cosθ
x_data_J.append(x)
y_data_J.append(y)
z_data_J.append(z)
text_data_J.append(ch)
fig = go.Figure()
fig.add_trace(go.Scatter3d(
x=x_data_A, y=y_data_A, z=z_data_A,
mode='text',
text=text_data_A,
textfont=dict(size=12, color='red'),
name='A (XY plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_B, y=y_data_B, z=z_data_B,
mode='text',
text=text_data_B,
textfont=dict(size=12, color='blue'),
name='B (YZ plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_C, y=y_data_C, z=z_data_C,
mode='text',
text=text_data_C,
textfont=dict(size=12, color='green'),
name='C (XZ plane)'
))
fig.add_trace(go.Scatter3d(
x=x_data_D, y=y_data_D, z=z_data_D,
mode='text',
text=text_data_D,
textfont=dict(size=12, color='purple'),
name='D (Diagonal plane Y1)'
))
fig.add_trace(go.Scatter3d(
x=x_data_E, y=y_data_E, z=z_data_E,
mode='text',
text=text_data_E,
textfont=dict(size=12, color='brown'),
name='E (Diagonal plane Y2)'
))
fig.add_trace(go.Scatter3d(
x=x_data_F, y=y_data_F, z=z_data_F,
mode='text',
text=text_data_F,
textfont=dict(size=12, color='black'),
name='F (Diagonal plane Y3)'
))
fig.add_trace(go.Scatter3d(
x=x_data_H, y=y_data_H, z=z_data_H,
mode='text',
text=text_data_H,
textfont=dict(size=12, color='purple'),
name='D (Diagonal plane -Y1)'
))
fig.add_trace(go.Scatter3d(
x=x_data_I, y=y_data_I, z=z_data_I,
mode='text',
text=text_data_I,
textfont=dict(size=12, color='brown'),
name='E (Diagonal plane -Y2)'
))
fig.add_trace(go.Scatter3d(
x=x_data_J, y=y_data_J, z=z_data_J,
mode='text',
text=text_data_J,
textfont=dict(size=12, color='black'),
name='F (Diagonal plane -Y3)'
))
fig.update_layout(
scene=dict(
xaxis=dict(title="X", range=[-max_layer, max_layer]),
yaxis=dict(title="Y", range=[-max_layer, max_layer]),
zaxis=dict(title="Z", range=[-max_layer, max_layer]),
camera=dict(
center=dict(x=0, y=0, z=0),
eye=dict(x=1.25, y=1.25, z=1.25)
)
),
title="3D Visualization (Manual Refresh)",
width=1000, height=800
)
fig.write_html(filename)
def draw_interface(stdscr):
stdscr.clear()
stdscr.addstr(0,0,f"Layer: {current_layer}, Axiom: {current_axiom}, Pos=({cursor_x},{cursor_y})")
stdscr.addstr(1,0,"F1=A(XY), F2=B(YZ), F3=C(XZ), F4=D(Diag) | +/-=layers | Arrows=move | Type=insert | Ctrl+D=exit")
stdscr.addstr(2,0,"Refresh matrix_visualization.html manually.")
stdscr.addstr(3,0,"A=XY plane, B=YZ plane, C=XZ plane, D=diagonal plane")
grid, read_only = data[(current_layer, current_axiom)]
dim = layer_dimension(current_layer)
center = current_layer
VIEW_RADIUS = 5
min_xv = max(cursor_x - VIEW_RADIUS, -current_layer)
max_xv = min(cursor_x + VIEW_RADIUS, current_layer)
min_yv = max(cursor_y - VIEW_RADIUS, -current_layer)
max_yv = min(cursor_y + VIEW_RADIUS, current_layer)
offset_line = 5
offset_col = 2
for draw_y in range(min_yv, max_yv+1):
row_chars = []
gy = draw_y + center
for draw_x in range(min_xv, max_xv+1):
gx = draw_x + center
ch = grid[gy][gx]
display_char = ' ' if read_only[gy][gx] else ch
if draw_x == cursor_x and draw_y == cursor_y:
if current_layer == 0 and current_axiom == 'A' and cursor_x == 0 and cursor_y == 0:
char = display_char
else:
char = "▮" if display_char != DEFAULT_CHAR else "○"
else:
char = display_char
row_chars.append(char)
stdscr.addstr(offset_line+(draw_y - min_yv), offset_col, "".join(row_chars))
stdscr.refresh()
def prefill_layers(mode, fillA, fillB, fillC, fillD, fillE, fillF, fillH, fillI, fillJ):
# number of layers = max(len(fillA), len(fillB), len(fillC), len(fillD))
max_layers = max(len(fillA), len(fillB), len(fillC), len(fillD), len(fillE), len(fillF), len(fillH), len(fillI), len(fillJ))
random.seed(0)
axioms = ['A','B','C','D','E','F','H','I','J']
fills = {'A': fillA, 'B': fillB, 'C': fillC, 'D': fillD, 'E': fillE, 'F': fillF, 'H': fillH, 'I': fillI, 'J': fillJ}
for layer in range(1, max_layers+1):
for axiom in axioms:
ensure_layer_axiom(layer, axiom)
grid, ro = data[(layer, axiom)]
center = layer
N = layer
ring_coords = []
for y in range(-N, N+1):
for x in range(-N, N+1):
if max(abs(x),abs(y)) == N:
gx = x+center
gy = y+center
if not ro[gy][gx]:
ring_coords.append((gx, gy))
total = len(ring_coords)
if total == 0:
continue
chars_list = fills[axiom]
# Determine what char to use for full/partial, or how to pick random
if layer <= len(chars_list):
base_char = chars_list[layer-1] # single char for this layer
else:
base_char = None
########################################
#TODO: replace default char by nothing
########################################
if mode == 'full':
# Need a base_char to fill entire ring
if base_char is not None:
for (gx,gy) in ring_coords:
grid[gy][gx] = base_char
elif mode == 'partial':
# Fill half ring cells with base_char if available
if base_char is not None:
#TODO: replace random select here
selected = random.sample(ring_coords, total//2)
for (gx,gy) in selected:
grid[gy][gx] = base_char
# else no fill if no base_char
elif mode == 'random':
# Partial logic: half ring cells chosen
# each chosen cell gets random char from chars_list
if len(chars_list) > 0:
selected = random.sample(ring_coords, total//2)
for (gx,gy) in selected:
ch = random.choice(chars_list)
grid[gy][gx] = ch
# if no chars_list empty, no fill
def run(stdscr):
global current_layer, current_axiom
curses.curs_set(0)
stdscr.nodelay(False)
stdscr.keypad(True)
go_to_layer_axiom(0, 'A')
while True:
render_3d()
draw_interface(stdscr)
key = stdscr.getch()
if key == -1:
continue
if key == 4: # Ctrl+D
break
if key == curses.KEY_F1:
go_to_layer_axiom(current_layer, 'A')
elif key == curses.KEY_F2:
go_to_layer_axiom(current_layer, 'B')
elif key == curses.KEY_F3:
go_to_layer_axiom(current_layer, 'C')
elif key == curses.KEY_F4:
go_to_layer_axiom(current_layer, 'D')
elif key == curses.KEY_F5:
go_to_layer_axiom(current_layer, 'E')
elif key == curses.KEY_F6:
go_to_layer_axiom(current_layer, 'F')
elif key == curses.KEY_F7:
go_to_layer_axiom(current_layer, 'H')
elif key == curses.KEY_F8:
go_to_layer_axiom(current_layer, 'I')
elif key == curses.KEY_F9:
go_to_layer_axiom(current_layer, 'J')
elif key == ord('+'):
go_to_layer_axiom(current_layer+1, current_axiom)
elif key == ord('-'):
if current_layer > 0:
go_to_layer_axiom(current_layer-1, current_axiom)
elif key == curses.KEY_LEFT:
move_cursor(-1, 0)
elif key == curses.KEY_RIGHT:
move_cursor(1, 0)
elif key == curses.KEY_UP:
move_cursor(0, -1)
elif key == curses.KEY_DOWN:
move_cursor(0, 1)
elif 32 <= key < 127:
ch = chr(key)
insert_char(ch)
if __name__ == "__main__":
prefill = ('--prefill' in sys.argv)
fillA = ['B']
fillB = ['B']
fillC = ['C']
fillD = ['D']
fillE = ['E']
fillF = ['F']
fillH = ['H']
fillI = ['I']
fillJ = ['J']
mode = 'full'
for arg in sys.argv:
if arg.startswith('--fillA='):
fillA = arg.split('=')[1].split(',')
elif arg.startswith('--fillB='):
fillB = arg.split('=')[1].split(',')
elif arg.startswith('--fillC='):
fillC = arg.split('=')[1].split(',')
elif arg.startswith('--fillD='):
fillD = arg.split('=')[1].split(',')
elif arg.startswith('--fillE='):
fillE = arg.split('=')[1].split(',')
elif arg.startswith('--fillF='):
fillF = arg.split('=')[1].split(',')
elif arg.startswith('--fillH='):
fillH = arg.split('=')[1].split(',')
elif arg.startswith('--fillI='):
fillI = arg.split('=')[1].split(',')
elif arg.startswith('--fillJ='):
fillJ = arg.split('=')[1].split(',')
elif arg.startswith('--mode='):
mode = arg.split('=')[1]
if prefill:
prefill_layers(mode, fillA, fillB, fillC, fillD, fillE, fillF, fillH, fillI, fillJ)
try:
curses.wrapper(run)
except KeyboardInterrupt:
pass
print("Exited.")
@cyberpunk042
Copy link
Author

big_atom3
big_atom4
big_atom5
big_atom6
big_atom7
atom4
atom3
atom2
atom1
big_atom1
big_atom2

@cyberpunk042
Copy link
Author

cyberpunk042 commented Dec 21, 2024

biggest_attom2
biggest_attom1

@cyberpunk042
Copy link
Author

biggest_attom4
biggest_attom5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment