Browse Source

Make new gas simulation

master
Lev 3 years ago
parent
commit
68916369a1
  1. 100
      turtle_2/gas/gas_simulation.py
  2. 1
      turtle_2/task_2.py
  3. 44
      turtle_2/turtle_gas.py

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

1
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

44
turtle_2/turtle_gas.py

@ -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…
Cancel
Save