

Inspired by A New Kind of Science by Stephen Wolfram, et al., I’ve been meaning to put at least one of its famous cellular automata rules in allrgb. I never got around to it, so I asked Chatgpt, which seemed happy to do it for me. It even picked a very nice rule!
Python code that can be adjusted and run:
import numpy as np from PIL import Image # --- CONFIGURATION --- IMAGE_SIZE = 4096 TOTAL_COLORS = IMAGE_SIZE * IMAGE_SIZE RULE = 101 # Wolfram's CA Rule SEED_ROW_CENTER = 1 # --- STEP 1: Generate All 24-bit RGB Colors --- def generate_rgb_colors(): colors = np.arange(TOTAL_COLORS, dtype=np.uint32) r = (colors >> 16) & 0xFF g = (colors >> 8) & 0xFF b = colors & 0xFF return np.stack([r, g, b], axis=1).astype(np.uint8) # --- STEP 2: Generate CA Binary Mask (0 or 1 for each pixel) --- def generate_ca_binary_mask(rule, size): rule_bin = np.array([int(b) for b in np.binary_repr(rule, width=8)], dtype=np.uint8) ca = np.zeros((size, size), dtype=np.uint8) ca[0, size // 2] = SEED_ROW_CENTER for y in range(1, size): left = np.roll(ca[y - 1], 1) center = ca[y - 1] right = np.roll(ca[y - 1], -1) pattern = (left << 2) | (center << 1) | right ca[y] = rule_bin[7 - pattern] return ca # --- STEP 3: Measure Number of 0s and 1s in CA --- def count_dark_light_pixels(ca_mask): num_light = np.count_nonzero(ca_mask) # CA=1 num_dark = TOTAL_COLORS - num_light # CA=0 return num_dark, num_light # --- STEP 4: Split Colors by Luminance, Then Shuffle --- def split_and_shuffle_colors(colors, num_dark, num_light): def luminance(c): r, g, b = c / 255.0 return 0.2126 * r + 0.7152 * g + 0.0722 * b lums = np.array([luminance(c) for c in colors]) sorted_indices = np.argsort(lums) # Take the lowest luminance for dark, highest for light dark_indices = sorted_indices[:num_dark] light_indices = sorted_indices[num_dark:] dark_colors = colors[dark_indices] light_colors = colors[light_indices] rng = np.random.default_rng(42) rng.shuffle(dark_colors) rng.shuffle(light_colors) return dark_colors, light_colors # --- STEP 5: Assign Colors to Pixels Based on CA Mask --- def assign_colors_by_ca(ca_mask, dark_colors, light_colors): output = np.zeros((IMAGE_SIZE, IMAGE_SIZE, 3), dtype=np.uint8) dark_idx = 0 light_idx = 0 for y in range(IMAGE_SIZE): for x in range(IMAGE_SIZE): if ca_mask[y, x] == 0: output[y, x] = dark_colors[dark_idx] dark_idx += 1 else: output[y, x] = light_colors[light_idx] light_idx += 1 return output # --- MAIN EXECUTION --- if __name__ == "__main__": print("Generating RGB colors...") all_colors = generate_rgb_colors() print("Generating cellular automaton (Rule {})...".format(RULE)) ca_mask = generate_ca_binary_mask(RULE, IMAGE_SIZE) print("Counting dark/light CA pixels...") num_dark, num_light = count_dark_light_pixels(ca_mask) print("Splitting and shuffling colors...") dark_colors, light_colors = split_and_shuffle_colors(all_colors, num_dark, num_light) print("Assigning colors to image...") image = assign_colors_by_ca(ca_mask, dark_colors, light_colors) print("Saving image...") Image.fromarray(image, mode='RGB').save("rgb_ca_shuffled_by_luminance_split.png") print("Done! Saved as 'rgb_ca_shuffled_by_luminance_split.png'"
Date | |
---|---|
Colors | 16,777,216 |
Pixels | 16,777,216 |
Dimensions | 4,096 × 4,096 |
Bytes | 50,361,688 |