GNU/Linux
•
xterm-256color
•
zsh
138 views
import sys
import random
import time
import string
class AsciiCanvas:
width: int
height: int
fill_char: str
canvas: list[list[str]]
def __init__(self, width, height, fill_char=' '):
self.width = width
self.height = height
self.fill_char = fill_char
self.canvas = [
[fill_char for _ in range(width)] for _ in range(height)]
def set_pixel(self, x, y, char):
if 0 <= x < self.width and 0 <= y < self.height:
self.canvas[int(y)][int(x)] = char
def __str__(self):
return '\n'.join([''.join(row) for row in self.canvas])
def clear(self):
sys.stdout.write("\033[2J") # Clear the screen
def move_cursor_to_origin(self):
sys.stdout.write("\033[H") # Move cursor to the top-left corner
sys.stdout.flush()
def update(self):
self.move_cursor_to_origin()
sys.stdout.write(str(self))
sys.stdout.flush()
class RDModel:
dA: float
dB: float
f: float
k: float
def __init__(self, dA=1.0, dB=0.5, f=0.055, k=0.062):
self.dA = dA
self.dB = dB
self.f = f
self.k = k
class ReactionDiffusion:
width: int
height: int
model: RDModel
grid: list[list[dict[str, float]]]
dt: float
def __init__(self, width, height, model, dt=1.0):
self.width = width
self.height = height
self.model = model
self.grid = [[{'a': 1, 'b': random.random() * 0.1} for _ in range(width)] for _ in range(height)]
self.dt = dt
def laplace(self, x, y, chem):
val = -self.grid[y][x][chem]
for j in range(-1, 2):
for i in range(-1, 2):
if 0 <= x + i < self.width and 0 <= y + j < self.height:
val += self.grid[y + j][x + i][chem] * (0.2 if i == 0 or j == 0 else 0.05)
return val
def step(self):
new_grid = [[{'a': 0., 'b': 0.} for _ in range(self.width)] for _ in range(self.height)]
for y in range(self.height):
for x in range(self.width):
a = self.grid[y][x]['a']
b = self.grid[y][x]['b']
ab2 = a * b * b
new_a = a + self.dt * (self.model.dA * self.laplace(x, y, 'a') - ab2 + self.model.f * (1 - a))
new_b = b + self.dt * (self.model.dB * self.laplace(x, y, 'b') + ab2 - (self.model.k + self.model.f) * b)
new_grid[y][x]['a'] = new_a
new_grid[y][x]['b'] = new_b
self.grid = new_grid
def render(self, canvas, ascii_chars):
for y in range(self.height):
for x in range(self.width):
b = self.grid[y][x]['b']
index = int(b * (len(ascii_chars) - 1)) % len(ascii_chars)
canvas.set_pixel(x, y, ascii_chars[index])
def main():
width, height = 80, 40
canvas = AsciiCanvas(width, height)
m = RDModel(dA=1.0, dB=0.5, f=0.055, k=0.062)
rd = ReactionDiffusion(width, height, m, dt=0.05)
ascii_chars = string.ascii_letters + string.digits + string.punctuation + ' '
ascii_chars = sorted(set(ascii_chars))
canvas.clear()
while True:
rd.step()
rd.render(canvas, ascii_chars)
canvas.update()
time.sleep(1/144)
if __name__ == "__main__":
main()