Skip to content

Instantly share code, notes, and snippets.

@samclane
Created April 4, 2023 20:31
Show Gist options
  • Save samclane/476011e6423110c8f61668f5d74e75bd to your computer and use it in GitHub Desktop.
Save samclane/476011e6423110c8f61668f5d74e75bd to your computer and use it in GitHub Desktop.
Another codon experiment. Made with help from GPT-4
import math
import time
import sys
import random
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 draw_line(self, x1, y1, x2, y2, char='*'):
# Bresenham's line algorithm
dx = abs(x2 - x1)
dy = abs(y2 - y1)
x, y = x1, y1
sx = -1 if x1 > x2 else 1
sy = -1 if y1 > y2 else 1
if dx > dy:
err = dx / 2.0
while x != x2:
self.set_pixel(x, y, char)
err -= dy
if err < 0:
y += sy
err += dx
x += sx
else:
err = dy / 2.0
while y != y2:
self.set_pixel(x, y, char)
err -= dx
if err < 0:
x += sx
err += dy
y += sy
self.set_pixel(x, y, char)
def draw_rect(self, x, y, width, height, char='*'):
for i in range(height):
for j in range(width):
if i == 0 or i == height - 1 or j == 0 or j == width - 1:
self.set_pixel(x + j, y + i, char)
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):
self.canvas = [[self.fill_char for _ in range(
self.width)] for _ in range(self.height)]
def update(self):
sys.stdout.write('\r' + str(self) + '\n')
sys.stdout.flush()
class Particle:
x: float
y: float
charge: float
mass: float
vx: float
vy: float
def __init__(self, x, y, charge, mass=1e-9):
self.x = x
self.y = y
self.charge = charge
self.mass = mass
self.vx = 0
self.vy = 0
def calculate_electric_force(particles, target):
k = 8.99e9 # Coulomb's constant, in N*m^2/C^2
fx, fy = 0., 0.
for p in particles:
if p is target:
continue
dx = p.x - target.x
dy = p.y - target.y
r_squared = dx**2 + dy**2
r = math.sqrt(r_squared)
if r_squared == 0:
continue
f = k * (p.charge - target.charge) / r_squared
fx += f * dx / r
fy += f * dy / r
return fx, fy
def calculate_electric_field(particles, x, y, distance_offset=0.5):
k = 8.99e9 # Coulomb's constant, in N*m^2/C^2
Ex, Ey = 0., 0.
for p in particles:
dx = p.x - x
dy = p.y - y
r_squared = (dx**2 + dy**2) + distance_offset**2
r = math.sqrt(r_squared)
if r_squared == 0:
continue
E = k * p.charge / r_squared
Ex += E * dx / r
Ey += E * dy / r
return Ex, Ey
def field_strength_character(E):
if E > 1e3:
return '█'
elif E > 9e2:
return '▓'
elif E > 8e2:
return '▒'
elif E > 7e2:
return '░'
elif E > 6e2:
return '#'
elif E > 5e2:
return '&'
elif E > 4e2:
return '@'
elif E > 3e2:
return '!'
elif E > 2e2:
return '%'
elif E > 1e2:
return '*'
elif E > 8e1:
return '+'
elif E > 5e1:
return '-'
elif E > 1e1:
return '.'
else:
return ' '
def update_positions(canvas, particles, dt):
for p in particles:
fx, fy = calculate_electric_force(particles, p)
ax, ay = fx / p.mass, fy / p.mass
p.vx += ax * dt
p.vy += ay * dt
p.x += p.vx * dt
p.y += p.vy * dt
if p.x < 0:
p.x = 0
p.vx = -p.vx
elif p.x >= canvas.width:
p.x = canvas.width - 1
p.vx = -p.vx
if p.y < 0:
p.y = 0
p.vy = -p.vy
elif p.y >= canvas.height:
p.y = canvas.height - 1
p.vy = -p.vy
def main():
canvas = AsciiCanvas(60, 20)
num_particles = 10
particles = [Particle(random.randint(0, canvas.width - 1),
random.randint(0, canvas.height - 1),
random.choice([-1e-9, 1e-9]))
for _ in range(num_particles)]
dt = 0.0000001
while True:
canvas.clear()
for y in range(canvas.height):
for x in range(canvas.width):
Ex, Ey = calculate_electric_field(particles, x, y)
E = math.sqrt(Ex**2 + Ey**2)
canvas.set_pixel(x, y, field_strength_character(E))
for p in particles:
canvas.set_pixel(int(p.x), int(p.y), '+' if p.charge > 0 else '-')
update_positions(canvas, particles, dt)
canvas.update()
time.sleep(1 / 144)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment