Лабораторные работы по Python, ЛФИ, 1 семестр
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.5 KiB

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()