Thumbnail.

The Ruliad

Description

This image was inspired by the concept of the ruliad from The Wolfram Physics Project. Created with Chatgpt and Google Colab.

import numpy as np
from PIL import Image, ImageDraw, ImageFont
import networkx as nx
from itertools import product
import random

# --- Enhanced: Generate a 4096×4096 image using every 24-bit RGB color once,
#     with bold labels, a shuffled gray-looking background, and 75% transparent bg.

# --- 1. Build the graph ----------------------------------------

alphabet     = ['A', 'B']
two_letter   = [''.join(p) for p in product(alphabet, repeat=2)]
four_letter  = [''.join(p) for p in product(alphabet, repeat=4)]

G = nx.DiGraph()
G.add_nodes_from(four_letter)
for state in four_letter:
    for i in range(3):
        for tgt in two_letter:
            new_state = state[:i] + tgt + state[i+2:]
            G.add_edge(state, new_state)

from networkx.algorithms.dag import transitive_closure
TC = transitive_closure(G)

# --- 2. Layout -------------------------------------------------

W = H = 4096
pos = nx.circular_layout(TC, scale=min(W, H) * 0.4, center=(W/2, H/2))

# --- 3. Render shapes & text to masks -------------------------

mask_shape = Image.new('1', (W, H), 0)
draw_shape = ImageDraw.Draw(mask_shape)

mask_label = Image.new('1', (W, H), 0)
draw_label = ImageDraw.Draw(mask_label)

# edges
for u, v in TC.edges():
    x1, y1 = pos[u]
    x2, y2 = pos[v]
    draw_shape.line([(x1, y1), (x2, y2)], fill=1)

# nodes
r = 3
for _, (x, y) in pos.items():
    draw_shape.ellipse([x-r, y-r, x+r, y+r], fill=1)

# labels with DejaVuSansBold size 48
try:
    font = ImageFont.truetype("DejaVuSans-Bold.ttf", size=48)
except IOError:
    font = ImageFont.load_default()

for node, (x, y) in pos.items():
    txt = node
    tx, ty = x + r + 5, y - 24
    draw_label.text((tx, ty), txt, font=font, fill=1)

shape_mask = np.array(mask_shape, dtype=bool)
label_mask = np.array(mask_label, dtype=bool)
shape_only  = shape_mask & ~label_mask
bg_mask     = ~(shape_mask | label_mask)

N = W * H
shape_idx = np.flatnonzero(shape_only.ravel())
label_idx = np.flatnonzero(label_mask.ravel())
bg_idx    = np.flatnonzero(bg_mask.ravel())
assert len(shape_idx) + len(label_idx) + len(bg_idx) == N

# --- 4. Prepare color pools --------------------------

all_colors = np.arange(N, dtype=np.uint32)
r_ch = (all_colors >> 16) & 0xFF
g_ch = (all_colors >> 8)  & 0xFF
b_ch =  all_colors        & 0xFF

lum = 0.2126*r_ch + 0.7152*g_ch + 0.0722*b_ch
sorted_idx = np.argsort(lum)

n_shape = len(shape_idx)
n_label = len(label_idx)
# brightest for shapes
bright_pool = sorted_idx[-n_shape:]
# darkest for labels + background
dark_pool   = sorted_idx[: n_label + (N - n_shape - n_label)]
label_colors = dark_pool[:n_label]
bg_colors    = dark_pool[n_label:]

# shuffle background pool for uniform gray appearance
random.shuffle(bg_colors)

# --- 5. Assemble RGBA image ----------------------------

img_arr = np.zeros((H*W, 4), dtype=np.uint8)

def unpack(c):
    return ((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF)

# labels: darkest, fully opaque
for i, pix in enumerate(label_idx):
    r_, g_, b_ = unpack(label_colors[i])
    img_arr[pix] = (r_, g_, b_, 255)

# background: next darkest, 75% opacity
alpha_bg = int(0.75 * 255)
for i, pix in enumerate(bg_idx):
    r_, g_, b_ = unpack(bg_colors[i])
    img_arr[pix] = (r_, g_, b_, alpha_bg)

# shapes: brightest, fully opaque
for i, pix in enumerate(shape_idx):
    r_, g_, b_ = unpack(bright_pool[i])
    img_arr[pix] = (r_, g_, b_, 255)

# reshape & save
img_arr = img_arr.reshape((H, W, 4))
img = Image.fromarray(img_arr, 'RGBA')
img.save('reachability_color_graph_4096_v2.png')
print("Saved RGBA 4096×4096 image with every 24-bit RGB color once, bg at 75% opacity.")

Author

ACJ
53 entries

Stats

Date
Colors16,777,216
Pixels16,777,216
Dimensions4,096 × 4,096
Bytes57,482,769