Lev
3 years ago
3 changed files with 101 additions and 44 deletions
@ -0,0 +1,100 @@
|
||||
from __future__ import annotations |
||||
|
||||
import numpy as np |
||||
from dataclasses import dataclass, field |
||||
from random import uniform |
||||
import typing |
||||
import time |
||||
import turtle as t |
||||
|
||||
if typing.TYPE_CHECKING: |
||||
from nptyping import NDArray |
||||
|
||||
|
||||
HALF_WIDTH, HALF_HEIGHT = 200, 200 |
||||
INITIAL_VELOCITY_COEF = 1000 |
||||
FORCE_LAW = lambda r: 600000 / (r ** 2) |
||||
DT, N, VELOCITY_CUTOFF, ACCELERATION_CUTOFF = 0.01, 10, 1500, 10000 |
||||
|
||||
|
||||
@dataclass |
||||
class Particle: |
||||
coordinates: NDArray[(2,), float] = field(default_factory=lambda: np.array( |
||||
[uniform(-HALF_WIDTH, HALF_WIDTH), uniform(-HALF_HEIGHT, HALF_HEIGHT)] |
||||
)) |
||||
velocity: NDArray[(2,)] = field( |
||||
default_factory=lambda: INITIAL_VELOCITY_COEF * np.array([uniform(-1, 1), uniform(-1, 1)])) |
||||
|
||||
def adjust_velocity(self, other_particles: typing.List[Particle], dt: float = DT): |
||||
a = np.array([0., 0.]) |
||||
for particle in other_particles: |
||||
if list(particle.coordinates) == list(self.coordinates): |
||||
continue |
||||
r = self.coordinates - particle.coordinates |
||||
a += (-1) * r * FORCE_LAW(np.abs(r)) |
||||
if np.linalg.norm(a) > ACCELERATION_CUTOFF: |
||||
a *= ACCELERATION_CUTOFF / np.linalg.norm(a) |
||||
self.velocity += a * dt |
||||
if np.linalg.norm(self.velocity) > VELOCITY_CUTOFF: |
||||
self.velocity *= VELOCITY_CUTOFF / np.linalg.norm(self.velocity) |
||||
if abs(self.coordinates[0]) >= HALF_WIDTH: |
||||
self.velocity[0] *= -1 |
||||
self.coordinates[0] = np.sign(self.coordinates[0]) * min(abs(self.coordinates[0]), HALF_WIDTH - 2) |
||||
if abs(self.coordinates[1]) >= HALF_HEIGHT: |
||||
self.velocity[1] *= -1 |
||||
self.coordinates[1] = np.sign(self.coordinates[1]) * min(abs(self.coordinates[1]), HALF_HEIGHT - 2) |
||||
|
||||
def move(self, dt: float = DT): |
||||
self.coordinates += self.velocity * dt |
||||
|
||||
|
||||
@dataclass |
||||
class Gas: |
||||
particles: typing.List[Particle] |
||||
dt: float = DT |
||||
|
||||
def __init__(self, number: int = N) -> Gas: |
||||
self.particles = [Particle() for _ in range(N)] |
||||
|
||||
def step(self): |
||||
for particle in self.particles: |
||||
particle.adjust_velocity(self.particles, self.dt) |
||||
for particle in self.particles: |
||||
particle.move(self.dt) |
||||
|
||||
def visualize_with_turtles(self, turtles: typing.List[t.Turtle]): |
||||
for turtle, particle in zip(turtles, self.particles): |
||||
turtle.goto(*particle.coordinates) |
||||
|
||||
def run_with_turtles(self, turtles: typing.List[t.Turtle]): |
||||
while True: |
||||
last_time: float = time.time() |
||||
self.visualize_with_turtles(turtles) |
||||
self.step() |
||||
time.sleep(max(0, self.dt - (time.time() - last_time))) |
||||
|
||||
@classmethod |
||||
def create_turtles_and_run(cls, number: int = N): |
||||
self = cls() |
||||
turtles = [t.Turtle(shape='circle') for i in range(number)] |
||||
for turtle in turtles: |
||||
turtle.penup() |
||||
turtle.speed(0) |
||||
master_turtle = t.Turtle() |
||||
master_turtle.penup() |
||||
master_turtle.speed(0) |
||||
delta = 5 |
||||
master_turtle.goto(-HALF_WIDTH - delta, -HALF_HEIGHT - delta) |
||||
master_turtle.pendown() |
||||
master_turtle.goto(HALF_WIDTH + delta, -HALF_HEIGHT - delta) |
||||
master_turtle.goto(HALF_WIDTH + delta, HALF_HEIGHT + delta) |
||||
master_turtle.goto(-HALF_WIDTH - delta, HALF_HEIGHT + delta) |
||||
master_turtle.goto(-HALF_WIDTH - delta, -HALF_HEIGHT - delta) |
||||
master_turtle.up() |
||||
master_turtle.goto(1000, 1000) |
||||
del master_turtle |
||||
self.run_with_turtles(turtles) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
Gas.create_turtles_and_run() |
@ -1,44 +0,0 @@
|
||||
from random import randint |
||||
import turtle |
||||
import math |
||||
|
||||
|
||||
number_of_turtles = 20 |
||||
steps_of_time_number = 300 |
||||
turtle.screensize(100, 150) |
||||
|
||||
|
||||
pool = [turtle.Turtle(shape='turtle') for i in range(number_of_turtles)] |
||||
for unit in pool: |
||||
unit.penup() |
||||
unit.speed(350) |
||||
unit.goto(randint(-200, 200), randint(-150, 150)) |
||||
unit.left(randint(-180, 180)) |
||||
unit.rev_x = False |
||||
unit.rev_y = False |
||||
|
||||
|
||||
for i in range(steps_of_time_number): |
||||
for unit in pool: |
||||
x, y = unit.xcor(), unit.ycor() |
||||
if abs(x) >= turtle.screensize()[0] and not unit.rev_x: |
||||
unit.seth(90 - unit.heading()) |
||||
unit.rev_x = True |
||||
elif not abs(x) >= turtle.screensize()[0]: |
||||
unit.rev_x = False |
||||
if abs(y) >= turtle.screensize()[1] and not unit.rev_y: |
||||
unit.seth(-unit.heading()) |
||||
unit.rev_y = True |
||||
elif abs(y) < turtle.screensize()[1]: |
||||
unit.rev_y = False |
||||
unit.forward(7) |
||||
for another_unit in pool: |
||||
if another_unit == unit: |
||||
continue |
||||
if math.hypot(another_unit.xcor() - unit.xcor(), another_unit.ycor() - unit.ycor()) < 6: |
||||
angle = randint(-180, 180) |
||||
unit.seth(angle) |
||||
another_unit.seth(-angle) |
||||
unit.forward(2) |
||||
another_unit.forward(2) |
||||
|
Loading…
Reference in new issue