From 68916369a148ac95af661aae1a928fd9845b8349 Mon Sep 17 00:00:00 2001 From: ennucore Date: Sun, 26 Sep 2021 21:49:14 +0300 Subject: [PATCH] Make new gas simulation --- turtle_2/gas/gas_simulation.py | 100 +++++++++++++++++++++++++++++++++ turtle_2/task_2.py | 1 + turtle_2/turtle_gas.py | 44 --------------- 3 files changed, 101 insertions(+), 44 deletions(-) create mode 100644 turtle_2/gas/gas_simulation.py delete mode 100644 turtle_2/turtle_gas.py diff --git a/turtle_2/gas/gas_simulation.py b/turtle_2/gas/gas_simulation.py new file mode 100644 index 0000000..6999443 --- /dev/null +++ b/turtle_2/gas/gas_simulation.py @@ -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() diff --git a/turtle_2/task_2.py b/turtle_2/task_2.py index c5abbab..60d7aa4 100644 --- a/turtle_2/task_2.py +++ b/turtle_2/task_2.py @@ -4,6 +4,7 @@ import math import json +# Put a list of coordinates (x, y) (where x from 0 to 1, y from 0 to 2) in the JSON file DATA: typing.Dict[str, typing.List[typing.Tuple[int, int]]] = json.loads(open('font.json').read()) DIGIT_SIZE = 25 diff --git a/turtle_2/turtle_gas.py b/turtle_2/turtle_gas.py deleted file mode 100644 index aa0a14e..0000000 --- a/turtle_2/turtle_gas.py +++ /dev/null @@ -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) -