This commit is contained in:
Tomáš Sláma 2025-02-11 21:33:11 +01:00
commit f8d03c6162
19 changed files with 187819 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.idea/
logo/
**__pycache__/
**venv/
ignored/

View file

@ -0,0 +1,3 @@
# Asteracer v Pythonu
Mělo by stačit spustit `__main__.py`.

View file

@ -0,0 +1,128 @@
from asteracer import *
def load_asteroid_graph(path: str):
with open(path) as f:
contents = [
line
for line in f.read().splitlines()
if not line.startswith("#") and line.strip() != ""
]
n_racer, n_asteroid, n_goal, m = list(map(int, contents[0].split()))
vertices = []
edges = []
vertex_objects = []
# Load vertices
for i in range(1, 1 + n_racer + n_asteroid + n_goal):
line = contents[i + 1].split()
vertices.append((int(line[0]), int(line[1])))
if 0 <= i < n_racer:
vertex_objects.append(("S", i))
elif n_racer <= i < n_asteroid:
vertex_objects.append(("A", int(line[2])))
elif n_asteroid <= i < n_goal:
vertex_objects.append(("G", int(line[2])))
# Load edges
for i in range(i, i + m):
line = contents[i + 1].split()
edges.append((int(line[0]), int(line[1])))
return vertices, edges, vertex_objects
if __name__ == "__main__":
simulation = Simulation.load(f"../mapy/test.txt")
print(f"Startovní pozice: {simulation.racer.x} {simulation.racer.y}")
print(f"Počet asteroidů: {len(simulation.asteroids)}")
print(f"Počet cílů: {len(simulation.goals)}")
print()
tick = 0
print("Letím doprava...")
while True:
result = simulation.tick(Instruction(127, 0))
if result & TickFlag.COLLIDED:
print(f"Narazili jsme po {tick} instrukcích! Au...")
print(f"Aktuální pozice: {simulation.racer.x} {simulation.racer.y}")
print()
break
tick += 1
print("Letím dolů (je tam gól)...")
while True:
result = simulation.tick(Instruction(0, 127))
if result & TickFlag.GOAL_REACHED:
print(f"Sebrali jsme gól po {tick} instrucích!")
print(f"Góly sesbírány: {simulation.reached_goals}")
print(f"Aktuální pozice: {simulation.racer.x} {simulation.racer.y}")
print()
break
tick += 1
# posbíráme zbývající cíle tak, že k nim poletíme přímou čarou
for _ in range(simulation.reached_goals.count(False)):
nearest_goal = None
nearest_goal_distance = float('inf')
for i, reached in enumerate(simulation.reached_goals):
if not reached:
goal = simulation.goals[i]
distance = euclidean_distance(goal.x, goal.y, simulation.racer.x, simulation.racer.y)
if distance < nearest_goal_distance:
nearest_goal_distance = distance
nearest_goal = goal
print("Letíme k nejbližšímu cíli přímou čarou...")
collided_count = 0
while True:
instruction = Instruction(
nearest_goal.x - simulation.racer.x,
nearest_goal.y - simulation.racer.y,
)
result = simulation.tick(instruction)
if result & TickFlag.COLLIDED:
collided_count += 1
if result & TickFlag.GOAL_REACHED:
print(f"Sebrali jsme další gól po {tick} instrucích!")
print(f"Počet nárazů po cestě: {collided_count}")
print(f"Góly sesbírány: {simulation.reached_goals}")
print()
break
tick += 1
print(f"Hotovo!")
print()
assert simulation.finished()
print("Načítám graf...")
# - vertices jsou (x, y) pozice vrcholů
# - edges jsou (u, v) dvojice vrcholů tvořících hranu
# - vertex_objects jsou dvojice (typ, index), kde
# typ je typ objektu vrcholu ('A' asteroid, 'G' gól a 'S' loď)
# a index je kolikátý je to objekt (t.j. kolikátý asteroid, gól, apod.)
vertices, edges, vertex_objects = load_asteroid_graph("../grafy/test.txt")
print(f"{len(vertices)} vrcholů a {len(edges)} hran, vypisuji prvních 5:")
print(f"-> vrcholy: {vertices[:5]}")
print(f"-> hrany: {edges[:5]}")
print(f"-> objekty: {vertex_objects[:5]}")

View file

@ -0,0 +1,434 @@
from __future__ import annotations
import dataclasses
import random
from collections import defaultdict
from dataclasses import dataclass
from math import isqrt
from typing import List, Union, Tuple, Dict
# tohle dříve byly numpy typy, ale asi je lepší,
# ať účastníci nemusí nic instalovat...
InstType = int # np.int8
PosType = int # np.int64
SpeedType = int # np.int64
SizeType = int # np.int64
class TickFlag:
"""Flags returned by simulation.tick() for various events that can occur during a tick."""
COLLIDED = 1
GOAL_REACHED = 2
@dataclass
class Racer:
x: PosType = 0
y: PosType = 0
vx: SpeedType = 0
vy: SpeedType = 0
radius: SizeType = 1
@dataclass(frozen=True)
class Asteroid:
x: PosType = 0
y: PosType = 0
radius: SizeType = 1
Goal = Asteroid
class Instruction:
MAX_ACCELERATION = 127
def __init__(self, vx: Union[int, float] = 0, vy: Union[int, float] = 0):
"""Whatever values we get, normalize them."""
if distance_squared(vx, vy) > Instruction.MAX_ACCELERATION ** 2:
vx = float(vx)
vy = float(vy)
# use float to properly normalize here
distance = (vx ** 2 + vy ** 2) ** (1/2)
vx = int(vx / distance * Instruction.MAX_ACCELERATION)
vy = int(vy / distance * Instruction.MAX_ACCELERATION)
# if we're still over, decrement both values
if distance_squared(vx, vy) > Instruction.MAX_ACCELERATION ** 2:
vx -= signum(vx)
vy -= signum(vy)
assert distance_squared(vx, vy) <= Instruction.MAX_ACCELERATION ** 2
self.vx = InstType(vx)
self.vy = InstType(vy)
def __hash__(self):
return hash((self.vx, self.vy))
def __eq__(self, other):
return self.vx == other.vx and self.vy == other.vy
def __str__(self):
return f"Instruction({self.vx}, {self.vy})"
@classmethod
def random(cls):
return cls(
random.randint(
-cls.MAX_ACCELERATION,
cls.MAX_ACCELERATION
),
random.randint(
-cls.MAX_ACCELERATION,
cls.MAX_ACCELERATION
),
)
@dataclass
class BoundingBox:
min_x: PosType
min_y: PosType
max_x: PosType
max_y: PosType
def width(self) -> SizeType:
return SizeType(self.max_x - self.min_x)
def height(self) -> SizeType:
return SizeType(self.max_y - self.min_y)
def distance_squared(x1, y1, x2=0, y2=0) -> PosType:
"""Squared Euclidean distance between two points."""
return (PosType(x1) - PosType(x2)) ** 2 + (PosType(y1) - PosType(y2)) ** 2
def euclidean_distance(x1, y1, x2=0, y2=0):
"""Integer Euclidean distance between two points. Uses integer square root."""
return PosType(isqrt(distance_squared(x1, y1, x2, y2)))
def signum(x):
return -1 if x < 0 else 0 if x == 0 else 1
def division(a, b):
"""Correctly implemented division, removing the fractional component."""
return (abs(int(a)) // int(b)) * signum(a)
class Simulation:
DRAG_FRACTION = (9, 10) # slowdown of the racer's velocity after each tick
COLLISION_FRACTION = (1, 2) # slowdown of the racer's velocity after a tick where a collision occurred
MAX_COLLISION_RESOLUTIONS = 5 # at most how many collision iterations to perform
CELL_SIZE = 10_000
def __init__(
self,
racer: Racer = Racer(),
asteroids: List[Asteroid] = None,
goals: List[Goal] = None,
bounding_box: BoundingBox = None,
):
# the initial racer state (used when resetting the simulation)
self.initial_racer = dataclasses.replace(racer)
self.racer = racer
self.asteroids = asteroids or []
self.goals = goals or []
self.bounding_box = bounding_box
# to speed up the computation, we divide the bounding box (if we have one) into a grid
# we do this so we don't need to check all asteroids at each tick, only those that could collide with the racer
self._grid: Dict[Tuple[int, int], List[Asteroid]] = defaultdict(list)
for asteroid in asteroids:
min_x, min_y = self._coordinate_to_grid(
asteroid.x - asteroid.radius - racer.radius,
asteroid.y - asteroid.radius - racer.radius,
)
max_x, max_y = self._coordinate_to_grid(
asteroid.x + asteroid.radius + racer.radius,
asteroid.y + asteroid.radius + racer.radius,
)
for grid_x in range(min_x, max_x + 1):
for grid_y in range(min_y, max_y + 1):
self._grid[(grid_x, grid_y)].append(asteroid)
self.reached_goals: List[bool] = [False] * len(self.goals)
# a list of simulation states that can be popped (restored to)
self._pushed_states = []
def _coordinate_to_grid(self, x: float, y: float) -> Tuple[int, int]:
"""Translate an (x,y) coordinate into a coordinate of the grid."""
return (x // self.CELL_SIZE, y // self.CELL_SIZE)
def _move_racer(self, instruction: Instruction):
"""Move the racer in the given direction."""
vx, vy = instruction.vx, instruction.vy
# drag
self.racer.vx = division(self.racer.vx * self.DRAG_FRACTION[0], self.DRAG_FRACTION[1])
self.racer.vy = division(self.racer.vy * self.DRAG_FRACTION[0], self.DRAG_FRACTION[1])
# velocity
self.racer.vx += SpeedType(vx)
self.racer.vy += SpeedType(vy)
# movement
self.racer.x += self.racer.vx
self.racer.y += self.racer.vy
def _push_out(self, obj: Union[Asteroid, BoundingBox]) -> bool:
"""Attempt to push the racer out of the object (if he's colliding), adjusting
his velocity accordingly (based on the angle of collision). Returns True if the
racer was pushed out, otherwise returns False."""
if isinstance(obj, Asteroid):
# not colliding, nothing to be done
if euclidean_distance(self.racer.x, self.racer.y, obj.x, obj.y) > (self.racer.radius + obj.radius):
return False
# the vector to push the racer out by
nx = self.racer.x - obj.x
ny = self.racer.y - obj.y
# how much to push by
distance = euclidean_distance(self.racer.x, self.racer.y, obj.x, obj.y)
push_by = distance - (self.racer.radius + obj.radius)
# the actual push
self.racer.x -= division(nx * push_by, distance)
self.racer.y -= division(ny * push_by, distance)
return True
elif isinstance(obj, BoundingBox):
# not pretty but easy to read :)
collided = False
if self.racer.x - self.racer.radius < obj.min_x:
self.racer.x = obj.min_x + self.racer.radius
collided = True
if self.racer.x + self.racer.radius > obj.max_x:
self.racer.x = obj.max_x - self.racer.radius
collided = True
if self.racer.y - self.racer.radius < obj.min_y:
self.racer.y = obj.min_y + self.racer.radius
collided = True
if self.racer.y + self.racer.radius > obj.max_y:
self.racer.y = obj.max_y - self.racer.radius
collided = True
return collided
else:
raise Exception("Attempted to collide with something other than asteroid / bounding box!")
def _check_goal(self) -> bool:
"""Sets the _reached_goals variable to True according to if the racer is intersecting them, returning True if
a new one was reached."""
new_goal_reached = False
for i, goal in enumerate(self.goals):
if euclidean_distance(self.racer.x, self.racer.y, goal.x, goal.y) <= (self.racer.radius + goal.radius):
if not self.reached_goals[i]:
new_goal_reached = True
self.reached_goals[i] = True
return new_goal_reached
def _resolve_collisions(self) -> bool:
"""Resolve all collisions of the racer and asteroids, returning True if a collison occurred."""
collided = False
for _ in range(self.MAX_COLLISION_RESOLUTIONS):
collided_this_iteration = False
for asteroid in self._grid[self._coordinate_to_grid(self.racer.x, self.racer.y)]:
if self._push_out(asteroid):
collided_this_iteration = collided = True
break
if self.bounding_box is not None and self._push_out(self.bounding_box):
collided_this_iteration = collided = True
if not collided_this_iteration:
break
if collided:
self.racer.vx = division(self.racer.vx * self.COLLISION_FRACTION[0], self.COLLISION_FRACTION[1])
self.racer.vy = division(self.racer.vy * self.COLLISION_FRACTION[0], self.COLLISION_FRACTION[1])
return collided
def finished(self) -> bool:
"""Returns True if the racer reached all goals."""
return all(self.reached_goals)
def restart(self):
"""Restart the simulation to its initial state."""
self.racer.x = self.initial_racer.x
self.racer.y = self.initial_racer.y
self.racer.vx = 0
self.racer.vy = 0
for i in range(len(self.reached_goals)):
self.reached_goals[i] = False
def tick(self, instruction: Instruction):
"""Simulate a single tick of the simulation."""
self._move_racer(instruction)
collided = self._resolve_collisions()
goal = self._check_goal()
return (TickFlag.COLLIDED if collided else 0) | (TickFlag.GOAL_REACHED if goal else 0)
def simulate(self, instructions: List[Instruction]):
"""Simulate a number of instructions for the simulation (from the start)."""
self.restart()
results = []
for instruction in instructions:
results.append(self.tick(instruction))
return results
def save(self, path: str):
"""Save the simulation to a file:
| 0 0 5
| -100 -100 100 100 // bounding box (min_x/min_y/max_x/max_y)
| 5 // number of asteroids
| 10 -10 10 // asteroid 1 x/y/radius
| 20 20 50 // asteroid 2 x/y/radius
| -10 10 30 // asteroid 3 x/y/radius
| 10 10 70 // asteroid 4 x/y/radius
| -10 -10 10 // asteroid 5 x/y/radius
| 1 // number of goals
| 100 100 10 // goal 1 x/y/radius
"""
with open(path, "w") as f:
f.write(f"{self.racer.x} {self.racer.y} {self.racer.radius}\n")
bbox = self.bounding_box
f.write(f"{bbox.min_x} {bbox.min_y} {bbox.max_x} {bbox.max_y}\n")
f.write(f"{len(self.asteroids)}\n")
for asteroid in self.asteroids:
f.write(f"{asteroid.x} {asteroid.y} {asteroid.radius}\n")
f.write(f"{len(self.goals)}\n")
for goal in self.goals:
f.write(f"{goal.x} {goal.y} {goal.radius}\n")
@classmethod
def load(cls, path: str) -> Simulation:
"""Load the simulation from a file (see self.save for the format description)."""
with open(path) as f:
lines = f.read().splitlines()
racer_parts = lines[0].split()
racer = Racer(x=PosType(racer_parts[0]), y=PosType(racer_parts[1]), radius=SizeType(racer_parts[2]))
bb_parts = lines[1].split()
bb = BoundingBox(PosType(bb_parts[0]), PosType(bb_parts[1]), PosType(bb_parts[2]), PosType(bb_parts[2]))
asteroid_count = int(lines[2])
asteroids = []
for i in range(3, 3 + asteroid_count):
asteroid_parts = lines[i].split()
asteroids.append(
Asteroid(
x=PosType(asteroid_parts[0]),
y=PosType(asteroid_parts[1]),
radius=SizeType(asteroid_parts[2]),
)
)
goal_count = int(lines[3 + asteroid_count])
goals = []
for i in range(4 + asteroid_count, 4 + asteroid_count + goal_count):
goal_parts = lines[i].split()
goals.append(
Asteroid(
x=PosType(goal_parts[0]),
y=PosType(goal_parts[1]),
radius=SizeType(goal_parts[2]),
)
)
return Simulation(racer=racer, bounding_box=bb, asteroids=asteroids, goals=goals)
def push(self):
"""Push (save) the current state of the simulation. Can be popped (restored) later."""
self._pushed_states.append(
(
dataclasses.replace(self.racer),
list(self.reached_goals),
)
)
def pop(self):
"""Pop (restore) the previously pushed state."""
assert len(self._pushed_states) != 0, "No states to pop!"
self.racer, self.reached_goals = self._pushed_states.pop()
def apply(self):
"""Apply the previously pushed state without popping it."""
self.racer = dataclasses.replace(self._pushed_states[-1][0])
self.reached_goals = list(self._pushed_states[-1][1])
def save_instructions(path: str, instructions: List[Instruction]):
"""Save a list of instructions to a file:
| 4 // number if instructions
| -16 -127 // instructions...
| -16 -127
| -26 -125
| -30 -124
"""
with open(path, "w") as f:
f.write(f"{len(instructions)}\n")
for instruction in instructions:
f.write(f"{instruction.vx} {instruction.vy}\n")
def load_instructions(path: str) -> List[Instruction]:
"""Load a list of instructions from a file (see save_instructions for the format description)."""
instructions = []
with open(path) as f:
for line in f.read().splitlines()[1:]:
instruction_parts = list(map(InstType, line.split()))
instructions.append(Instruction(*instruction_parts))
return instructions
if __name__ == "__main__":
map_path = "../../maps/test.txt"
simulation = Simulation.load(map_path)
tick_result = 0
print("Running simulation until collision...")
while tick_result & TickFlag.COLLIDED == 0:
tick_result = simulation.tick(Instruction(0, Instruction.MAX_ACCELERATION))
print(simulation.racer)
print("Bam!")

1
asteracer-rust/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

244
asteracer-rust/Cargo.lock generated Normal file
View file

@ -0,0 +1,244 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "asteracer-rust"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi",
"windows-targets",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy 0.7.35",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy 0.8.17",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
dependencies = [
"getrandom",
"zerocopy 0.8.17",
]
[[package]]
name = "syn"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
dependencies = [
"zerocopy-derive 0.8.17",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -0,0 +1,7 @@
[package]
name = "asteracer-rust"
version = "0.1.0"
edition = "2024"
[dependencies]
rand = "0.9.0"

3
asteracer-rust/README.md Normal file
View file

@ -0,0 +1,3 @@
# Asteracer v Rustu
Mělo by stačit spustit `cargo run`.

View file

@ -0,0 +1,460 @@
use rand::prelude::*;
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
pub mod TickFlag {
pub const COLLIDED: usize = 1;
pub const GOAL_REACHED: usize = 2;
}
pub type TickResult = usize;
pub type InstType = i8;
pub type PosType = i64;
pub type SpeedType = i64;
pub type SizeType = i64;
pub static MAX_ACCELERATION: InstType = 127;
pub static DRAG_FRACTION: (SpeedType, SpeedType) = (9, 10);
pub static COLLISION_FRACTION: (SpeedType, SpeedType) = (1, 2);
pub static MAX_COLLISION_RESOLUTIONS: usize = 5;
pub static CELL_SIZE: PosType = 10_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Racer {
pub x: PosType,
pub y: PosType,
pub vx: SpeedType,
pub vy: SpeedType,
pub radius: SizeType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Asteroid {
pub x: PosType,
pub y: PosType,
pub radius: SizeType,
}
pub type Goal = Asteroid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Instruction {
pub vx: InstType,
pub vy: InstType,
}
impl Instruction {
fn valid(vx: PosType, vy: PosType) -> bool {
distance_squared(vx, vy, 0, 0) <= (MAX_ACCELERATION as PosType).pow(2)
}
pub fn new<T>(vx: T, vy: T) -> Self
where
T: Copy + Into<PosType>,
{
let vx: i64 = vx.into();
let vy: i64 = vy.into();
if !Self::valid(vx, vy) {
// use float to properly normalize here
let float_distance = ((vx as f64).powf(2.) + (vy as f64).powf(2.)).powf(1. / 2.);
let mut vx = ((vx as f64 / float_distance) * MAX_ACCELERATION as f64) as PosType;
let mut vy = ((vy as f64 / float_distance) * MAX_ACCELERATION as f64) as PosType;
// if we're still over, decrement both values
if !Self::valid(vx, vy) {
vx -= vx.signum();
vy -= vy.signum();
}
return Self { vx: vx as InstType, vy: vy as InstType };
}
assert!(Self::valid(vx, vy));
Self {
vx: vx as InstType,
vy: vy as InstType,
}
}
pub fn random() -> Self {
let mut rng = rand::rng();
Self {
vx: rng.random::<InstType>(),
vy: rng.random::<InstType>(),
}
}
pub fn load(path: &PathBuf) -> Vec<Instruction> {
let contents = fs::read_to_string(path).expect("Failed reading a file!");
let mut lines = contents.lines();
let instruction_count = lines.next().unwrap().parse::<usize>().unwrap();
let mut instructions = vec![];
for _ in 0..instruction_count {
let parts = lines
.next()
.expect("No more lines!")
.split_whitespace()
.collect::<Vec<&str>>();
instructions.push(Instruction {
vx: parts[0].parse::<InstType>().unwrap(),
vy: parts[1].parse::<InstType>().unwrap(),
})
}
instructions
}
pub fn save(path: &PathBuf, instructions: &Vec<Instruction>) {
let mut file = File::create(path).expect("Failed creating a file!");
for instruction in instructions {
file.write_all(format!("{} {}\n", instruction.vx, instruction.vy).as_bytes())
.expect("Failed writing to file!");
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct BoundingBox {
pub min_x: SizeType,
pub min_y: SizeType,
pub max_x: SizeType,
pub max_y: SizeType,
}
impl BoundingBox {
pub fn width(&self) -> SizeType {
self.max_x - self.min_x
}
pub fn height(&self) -> SizeType {
self.max_y - self.min_y
}
}
/// Squared Euclidean distance; useful for distance checks.
fn distance_squared(x1: PosType, y1: PosType, x2: PosType, y2: PosType) -> PosType {
(x1 - x2).pow(2) + (y1 - y2).pow(2)
}
/// Plain-old integer Euclidean distance.
///
/// Note: this implementation might break for larger position values, but since
/// the maps are never going to be this large, I'm not fixing it now.
pub fn euclidean_distance(x1: PosType, y1: PosType, x2: PosType, y2: PosType) -> PosType {
(distance_squared(x1, y1, x2, y2) as f64).sqrt() as PosType
}
#[derive(Debug, Clone)]
pub struct Simulation {
pub initial_racer: Racer,
pub racer: Racer,
pub asteroids: Vec<Asteroid>,
pub goals: Vec<Goal>,
pub bbox: BoundingBox,
pub reached_goals: Vec<bool>,
_grid: HashMap<(PosType, PosType), Vec<Asteroid>>,
_cell_size: PosType,
}
///
/// # Examples
/// ```
/// let map_path = PathBuf::from("../../maps/test.txt");
///
/// let mut simulation = Simulation::load(&map_path);
///
/// let mut tick_result: TickResult = 0;
///
/// println!("Running simulation until collision...");
///
/// while tick_result & TickFlag::COLLIDED == 0 {
/// tick_result = simulation.tick(Instruction::new(0, MAX_ACCELERATION));
///
/// println!("{:?}", simulation.racer);
/// }
///
/// println!("Bam!");
/// ```
///
impl Simulation {
pub fn new(racer: Racer, asteroids: Vec<Asteroid>, goals: Vec<Goal>, bbox: BoundingBox) -> Self {
let reached_goals = vec![false; goals.len()];
let mut simulation = Self {
initial_racer: racer,
racer,
asteroids,
goals,
bbox,
reached_goals,
_grid: HashMap::new(),
_cell_size: CELL_SIZE,
};
for &asteroid in &simulation.asteroids {
let (min_x, min_y) = simulation.coordinate_to_grid(
asteroid.x - asteroid.radius - racer.radius,
asteroid.y - asteroid.radius - racer.radius,
);
let (max_x, max_y) = simulation.coordinate_to_grid(
asteroid.x + asteroid.radius + racer.radius,
asteroid.y + asteroid.radius + racer.radius,
);
for grid_x in min_x..=max_x {
for grid_y in min_y..=max_y {
simulation
._grid
.entry((grid_x, grid_y))
.or_insert(vec![])
.push(asteroid);
}
}
}
simulation
}
fn coordinate_to_grid(&self, x: PosType, y: PosType) -> (PosType, PosType) {
(x / self._cell_size, y / self._cell_size)
}
fn move_racer(&mut self, instruction: Instruction) {
self.racer.vx = (self.racer.vx * DRAG_FRACTION.0) / DRAG_FRACTION.1;
self.racer.vy = (self.racer.vy * DRAG_FRACTION.0) / DRAG_FRACTION.1;
self.racer.vx += instruction.vx as SpeedType;
self.racer.vy += instruction.vy as SpeedType;
self.racer.x += self.racer.vx as PosType;
self.racer.y += self.racer.vy as PosType;
}
fn push_from_asteroids(&mut self) -> bool {
let grid_coordinate = self.coordinate_to_grid(self.racer.x, self.racer.y);
match self._grid.get(&grid_coordinate) {
None => false,
Some(asteroids) => {
for asteroid in asteroids {
// not colliding, nothing to be done
if euclidean_distance(self.racer.x, self.racer.y, asteroid.x, asteroid.y)
> self.racer.radius + asteroid.radius
{
continue;
}
// the vector to push the racer out by
let nx = self.racer.x - asteroid.x;
let ny = self.racer.y - asteroid.y;
// how much to push by
let distance =
euclidean_distance(self.racer.x, self.racer.y, asteroid.x, asteroid.y);
let push_by = distance - (self.racer.radius + asteroid.radius);
// the actual push
self.racer.x -= (nx * push_by) / distance;
self.racer.y -= (ny * push_by) / distance;
return true;
}
false
}
}
}
fn push_from_bounding_box(&mut self) -> bool {
// not pretty but easy to read :)
let mut collided = false;
if self.racer.x - self.racer.radius < self.bbox.min_x {
self.racer.x = self.bbox.min_x + self.racer.radius;
collided = true;
}
if self.racer.x + self.racer.radius > self.bbox.max_x {
self.racer.x = self.bbox.max_x - self.racer.radius;
collided = true;
}
if self.racer.y - self.racer.radius < self.bbox.min_y {
self.racer.y = self.bbox.min_y + self.racer.radius;
collided = true;
}
if self.racer.y + self.racer.radius > self.bbox.max_y {
self.racer.y = self.bbox.max_y - self.racer.radius;
collided = true;
}
collided
}
fn check_goal(&mut self) -> bool {
let mut new_goal_reached = false;
for (i, goal) in self.goals.iter().enumerate() {
if euclidean_distance(self.racer.x, self.racer.y, goal.x, goal.y)
<= (self.racer.radius + goal.radius)
{
if !&self.reached_goals[i] {
new_goal_reached = true;
}
self.reached_goals[i] = true;
}
}
new_goal_reached
}
fn resolve_collisions(&mut self) -> bool {
let mut collided = false;
for _ in 0..MAX_COLLISION_RESOLUTIONS {
let mut collided_this_iteration = false;
if self.push_from_asteroids() {
collided_this_iteration = true;
collided = true;
}
if self.push_from_bounding_box() {
collided_this_iteration = true;
collided = true;
}
if !collided_this_iteration {
break;
}
}
if collided {
self.racer.vx = (self.racer.vx * COLLISION_FRACTION.0) / COLLISION_FRACTION.1;
self.racer.vy = (self.racer.vy * COLLISION_FRACTION.0) / COLLISION_FRACTION.1;
}
collided
}
pub fn finished(&self) -> bool {
self.reached_goals.iter().all(|v| *v)
}
pub fn restart(&mut self) {
self.racer.x = self.initial_racer.x;
self.racer.y = self.initial_racer.y;
self.racer.vx = 0;
self.racer.vy = 0;
self.reached_goals.fill(false);
}
pub fn tick(&mut self, instruction: Instruction) -> TickResult {
self.move_racer(instruction);
let collided = self.resolve_collisions();
let goal = self.check_goal();
let mut result: TickResult = 0;
if collided {
result |= TickFlag::COLLIDED;
}
if goal {
result |= TickFlag::GOAL_REACHED;
}
result
}
pub fn simulate(&mut self, instructions: &Vec<Instruction>) -> Vec<TickResult> {
self.restart();
let mut results = vec![];
for instruction in instructions {
results.push(self.tick(*instruction));
}
results
}
pub fn load(path: &PathBuf) -> Self {
let binding = fs::read_to_string(path).unwrap();
let mut lines = binding.lines();
let mut parts_fn = || {
lines
.next()
.unwrap()
.split_whitespace()
.collect::<Vec<&str>>()
};
let racer_parts = parts_fn();
let racer = Racer {
x: racer_parts[0].parse::<PosType>().unwrap(),
y: racer_parts[1].parse::<PosType>().unwrap(),
radius: racer_parts[2].parse::<SizeType>().unwrap(),
vx: 0,
vy: 0,
};
let bb_parts = parts_fn();
let bbox = BoundingBox {
min_x: bb_parts[0].parse::<SizeType>().unwrap(),
min_y: bb_parts[1].parse::<SizeType>().unwrap(),
max_x: bb_parts[2].parse::<SizeType>().unwrap(),
max_y: bb_parts[3].parse::<SizeType>().unwrap(),
};
let asteroid_count = parts_fn()[0].parse::<usize>().unwrap();
let mut asteroids = vec![];
for _ in 0..asteroid_count {
let asteroid_parts = parts_fn();
asteroids.push(Asteroid {
x: asteroid_parts[0].parse::<PosType>().unwrap(),
y: asteroid_parts[1].parse::<PosType>().unwrap(),
radius: asteroid_parts[2].parse::<PosType>().unwrap(),
});
}
let goal_count = parts_fn()[0].parse::<usize>().unwrap();
let mut goals = vec![];
for _ in 0..goal_count {
let goal_parts = parts_fn();
goals.push(Asteroid {
x: goal_parts[0].parse::<PosType>().unwrap(),
y: goal_parts[1].parse::<PosType>().unwrap(),
radius: goal_parts[2].parse::<PosType>().unwrap(),
});
}
Self::new(racer, asteroids, goals, bbox)
}
}

179
asteracer-rust/src/main.rs Normal file
View file

@ -0,0 +1,179 @@
use std::fs::File;
use std::io;
use std::io::BufRead;
use asteracer::*;
use std::path::PathBuf;
mod asteracer;
pub fn load_asteroid_graph(path: &PathBuf) -> (
Vec<(PosType, PosType)>,
Vec<(usize, usize)>,
Vec<(char, usize)>,
) {
let file = File::open(path).unwrap();
let reader = io::BufReader::new(file);
let contents: Vec<String> = reader
.lines()
.filter_map(Result::ok)
.filter(|line| !line.starts_with('#') && !line.trim().is_empty())
.collect();
let mut iter = contents.iter();
let first_line: Vec<usize> = iter
.next()
.unwrap()
.split_whitespace()
.filter_map(|s| s.parse().ok())
.collect();
let (n_racer, n_asteroid, n_goal, m) =
(first_line[0], first_line[1], first_line[2], first_line[3]);
let mut vertices = Vec::new();
let mut edges = Vec::new();
let mut vertex_objects = Vec::new();
// Load vertices
for i in 0..(n_racer + n_asteroid + n_goal) {
let line: Vec<i64> = iter
.next()
.unwrap()
.split_whitespace()
.filter_map(|s| s.parse().ok())
.collect();
vertices.push((line[0], line[1]));
if i < n_racer {
vertex_objects.push(('S', i));
} else if i < (n_racer + n_asteroid) {
vertex_objects.push(('A', line[2] as usize));
} else {
vertex_objects.push(('G', line[2] as usize));
}
}
// Load edges
for _ in 0..m {
let line: Vec<usize> = iter
.next()
.unwrap()
.split_whitespace()
.filter_map(|s| s.parse().ok())
.collect();
edges.push((line[0], line[1]));
}
(vertices, edges, vertex_objects)
}
fn main() {
let mut simulation = Simulation::load(&PathBuf::from("../mapy/test.txt"));
println!(
"Startovní pozice: {} {}",
simulation.racer.x, simulation.racer.y
);
println!("Počet asteroidů: {}", simulation.asteroids.len());
println!("Počet cílů: {}", simulation.goals.len());
println!();
// Fly to the right until we hit the wall
let mut tick = 0;
println!("Letím doprava...");
loop {
let result = simulation.tick(Instruction::new(MAX_ACCELERATION, 0));
if (result & TickFlag::COLLIDED) != 0 {
println!("Narazili jsme po {} instrukcích! Au...", tick);
println!(
"Aktuální pozice: {} {}",
simulation.racer.x, simulation.racer.y
);
println!();
break;
}
tick += 1;
}
// Fly down to reach the first checkpoint
println!("Letím dolů (je tam gól)...");
loop {
let result = simulation.tick(Instruction::new(0, MAX_ACCELERATION));
if (result & TickFlag::GOAL_REACHED) != 0 {
println!("Sebrali jsme gól po {} instrucích!", tick);
println!("Góly sesbírány: {:?}", simulation.reached_goals);
println!(
"Current racer position: {} {}",
simulation.racer.x, simulation.racer.y
);
println!();
break;
}
tick += 1;
}
// posbíráme zbývající cíle tak, že k nim poletíme přímou čarou
while simulation.reached_goals.iter().any(|&reached| !reached) {
let mut nearest_goal = None;
let mut nearest_goal_distance = PosType::MAX;
for (i, &reached) in simulation.reached_goals.iter().enumerate() {
if !reached {
let goal = &simulation.goals[i];
let distance = euclidean_distance(goal.x, goal.y, simulation.racer.x, simulation.racer.y);
if distance < nearest_goal_distance {
nearest_goal_distance = distance;
nearest_goal = Some(goal.clone());
}
}
}
let nearest_goal = nearest_goal.unwrap();
println!("Letíme k nejbližšímu cíli přímou čarou...");
let mut collided_count = 0;
loop {
let instruction = Instruction::new(
nearest_goal.x - simulation.racer.x,
nearest_goal.y - simulation.racer.y,
);
let result = simulation.tick(instruction);
if (result & TickFlag::COLLIDED) != 0 {
collided_count += 1;
}
if (result & TickFlag::GOAL_REACHED) != 0 {
println!("Sebrali jsme další gól po {} instrucích!", tick);
println!("Počet nárazů po cestě: {}", collided_count);
println!("Góly sesbírány: {:?}", simulation.reached_goals);
println!();
break;
}
tick += 1;
}
}
println!("Hotovo!");
assert!(simulation.finished());
println!("Načítám graf...");
// - vertices jsou (x, y) pozice vrcholů
// - edges jsou (u, v) dvojice vrcholů tvořících hranu
// - vertex_objects jsou dvojice (typ, index), kde
// typ je typ objektu vrcholu ('A' asteroid, 'G' gól a 'S' loď)
// a index je kolikátý je to objekt (t.j. kolikátý asteroid, gól, apod.)
let (vertices, edges, vertex_objects) = load_asteroid_graph(&PathBuf::from("../grafy/test.txt"));
println!("{} vrcholů a {} hran, vypisuji prvních 5:", vertices.len(), edges.len());
println!("-> vrcholy: {:?}", vertices.iter().take(5).collect::<Vec<_>>());
println!("-> hrany: {:?}", edges.iter().take(5).collect::<Vec<_>>());
println!("-> objekty: {:?}", vertex_objects.iter().take(5).collect::<Vec<_>>());
}

157720
grafy/marathon.txt Normal file

File diff suppressed because it is too large Load diff

22993
grafy/sprint.txt Normal file

File diff suppressed because it is too large Load diff

1235
grafy/test.txt Normal file

File diff suppressed because it is too large Load diff

1578
mapy/marathon.svg Normal file

File diff suppressed because it is too large Load diff

After

(image error) Size: 152 KiB

1574
mapy/marathon.txt Normal file

File diff suppressed because it is too large Load diff

609
mapy/sprint.svg Normal file
View file

@ -0,0 +1,609 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1000" height="1000" viewBox="-500.0 -500.0 1000 1000">
<defs>
</defs>
<rect x="-500.0" y="-500.0" width="1000" height="1000" fill="White" />
<circle cx="392.795" cy="-328.831" r="18.468" fill="Black" stroke="Black" />
<circle cx="-307.826" cy="377.623" r="19.829" fill="Black" stroke="Black" />
<circle cx="-442.617" cy="-154.891" r="11.264" fill="Black" stroke="Black" />
<circle cx="432.417" cy="268.197" r="24.37" fill="Black" stroke="Black" />
<circle cx="63.112" cy="63.218" r="9.622" fill="Black" stroke="Black" />
<circle cx="145.009" cy="-244.769" r="25.481" fill="Black" stroke="Black" />
<circle cx="-182.475" cy="-481.847" r="16.616" fill="Black" stroke="Black" />
<circle cx="271.657" cy="16.729" r="11.598" fill="Black" stroke="Black" />
<circle cx="107.669" cy="336.857" r="19.407" fill="Black" stroke="Black" />
<circle cx="-262.21" cy="83.341" r="12.495" fill="Black" stroke="Black" />
<circle cx="57.295" cy="-466.957" r="8.501" fill="Black" stroke="Black" />
<circle cx="-486.605" cy="406.957" r="10.652" fill="Black" stroke="Black" />
<circle cx="-477.64" cy="176.38" r="15.416" fill="Black" stroke="Black" />
<circle cx="-175.17" cy="-203.102" r="8.825" fill="Black" stroke="Black" />
<circle cx="256.472" cy="360.989" r="13.94" fill="Black" stroke="Black" />
<circle cx="276.792" cy="-175.871" r="15.787" fill="Black" stroke="Black" />
<circle cx="411.182" cy="-486.282" r="19.694" fill="Black" stroke="Black" />
<circle cx="285.329" cy="206.724" r="8.553" fill="Black" stroke="Black" />
<circle cx="-40.717" cy="-245.739" r="11.996" fill="Black" stroke="Black" />
<circle cx="-104.495" cy="367.324" r="12.911" fill="Black" stroke="Black" />
<circle cx="-47.927" cy="-121.478" r="8.043" fill="Black" stroke="Black" />
<circle cx="-180.885" cy="-36.462" r="10.454" fill="Black" stroke="Black" />
<circle cx="193.344" cy="-405.06" r="24.913" fill="Black" stroke="Black" />
<circle cx="-80.692" cy="137.487" r="13.663" fill="Black" stroke="Black" />
<circle cx="-439.381" cy="-399.996" r="11.19" fill="Black" stroke="Black" />
<circle cx="394.286" cy="473.944" r="25.792" fill="Black" stroke="Black" />
<circle cx="-410.443" cy="-12.242" r="20.71" fill="Black" stroke="Black" />
<circle cx="-285.133" cy="-273.097" r="10.62" fill="Black" stroke="Black" />
<circle cx="-350.383" cy="-492.637" r="20.295" fill="Black" stroke="Black" />
<circle cx="-101.287" cy="-353.076" r="9.943" fill="Black" stroke="Black" />
<circle cx="469.567" cy="107.413" r="21.633" fill="Black" stroke="Black" />
<circle cx="-300.795" cy="-25.595" r="12.762" fill="Black" stroke="Black" />
<circle cx="445.112" cy="-134.854" r="22.928" fill="Black" stroke="Black" />
<circle cx="142.189" cy="453.543" r="23.358" fill="Black" stroke="Black" />
<circle cx="161.973" cy="200.13" r="17.818" fill="Black" stroke="Black" />
<circle cx="-27.468" cy="476.664" r="9.343" fill="Black" stroke="Black" />
<circle cx="-453.458" cy="-291.797" r="15.844" fill="Black" stroke="Black" />
<circle cx="-161.537" cy="476.679" r="22.862" fill="Black" stroke="Black" />
<circle cx="463.708" cy="-238.047" r="8.346" fill="Black" stroke="Black" />
<circle cx="-430.771" cy="305.86" r="10.816" fill="Black" stroke="Black" />
<circle cx="-368.436" cy="150.517" r="22.764" fill="Black" stroke="Black" />
<circle cx="217.356" cy="94.848" r="27.525" fill="Black" stroke="Black" />
<circle cx="288.161" cy="497.372" r="9.874" fill="Black" stroke="Black" />
<circle cx="-211.861" cy="288.11" r="18.422" fill="Black" stroke="Black" />
<circle cx="-57.97" cy="34.67" r="18.013" fill="Black" stroke="Black" />
<circle cx="-310.308" cy="248.085" r="10.009" fill="Black" stroke="Black" />
<circle cx="-215.947" cy="-380.294" r="22.018" fill="Black" stroke="Black" />
<circle cx="39.754" cy="223.623" r="23.391" fill="Black" stroke="Black" />
<circle cx="99.171" cy="-80.776" r="14.531" fill="Black" stroke="Black" />
<circle cx="-222.75" cy="-305.515" r="7.873" fill="Black" stroke="Black" />
<circle cx="320.627" cy="123.792" r="17.295" fill="Black" stroke="Black" />
<circle cx="470.371" cy="-397.197" r="9.206" fill="Black" stroke="Black" />
<circle cx="243.285" cy="-97.354" r="20.326" fill="Black" stroke="Black" />
<circle cx="397.408" cy="195.394" r="23.445" fill="Black" stroke="Black" />
<circle cx="120.11" cy="-338.393" r="15.885" fill="Black" stroke="Black" />
<circle cx="-149.857" cy="182.001" r="16.464" fill="Black" stroke="Black" />
<circle cx="-331.16" cy="-197.631" r="15.846" fill="Black" stroke="Black" />
<circle cx="-437.729" cy="110.062" r="15.29" fill="Black" stroke="Black" />
<circle cx="-487.64" cy="40.083" r="12.546" fill="Black" stroke="Black" />
<circle cx="-324.223" cy="483.909" r="17.943" fill="Black" stroke="Black" />
<circle cx="-340.153" cy="-115.642" r="28.382" fill="Black" stroke="Black" />
<circle cx="33.462" cy="415.832" r="14.084" fill="Black" stroke="Black" />
<circle cx="-3.71" cy="-486.538" r="16.094" fill="Black" stroke="Black" />
<circle cx="159.225" cy="-33.74" r="17.57" fill="Black" stroke="Black" />
<circle cx="440.724" cy="-41.068" r="13.183" fill="Black" stroke="Black" />
<circle cx="170.428" cy="-157.966" r="21.967" fill="Black" stroke="Black" />
<circle cx="383.71" cy="364.316" r="21.325" fill="Black" stroke="Black" />
<circle cx="45.465" cy="-268.348" r="13.761" fill="Black" stroke="Black" />
<circle cx="-396.363" cy="437.991" r="14.6" fill="Black" stroke="Black" />
<circle cx="102.597" cy="136.279" r="10.164" fill="Black" stroke="Black" />
<circle cx="-3.04" cy="321.144" r="11.343" fill="Black" stroke="Black" />
<circle cx="-305.376" cy="-363.526" r="20.435" fill="Black" stroke="Black" />
<circle cx="299.171" cy="417.759" r="23.535" fill="Black" stroke="Black" />
<circle cx="271.568" cy="-253.278" r="15.258" fill="Black" stroke="Black" />
<circle cx="-348.183" cy="325.45" r="10.457" fill="Black" stroke="Black" />
<circle cx="-172.848" cy="54.732" r="24.771" fill="Black" stroke="Black" />
<circle cx="155.144" cy="47.653" r="14.864" fill="Black" stroke="Black" />
<circle cx="378.476" cy="-166.477" r="17.592" fill="Black" stroke="Black" />
<circle cx="-100.937" cy="-64.881" r="27.363" fill="Black" stroke="Black" />
<circle cx="387.43" cy="47.855" r="16.212" fill="Black" stroke="Black" />
<circle cx="-373.414" cy="47.657" r="7.873" fill="Black" stroke="Black" />
<circle cx="34.354" cy="-370.209" r="9.701" fill="Black" stroke="Black" />
<circle cx="-258.645" cy="-164.399" r="24.168" fill="Black" stroke="Black" />
<circle cx="-104.947" cy="-498.767" r="8.08" fill="Black" stroke="Black" />
<circle cx="395.704" cy="-233.557" r="19.626" fill="Black" stroke="Black" />
<circle cx="-248.537" cy="400.613" r="14.182" fill="Black" stroke="Black" />
<circle cx="-29.231" cy="-340.226" r="17.342" fill="Black" stroke="Black" />
<circle cx="-245.041" cy="28.389" r="11.555" fill="Black" stroke="Black" />
<circle cx="-402.022" cy="-239.563" r="23.46" fill="Black" stroke="Black" />
<circle cx="162.623" cy="122.807" r="18.924" fill="Black" stroke="Black" />
<circle cx="197.854" cy="-70.149" r="21.417" fill="Black" stroke="Black" />
<circle cx="34.605" cy="-138.191" r="13.439" fill="Black" stroke="Black" />
<circle cx="198.523" cy="-496.473" r="8.182" fill="Black" stroke="Black" />
<circle cx="120.653" cy="-413.646" r="15.073" fill="Black" stroke="Black" />
<circle cx="475.163" cy="344.743" r="12.137" fill="Black" stroke="Black" />
<circle cx="188.447" cy="267.486" r="13.171" fill="Black" stroke="Black" />
<circle cx="250.266" cy="261.94" r="9.167" fill="Black" stroke="Black" />
<circle cx="405.902" cy="-418.221" r="28.03" fill="Black" stroke="Black" />
<circle cx="473.967" cy="176.762" r="7.843" fill="Black" stroke="Black" />
<circle cx="134.888" cy="386.809" r="22.617" fill="Black" stroke="Black" />
<circle cx="-366.256" cy="206.467" r="16.806" fill="Black" stroke="Black" />
<circle cx="85.88" cy="-167.652" r="10.445" fill="Black" stroke="Black" />
<circle cx="332.712" cy="-83.674" r="23.828" fill="Black" stroke="Black" />
<circle cx="-463.567" cy="-44.84" r="15.846" fill="Black" stroke="Black" />
<circle cx="-220.275" cy="148.506" r="25.58" fill="Black" stroke="Black" />
<circle cx="-270.737" cy="326.937" r="9.792" fill="Black" stroke="Black" />
<circle cx="244.683" cy="-335.079" r="19.732" fill="Black" stroke="Black" />
<circle cx="-117.435" cy="-411.315" r="12.161" fill="Black" stroke="Black" />
<circle cx="337.224" cy="315.179" r="12.097" fill="Black" stroke="Black" />
<circle cx="83.02" cy="198.288" r="18.43" fill="Black" stroke="Black" />
<circle cx="333.493" cy="-453.784" r="27.339" fill="Black" stroke="Black" />
<circle cx="-125.596" cy="-260.323" r="14.041" fill="Black" stroke="Black" />
<circle cx="-431.874" cy="377.827" r="21.138" fill="Black" stroke="Black" />
<circle cx="113.891" cy="270.581" r="10.856" fill="Black" stroke="Black" />
<circle cx="404.806" cy="312.528" r="15.651" fill="Black" stroke="Black" />
<circle cx="107.395" cy="-475.358" r="13.144" fill="Black" stroke="Black" />
<circle cx="231.37" cy="-440.922" r="7.631" fill="Black" stroke="Black" />
<circle cx="481.288" cy="19.021" r="12.826" fill="Black" stroke="Black" />
<circle cx="224.54" cy="308.64" r="22.139" fill="Black" stroke="Black" />
<circle cx="-228.826" cy="229.27" r="7.876" fill="Black" stroke="Black" />
<circle cx="-477.744" cy="244.584" r="22.936" fill="Black" stroke="Black" />
<circle cx="-193.567" cy="-101.924" r="18.488" fill="Black" stroke="Black" />
<circle cx="-388.749" cy="-317.126" r="7.5" fill="Black" stroke="Black" />
<circle cx="385.203" cy="-0.485" r="18.395" fill="Black" stroke="Black" />
<circle cx="-23.806" cy="-31.947" r="20.077" fill="Black" stroke="Black" />
<circle cx="491.409" cy="-164.503" r="20.746" fill="Black" stroke="Black" />
<circle cx="-131.333" cy="135.034" r="13.03" fill="Black" stroke="Black" />
<circle cx="-65.28" cy="305.324" r="22.585" fill="Black" stroke="Black" />
<circle cx="-78.249" cy="-281.592" r="23.486" fill="Black" stroke="Black" />
<circle cx="-123.388" cy="60.777" r="23.833" fill="Black" stroke="Black" />
<circle cx="-288.375" cy="146.618" r="9.394" fill="Black" stroke="Black" />
<circle cx="391.538" cy="-87.368" r="8.353" fill="Black" stroke="Black" />
<circle cx="284.964" cy="-420.371" r="16.029" fill="Black" stroke="Black" />
<circle cx="-333.908" cy="-315.912" r="24.242" fill="Black" stroke="Black" />
<circle cx="-7.136" cy="186.196" r="12.618" fill="Black" stroke="Black" />
<circle cx="178.477" cy="359.268" r="9.515" fill="Black" stroke="Black" />
<circle cx="-294.092" cy="-443.244" r="7.716" fill="Black" stroke="Black" />
<circle cx="-19.667" cy="-402.065" r="19.921" fill="Black" stroke="Black" />
<circle cx="-297.24" cy="434.231" r="11.909" fill="Black" stroke="Black" />
<circle cx="353.638" cy="-272.777" r="8.056" fill="Black" stroke="Black" />
<circle cx="21.168" cy="138.088" r="7.517" fill="Black" stroke="Black" />
<circle cx="-315.267" cy="41.144" r="24.251" fill="Black" stroke="Black" />
<circle cx="-152.271" cy="-361.27" r="13.138" fill="Black" stroke="Black" />
<circle cx="-248.59" cy="-406.319" r="15.006" fill="Black" stroke="Black" />
<circle cx="-5.907" cy="42.047" r="18.178" fill="Black" stroke="Black" />
<circle cx="-100.921" cy="-185.419" r="12.574" fill="Black" stroke="Black" />
<circle cx="460.049" cy="-335.988" r="22.563" fill="Black" stroke="Black" />
<circle cx="-170.765" cy="362.167" r="9.959" fill="Black" stroke="Black" />
<circle cx="-343.29" cy="100.893" r="10.834" fill="Black" stroke="Black" />
<circle cx="-201.109" cy="19.032" r="15.716" fill="Black" stroke="Black" />
<circle cx="101.991" cy="-265.18" r="26.475" fill="Black" stroke="Black" />
<circle cx="-135.249" cy="-109.061" r="18.403" fill="Black" stroke="Black" />
<circle cx="337.827" cy="-214.624" r="24.421" fill="Black" stroke="Black" />
<circle cx="-68.245" cy="-417.037" r="10.058" fill="Black" stroke="Black" />
<circle cx="479.587" cy="-485.899" r="20.104" fill="Black" stroke="Black" />
<circle cx="-497.668" cy="472.65" r="11.753" fill="Black" stroke="Black" />
<circle cx="278.299" cy="-297.932" r="27.031" fill="Black" stroke="Black" />
<circle cx="-106.631" cy="433.66" r="13.298" fill="Black" stroke="Black" />
<circle cx="-25.59" cy="399.714" r="7.913" fill="Black" stroke="Black" />
<circle cx="248.127" cy="-23.375" r="12.327" fill="Black" stroke="Black" />
<circle cx="440.61" cy="213.192" r="14.493" fill="Black" stroke="Black" />
<circle cx="229.84" cy="159.247" r="14.813" fill="Black" stroke="Black" />
<circle cx="80.221" cy="419.756" r="8.851" fill="Black" stroke="Black" />
<circle cx="-343.117" cy="419.03" r="13.459" fill="Black" stroke="Black" />
<circle cx="344.904" cy="-117.364" r="17.224" fill="Black" stroke="Black" />
<circle cx="348.006" cy="246.641" r="15.813" fill="Black" stroke="Black" />
<circle cx="-498.378" cy="309.768" r="26.929" fill="Black" stroke="Black" />
<circle cx="458.369" cy="-195.098" r="8.829" fill="Black" stroke="Black" />
<circle cx="334.318" cy="475.656" r="10.551" fill="Black" stroke="Black" />
<circle cx="-349.825" cy="-416.231" r="11.522" fill="Black" stroke="Black" />
<circle cx="-264.175" cy="-370.527" r="23.909" fill="Black" stroke="Black" />
<circle cx="-385.38" cy="-171.897" r="23.221" fill="Black" stroke="Black" />
<circle cx="-151.541" cy="250.389" r="11.227" fill="Black" stroke="Black" />
<circle cx="-226.674" cy="468.254" r="23.695" fill="Black" stroke="Black" />
<circle cx="-210.596" cy="-244.706" r="8.771" fill="Black" stroke="Black" />
<circle cx="459.892" cy="142.161" r="10.09" fill="Black" stroke="Black" />
<circle cx="496.842" cy="269.363" r="19.546" fill="Black" stroke="Black" />
<circle cx="-182.186" cy="424.337" r="11.491" fill="Black" stroke="Black" />
<circle cx="70.77" cy="294.693" r="18.524" fill="Black" stroke="Black" />
<circle cx="334.974" cy="-42.072" r="17.024" fill="Black" stroke="Black" />
<circle cx="-489.838" cy="-114.691" r="11.067" fill="Black" stroke="Black" />
<circle cx="255.695" cy="-384.787" r="22.992" fill="Black" stroke="Black" />
<circle cx="-428.679" cy="495.764" r="18.778" fill="Black" stroke="Black" />
<circle cx="-64.298" cy="-487.659" r="25.603" fill="Black" stroke="Black" />
<circle cx="73.342" cy="-223.311" r="8.281" fill="Black" stroke="Black" />
<circle cx="-275.735" cy="-227.412" r="20.248" fill="Black" stroke="Black" />
<circle cx="300.203" cy="261.273" r="22.813" fill="Black" stroke="Black" />
<circle cx="-117.082" cy="-136.068" r="23.1" fill="Black" stroke="Black" />
<circle cx="-498.564" cy="-172.486" r="10.808" fill="Black" stroke="Black" />
<circle cx="-13.622" cy="-74.025" r="17.29" fill="Black" stroke="Black" />
<circle cx="356.533" cy="158.284" r="21.659" fill="Black" stroke="Black" />
<circle cx="52.473" cy="474.233" r="13.759" fill="Black" stroke="Black" />
<circle cx="393.748" cy="127.23" r="21.981" fill="Black" stroke="Black" />
<circle cx="-39.701" cy="91.992" r="20.006" fill="Black" stroke="Black" />
<circle cx="-391.589" cy="-125.507" r="16.181" fill="Black" stroke="Black" />
<circle cx="314.051" cy="55.832" r="12.04" fill="Black" stroke="Black" />
<circle cx="-67.9" cy="257.802" r="12.308" fill="Black" stroke="Black" />
<circle cx="-278.931" cy="286.708" r="22.76" fill="Black" stroke="Black" />
<circle cx="-377.974" cy="-389.139" r="10.083" fill="Black" stroke="Black" />
<circle cx="-440.028" cy="55.382" r="15.127" fill="Black" stroke="Black" />
<circle cx="183.012" cy="-350.9" r="8.991" fill="Black" stroke="Black" />
<circle cx="78.638" cy="-35.838" r="8.988" fill="Black" stroke="Black" />
<circle cx="-332.451" cy="186.122" r="12.52" fill="Black" stroke="Black" />
<circle cx="98.152" cy="489.331" r="28.498" fill="Black" stroke="Black" />
<circle cx="53.421" cy="359.166" r="8.462" fill="Black" stroke="Black" />
<circle cx="295.478" cy="-135.916" r="13.667" fill="Black" stroke="Black" />
<circle cx="-253.584" cy="-35.403" r="10.915" fill="Black" stroke="Black" />
<circle cx="-196.933" cy="85.295" r="18.204" fill="Black" stroke="Black" />
<circle cx="310.643" cy="-336.092" r="10.192" fill="Black" stroke="Black" />
<circle cx="-474.007" cy="-344.638" r="8.407" fill="Black" stroke="Black" />
<circle cx="-30.893" cy="-437.708" r="19.219" fill="Black" stroke="Black" />
<circle cx="-211.828" cy="188.96" r="13.029" fill="Black" stroke="Black" />
<circle cx="269.705" cy="445.617" r="12.307" fill="Black" stroke="Black" />
<circle cx="-90.512" cy="490.959" r="17.481" fill="Black" stroke="Black" />
<circle cx="428.23" cy="56.715" r="21.058" fill="Black" stroke="Black" />
<circle cx="204.493" cy="404.47" r="8.018" fill="Black" stroke="Black" />
<circle cx="474.522" cy="302.885" r="9.957" fill="Black" stroke="Black" />
<circle cx="224.46" cy="-360.377" r="13.101" fill="Black" stroke="Black" />
<circle cx="-50.048" cy="212.972" r="9.384" fill="Black" stroke="Black" />
<circle cx="-335.09" cy="-377.318" r="24.123" fill="Black" stroke="Black" />
<circle cx="237.325" cy="-153.124" r="19.189" fill="Black" stroke="Black" />
<circle cx="433.762" cy="-390.341" r="22.613" fill="Black" stroke="Black" />
<circle cx="-16.694" cy="-216.812" r="17.868" fill="Black" stroke="Black" />
<circle cx="-5.565" cy="-154.947" r="22.586" fill="Black" stroke="Black" />
<circle cx="115.048" cy="65.968" r="13.423" fill="Black" stroke="Black" />
<circle cx="145.072" cy="8.401" r="11.167" fill="Black" stroke="Black" />
<circle cx="40.493" cy="-175.931" r="19.035" fill="Black" stroke="Black" />
<circle cx="-316.511" cy="-88.272" r="20.786" fill="Black" stroke="Black" />
<circle cx="-409.711" cy="80.5" r="24.235" fill="Black" stroke="Black" />
<circle cx="-270.159" cy="-121.192" r="13.903" fill="Black" stroke="Black" />
<circle cx="31.289" cy="-424.583" r="19.216" fill="Black" stroke="Black" />
<circle cx="-462.951" cy="318.763" r="11.475" fill="Black" stroke="Black" />
<circle cx="-495.818" cy="126.802" r="19.417" fill="Black" stroke="Black" />
<circle cx="208.16" cy="-313.623" r="22.149" fill="Black" stroke="Black" />
<circle cx="284.886" cy="-55.311" r="9.315" fill="Black" stroke="Black" />
<circle cx="486.694" cy="-122.787" r="24.075" fill="Black" stroke="Black" />
<circle cx="423.079" cy="-4.889" r="15.925" fill="Black" stroke="Black" />
<circle cx="122.079" cy="-192.73" r="15.465" fill="Black" stroke="Black" />
<circle cx="-6.279" cy="-285.506" r="10.04" fill="Black" stroke="Black" />
<circle cx="132.726" cy="219.463" r="17.035" fill="Black" stroke="Black" />
<circle cx="-333.925" cy="363.831" r="12.924" fill="Black" stroke="Black" />
<circle cx="243.85" cy="72.297" r="18.985" fill="Black" stroke="Black" />
<circle cx="367.966" cy="-315.373" r="24.172" fill="Black" stroke="Black" />
<circle cx="310.876" cy="18.054" r="25.379" fill="Black" stroke="Black" />
<circle cx="43.235" cy="-81.269" r="9.535" fill="Black" stroke="Black" />
<circle cx="-72.257" cy="-19.728" r="16.146" fill="Black" stroke="Black" />
<circle cx="495.417" cy="82.812" r="10.032" fill="Black" stroke="Black" />
<circle cx="147.023" cy="-97.019" r="11.164" fill="Black" stroke="Black" />
<circle cx="-256.934" cy="-335.184" r="12.364" fill="Black" stroke="Black" />
<circle cx="-211.254" cy="-181.612" r="11.875" fill="Black" stroke="Black" />
<circle cx="158.008" cy="318.644" r="8.107" fill="Black" stroke="Black" />
<circle cx="195.095" cy="467.446" r="8.994" fill="Black" stroke="Black" />
<circle cx="-430.127" cy="-104.751" r="9.915" fill="Black" stroke="Black" />
<circle cx="-119.574" cy="202.886" r="25.445" fill="Black" stroke="Black" />
<circle cx="352.848" cy="420.097" r="12.627" fill="Black" stroke="Black" />
<circle cx="30.482" cy="292.628" r="19.631" fill="Black" stroke="Black" />
<circle cx="471.048" cy="-48.874" r="9.652" fill="Black" stroke="Black" />
<circle cx="475.254" cy="399.807" r="23.609" fill="Black" stroke="Black" />
<circle cx="23.461" cy="-323.738" r="8.84" fill="Black" stroke="Black" />
<circle cx="154.099" cy="245.171" r="24.077" fill="Black" stroke="Black" />
<circle cx="-230.745" cy="-486.274" r="12.934" fill="Black" stroke="Black" />
<circle cx="-140.412" cy="-313.81" r="9.507" fill="Black" stroke="Black" />
<circle cx="-424.535" cy="238.944" r="9.836" fill="Black" stroke="Black" />
<circle cx="-375.766" cy="368.63" r="9.44" fill="Black" stroke="Black" />
<circle cx="252.102" cy="216.621" r="18.48" fill="Black" stroke="Black" />
<circle cx="-341.72" cy="-40.794" r="12.893" fill="Black" stroke="Black" />
<circle cx="437.979" cy="331.07" r="13.572" fill="Black" stroke="Black" />
<circle cx="-274.193" cy="495.422" r="11.955" fill="Black" stroke="Black" />
<circle cx="321.418" cy="214.636" r="11.129" fill="Black" stroke="Black" />
<circle cx="45.535" cy="182.323" r="16.627" fill="Black" stroke="Black" />
<circle cx="-260.611" cy="256.412" r="12.176" fill="Black" stroke="Black" />
<circle cx="365.44" cy="288.625" r="7.737" fill="Black" stroke="Black" />
<circle cx="208.896" cy="205.863" r="22.402" fill="Black" stroke="Black" />
<circle cx="-4.751" cy="354.719" r="15.698" fill="Black" stroke="Black" />
<circle cx="-101.189" cy="24.442" r="13.381" fill="Black" stroke="Black" />
<circle cx="300.441" cy="308.321" r="12.232" fill="Black" stroke="Black" />
<circle cx="-338.937" cy="247.605" r="8.509" fill="Black" stroke="Black" />
<circle cx="-334.104" cy="-252.858" r="11.416" fill="Black" stroke="Black" />
<circle cx="186.796" cy="-435.041" r="26.488" fill="Black" stroke="Black" />
<circle cx="271.38" cy="105.847" r="15.415" fill="Black" stroke="Black" />
<circle cx="431.73" cy="-87.891" r="20.804" fill="Black" stroke="Black" />
<circle cx="351.429" cy="32.592" r="17.682" fill="Black" stroke="Black" />
<circle cx="-76.008" cy="84.915" r="19.953" fill="Black" stroke="Black" />
<circle cx="-120.776" cy="99.407" r="24.766" fill="Black" stroke="Black" />
<circle cx="-48.848" cy="165.416" r="20.057" fill="Black" stroke="Black" />
<circle cx="-173.98" cy="121.42" r="18.451" fill="Black" stroke="Black" />
<circle cx="-311.818" cy="-219.948" r="7.941" fill="Black" stroke="Black" />
<circle cx="134.139" cy="-138.232" r="19.977" fill="Black" stroke="Black" />
<circle cx="147.411" cy="-313.387" r="21.323" fill="Black" stroke="Black" />
<circle cx="-175.576" cy="-428.456" r="16.937" fill="Black" stroke="Black" />
<circle cx="-6.235" cy="426.397" r="13.921" fill="Black" stroke="Black" />
<circle cx="370.621" cy="-470.139" r="22.404" fill="Black" stroke="Black" />
<circle cx="268.157" cy="-213.411" r="8.183" fill="Black" stroke="Black" />
<circle cx="-303.78" cy="-165.944" r="22.891" fill="Black" stroke="Black" />
<circle cx="-28.176" cy="280.286" r="10.355" fill="Black" stroke="Black" />
<circle cx="181.593" cy="-112.74" r="20.519" fill="Black" stroke="Black" />
<circle cx="-183.432" cy="222.97" r="10.378" fill="Black" stroke="Black" />
<circle cx="103.959" cy="368.392" r="18.7" fill="Black" stroke="Black" />
<circle cx="-374.017" cy="252.275" r="16.493" fill="Black" stroke="Black" />
<circle cx="8.16" cy="-388.374" r="16.287" fill="Black" stroke="Black" />
<circle cx="341.326" cy="85.964" r="10.829" fill="Black" stroke="Black" />
<circle cx="-480.602" cy="-261.262" r="11.054" fill="Black" stroke="Black" />
<circle cx="-355.709" cy="-7.647" r="19.385" fill="Black" stroke="Black" />
<circle cx="143.206" cy="172.886" r="11.849" fill="Black" stroke="Black" />
<circle cx="392.969" cy="434.997" r="18.007" fill="Black" stroke="Black" />
<circle cx="-417.463" cy="170.789" r="8.649" fill="Black" stroke="Black" />
<circle cx="-389.29" cy="334.73" r="17.466" fill="Black" stroke="Black" />
<circle cx="-65.223" cy="-147.091" r="9.597" fill="Black" stroke="Black" />
<circle cx="-212.19" cy="369.914" r="19.382" fill="Black" stroke="Black" />
<circle cx="183.021" cy="-274.592" r="19.859" fill="Black" stroke="Black" />
<circle cx="-175.596" cy="-379.406" r="19.82" fill="Black" stroke="Black" />
<circle cx="-418.503" cy="-359.704" r="9.107" fill="Black" stroke="Black" />
<circle cx="340.751" cy="-5.936" r="18.465" fill="Black" stroke="Black" />
<circle cx="-288.75" cy="102.943" r="8.457" fill="Black" stroke="Black" />
<circle cx="249.125" cy="-125.436" r="26.867" fill="Black" stroke="Black" />
<circle cx="-392.281" cy="296.452" r="24.113" fill="Black" stroke="Black" />
<circle cx="157.697" cy="497.422" r="12.712" fill="Black" stroke="Black" />
<circle cx="-488.604" cy="211.353" r="23.925" fill="Black" stroke="Black" />
<circle cx="405.671" cy="233.617" r="15.616" fill="Black" stroke="Black" />
<circle cx="409.023" cy="-136.338" r="13.401" fill="Black" stroke="Black" />
<circle cx="-444.262" cy="-197.229" r="11.278" fill="Black" stroke="Black" />
<circle cx="359.779" cy="331.073" r="19.061" fill="Black" stroke="Black" />
<circle cx="-485.492" cy="-13.298" r="23.103" fill="Black" stroke="Black" />
<circle cx="102.639" cy="172.792" r="9.518" fill="Black" stroke="Black" />
<circle cx="431.019" cy="-275.871" r="11.778" fill="Black" stroke="Black" />
<circle cx="-314.645" cy="304.002" r="9.024" fill="Black" stroke="Black" />
<circle cx="-143.219" cy="-164.474" r="18.637" fill="Black" stroke="Black" />
<circle cx="8.897" cy="-109.424" r="22.816" fill="Black" stroke="Black" />
<circle cx="-156.408" cy="26.103" r="17.815" fill="Black" stroke="Black" />
<circle cx="213.179" cy="343.489" r="20.832" fill="Black" stroke="Black" />
<circle cx="463.003" cy="254.177" r="25.155" fill="Black" stroke="Black" />
<circle cx="-135.246" cy="-218.957" r="12.467" fill="Black" stroke="Black" />
<circle cx="-166.906" cy="295.332" r="8.536" fill="Black" stroke="Black" />
<circle cx="-230.727" cy="113.72" r="22.229" fill="Black" stroke="Black" />
<circle cx="-110.086" cy="177.103" r="13.971" fill="Black" stroke="Black" />
<circle cx="-327.109" cy="-458.195" r="14.527" fill="Black" stroke="Black" />
<circle cx="-132.829" cy="291.862" r="7.735" fill="Black" stroke="Black" />
<circle cx="-223.411" cy="425.892" r="8.417" fill="Black" stroke="Black" />
<circle cx="495.842" cy="-302.456" r="10.474" fill="Black" stroke="Black" />
<circle cx="384.749" cy="83.034" r="11.118" fill="Black" stroke="Black" />
<circle cx="-301.762" cy="-496.267" r="17.004" fill="Black" stroke="Black" />
<circle cx="-295.195" cy="-317.384" r="11.697" fill="Black" stroke="Black" />
<circle cx="-499.073" cy="-72.011" r="23.612" fill="Black" stroke="Black" />
<circle cx="329.102" cy="-414.575" r="17.861" fill="Black" stroke="Black" />
<circle cx="-71.922" cy="370.073" r="11.162" fill="Black" stroke="Black" />
<circle cx="-497.386" cy="78.391" r="9.688" fill="Black" stroke="Black" />
<circle cx="425.157" cy="386.645" r="15.648" fill="Black" stroke="Black" />
<circle cx="-291.216" cy="55.171" r="23.326" fill="Black" stroke="Black" />
<circle cx="19.181" cy="340.369" r="17.501" fill="Black" stroke="Black" />
<circle cx="-292.35" cy="15.051" r="25.045" fill="Black" stroke="Black" />
<circle cx="348.155" cy="-335.512" r="18.373" fill="Black" stroke="Black" />
<circle cx="10.553" cy="-451.898" r="10.592" fill="Black" stroke="Black" />
<circle cx="-354.462" cy="465.573" r="23.512" fill="Black" stroke="Black" />
<circle cx="-129.218" cy="487.182" r="24.323" fill="Black" stroke="Black" />
<circle cx="301.04" cy="456.932" r="14.457" fill="Black" stroke="Black" />
<circle cx="-477.738" cy="100.641" r="17.009" fill="Black" stroke="Black" />
<circle cx="-152.969" cy="83.814" r="23.421" fill="Black" stroke="Black" />
<circle cx="-416.056" cy="-270.894" r="21.679" fill="Black" stroke="Black" />
<circle cx="287.844" cy="380.877" r="19.163" fill="Black" stroke="Black" />
<circle cx="-47.816" cy="-195.076" r="15.07" fill="Black" stroke="Black" />
<circle cx="-171.72" cy="157.388" r="14.308" fill="Black" stroke="Black" />
<circle cx="77.347" cy="-436.065" r="18.65" fill="Black" stroke="Black" />
<circle cx="-235.921" cy="-200.738" r="18.255" fill="Black" stroke="Black" />
<circle cx="-369.603" cy="-92.068" r="7.809" fill="Black" stroke="Black" />
<circle cx="-148.662" cy="-396.758" r="10.356" fill="Black" stroke="Black" />
<circle cx="-125.778" cy="-41.347" r="12.859" fill="Black" stroke="Black" />
<circle cx="33.298" cy="-47.659" r="11.754" fill="Black" stroke="Black" />
<circle cx="-472.055" cy="-376.822" r="20.684" fill="Black" stroke="Black" />
<circle cx="159.246" cy="-477.525" r="8.77" fill="Black" stroke="Black" />
<circle cx="-55.836" cy="-374.719" r="25.131" fill="Black" stroke="Black" />
<circle cx="-366.378" cy="-343.233" r="26.823" fill="Black" stroke="Black" />
<circle cx="228.236" cy="3.269" r="8.32" fill="Black" stroke="Black" />
<circle cx="103.781" cy="-13.01" r="8.542" fill="Black" stroke="Black" />
<circle cx="76.934" cy="-384.842" r="9.337" fill="Black" stroke="Black" />
<circle cx="299.839" cy="-10.018" r="27.843" fill="Black" stroke="Black" />
<circle cx="131.049" cy="299.476" r="16.512" fill="Black" stroke="Black" />
<circle cx="-92.185" cy="-307.983" r="11.248" fill="Black" stroke="Black" />
<circle cx="446.526" cy="-486.466" r="18.574" fill="Black" stroke="Black" />
<circle cx="-1.337" cy="231.081" r="9.093" fill="Black" stroke="Black" />
<circle cx="-431.632" cy="442.685" r="16.247" fill="Black" stroke="Black" />
<circle cx="-272.727" cy="366.752" r="15.537" fill="Black" stroke="Black" />
<circle cx="329.233" cy="265.988" r="20.812" fill="Black" stroke="Black" />
<circle cx="102.746" cy="466.117" r="26.102" fill="Black" stroke="Black" />
<circle cx="129.267" cy="-165.183" r="23.727" fill="Black" stroke="Black" />
<circle cx="321.372" cy="-300.134" r="17.94" fill="Black" stroke="Black" />
<circle cx="151.077" cy="-192.342" r="11.292" fill="Black" stroke="Black" />
<circle cx="276.717" cy="288.966" r="19.349" fill="Black" stroke="Black" />
<circle cx="270.936" cy="-366.851" r="22.978" fill="Black" stroke="Black" />
<circle cx="-160.59" cy="407.175" r="19.64" fill="Black" stroke="Black" />
<circle cx="10.363" cy="101.351" r="15.896" fill="Black" stroke="Black" />
<circle cx="-65.356" cy="-446.693" r="9.655" fill="Black" stroke="Black" />
<circle cx="156.072" cy="-386.094" r="8.807" fill="Black" stroke="Black" />
<circle cx="18.789" cy="496.573" r="16.096" fill="Black" stroke="Black" />
<circle cx="304.236" cy="-394.032" r="11.005" fill="Black" stroke="Black" />
<circle cx="469.919" cy="-458.315" r="22.829" fill="Black" stroke="Black" />
<circle cx="346.259" cy="380.218" r="14.873" fill="Black" stroke="Black" />
<circle cx="-464.044" cy="490.62" r="22.147" fill="Black" stroke="Black" />
<circle cx="313.864" cy="347.926" r="9.025" fill="Black" stroke="Black" />
<circle cx="-79.48" cy="226.841" r="16.432" fill="Black" stroke="Black" />
<circle cx="-263.032" cy="128.458" r="13.904" fill="Black" stroke="Black" />
<circle cx="319.102" cy="176.306" r="10.804" fill="Black" stroke="Black" />
<circle cx="499.269" cy="-100.857" r="16.782" fill="Black" stroke="Black" />
<circle cx="-100.273" cy="115.342" r="19.216" fill="Black" stroke="Black" />
<circle cx="116.749" cy="-442.491" r="24.134" fill="Black" stroke="Black" />
<circle cx="28.236" cy="-478.648" r="10.11" fill="Black" stroke="Black" />
<circle cx="-30.018" cy="-174.525" r="22.639" fill="Black" stroke="Black" />
<circle cx="-214.182" cy="-447.567" r="21.512" fill="Black" stroke="Black" />
<circle cx="-475.763" cy="360.318" r="7.522" fill="Black" stroke="Black" />
<circle cx="-327.204" cy="76.734" r="17.72" fill="Black" stroke="Black" />
<circle cx="-36.938" cy="365.696" r="7.773" fill="Black" stroke="Black" />
<circle cx="-432.192" cy="12.046" r="15.409" fill="Black" stroke="Black" />
<circle cx="207.874" cy="-120.097" r="19.353" fill="Black" stroke="Black" />
<circle cx="479.671" cy="217.921" r="19.497" fill="Black" stroke="Black" />
<circle cx="-268.112" cy="435.597" r="12.228" fill="Black" stroke="Black" />
<circle cx="-163.079" cy="-91.068" r="18.812" fill="Black" stroke="Black" />
<circle cx="-251.148" cy="156.736" r="8.577" fill="Black" stroke="Black" />
<circle cx="-203.52" cy="55.787" r="16.607" fill="Black" stroke="Black" />
<circle cx="303.029" cy="-211.926" r="12.918" fill="Black" stroke="Black" />
<circle cx="-123.987" cy="407.868" r="20.994" fill="Black" stroke="Black" />
<circle cx="371.556" cy="-402.167" r="10.138" fill="Black" stroke="Black" />
<circle cx="-285.991" cy="-398.573" r="18.454" fill="Black" stroke="Black" />
<circle cx="400.922" cy="-373.056" r="10.014" fill="Black" stroke="Black" />
<circle cx="49.967" cy="132.037" r="10.475" fill="Black" stroke="Black" />
<circle cx="355.571" cy="-437.075" r="24.513" fill="Black" stroke="Black" />
<circle cx="420.758" cy="290.923" r="20.857" fill="Black" stroke="Black" />
<circle cx="9.252" cy="-226.34" r="17.815" fill="Black" stroke="Black" />
<circle cx="-263.261" cy="-2.267" r="21.35" fill="Black" stroke="Black" />
<circle cx="493.651" cy="-329.811" r="19.264" fill="Black" stroke="Black" />
<circle cx="441.763" cy="-308.889" r="12.145" fill="Black" stroke="Black" />
<circle cx="423.041" cy="100.071" r="24.21" fill="Black" stroke="Black" />
<circle cx="288.636" cy="40.435" r="9.356" fill="Black" stroke="Black" />
<circle cx="-234.462" cy="337.764" r="20.728" fill="Black" stroke="Black" />
<circle cx="411.006" cy="-299.985" r="15.627" fill="Black" stroke="Black" />
<circle cx="-51.913" cy="-46.482" r="17.25" fill="Black" stroke="Black" />
<circle cx="488.552" cy="144.453" r="19.089" fill="Black" stroke="Black" />
<circle cx="-451.099" cy="-236.034" r="15.338" fill="Black" stroke="Black" />
<circle cx="-499.465" cy="442.871" r="16.113" fill="Black" stroke="Black" />
<circle cx="133.633" cy="480.182" r="19.795" fill="Black" stroke="Black" />
<circle cx="218.044" cy="499.681" r="11.805" fill="Black" stroke="Black" />
<circle cx="156.524" cy="-427.691" r="21.426" fill="Black" stroke="Black" />
<circle cx="-374.684" cy="173.379" r="25.59" fill="Black" stroke="Black" />
<circle cx="439.661" cy="-245.914" r="15.153" fill="Black" stroke="Black" />
<circle cx="292.999" cy="-91.424" r="7.787" fill="Black" stroke="Black" />
<circle cx="-227.765" cy="-71.149" r="18.208" fill="Black" stroke="Black" />
<circle cx="-25.479" cy="24.474" r="22.02" fill="Black" stroke="Black" />
<circle cx="-32.095" cy="433.939" r="7.803" fill="Black" stroke="Black" />
<circle cx="12.735" cy="-20.696" r="10.211" fill="Black" stroke="Black" />
<circle cx="-34.999" cy="58.786" r="23.508" fill="Black" stroke="Black" />
<circle cx="-446.624" cy="271.799" r="18.237" fill="Black" stroke="Black" />
<circle cx="442.957" cy="-438.916" r="21.469" fill="Black" stroke="Black" />
<circle cx="-417.141" cy="-45.226" r="11.608" fill="Black" stroke="Black" />
<circle cx="-454.274" cy="422.165" r="8.205" fill="Black" stroke="Black" />
<circle cx="-93.796" cy="-386.546" r="25.019" fill="Black" stroke="Black" />
<circle cx="-406.532" cy="265.96" r="19.502" fill="Black" stroke="Black" />
<circle cx="-190.358" cy="-457.861" r="20.952" fill="Black" stroke="Black" />
<circle cx="169.813" cy="-57.224" r="16.485" fill="Black" stroke="Black" />
<circle cx="203.292" cy="55.153" r="17.648" fill="Black" stroke="Black" />
<circle cx="-426.673" cy="-315.337" r="8.855" fill="Black" stroke="Black" />
<circle cx="420.372" cy="159.002" r="20.712" fill="Black" stroke="Black" />
<circle cx="224.041" cy="242.719" r="8.034" fill="Black" stroke="Black" />
<circle cx="191.91" cy="95.286" r="23.974" fill="Black" stroke="Black" />
<circle cx="140.865" cy="-282.536" r="26.559" fill="Black" stroke="Black" />
<circle cx="163.853" cy="428.854" r="18.74" fill="Black" stroke="Black" />
<circle cx="497.686" cy="-252.069" r="19.583" fill="Black" stroke="Black" />
<circle cx="367.478" cy="-56.821" r="11.51" fill="Black" stroke="Black" />
<circle cx="-233.43" cy="-276.126" r="13.245" fill="Black" stroke="Black" />
<circle cx="-203.233" cy="-148.255" r="11.07" fill="Black" stroke="Black" />
<circle cx="241.967" cy="-267.83" r="9.119" fill="Black" stroke="Black" />
<circle cx="457.678" cy="-268.965" r="7.586" fill="Black" stroke="Black" />
<circle cx="-47.052" cy="-274.437" r="21.635" fill="Black" stroke="Black" />
<circle cx="-122.813" cy="340.303" r="7.57" fill="Black" stroke="Black" />
<circle cx="401.051" cy="-264.958" r="11.738" fill="Black" stroke="Black" />
<circle cx="424.892" cy="-221.412" r="22.017" fill="Black" stroke="Black" />
<circle cx="436.059" cy="-355.138" r="20.128" fill="Black" stroke="Black" />
<circle cx="410.104" cy="-55.424" r="10.043" fill="Black" stroke="Black" />
<circle cx="188.565" cy="144.906" r="24.838" fill="Black" stroke="Black" />
<circle cx="-351.538" cy="-220.424" r="8.187" fill="Black" stroke="Black" />
<circle cx="23.132" cy="254.342" r="16.163" fill="Black" stroke="Black" />
<circle cx="-315.855" cy="-278.623" r="19.425" fill="Black" stroke="Black" />
<circle cx="343.396" cy="189.193" r="20.723" fill="Black" stroke="Black" />
<circle cx="14.847" cy="455.948" r="7.564" fill="Black" stroke="Black" />
<circle cx="212.1" cy="27.715" r="9.055" fill="Black" stroke="Black" />
<circle cx="-86.767" cy="-335.991" r="10.123" fill="Black" stroke="Black" />
<circle cx="-138.543" cy="-475.865" r="7.743" fill="Black" stroke="Black" />
<circle cx="245.684" cy="292.392" r="16.876" fill="Black" stroke="Black" />
<circle cx="-360.274" cy="-296.654" r="10.878" fill="Black" stroke="Black" />
<circle cx="-410.417" cy="401.005" r="22.266" fill="Black" stroke="Black" />
<circle cx="38.109" cy="88.323" r="18.188" fill="Black" stroke="Black" />
<circle cx="312.293" cy="88.552" r="12.978" fill="Black" stroke="Black" />
<circle cx="-69.468" cy="-80.216" r="9.765" fill="Black" stroke="Black" />
<circle cx="360.615" cy="-146.898" r="10.331" fill="Black" stroke="Black" />
<circle cx="-171.283" cy="328.958" r="8.432" fill="Black" stroke="Black" />
<circle cx="258.239" cy="415.267" r="7.945" fill="Black" stroke="Black" />
<circle cx="69.695" cy="92.155" r="22.131" fill="Black" stroke="Black" />
<circle cx="-107.252" cy="262.206" r="14.171" fill="Black" stroke="Black" />
<circle cx="105.416" cy="-231.756" r="16.081" fill="Black" stroke="Black" />
<circle cx="-248.703" cy="-233.753" r="23.47" fill="Black" stroke="Black" />
<circle cx="16.243" cy="21.191" r="9.153" fill="Black" stroke="Black" />
<circle cx="179.311" cy="223.736" r="17.747" fill="Black" stroke="Black" />
<circle cx="-191.391" cy="-353.702" r="23.726" fill="Black" stroke="Black" />
<circle cx="-153.661" cy="-185.634" r="14.126" fill="Black" stroke="Black" />
<circle cx="273.211" cy="-127.757" r="21.477" fill="Black" stroke="Black" />
<circle cx="21.555" cy="367.027" r="22.446" fill="Black" stroke="Black" />
<circle cx="220.112" cy="381.474" r="13.054" fill="Black" stroke="Black" />
<circle cx="-381.248" cy="400.068" r="9.521" fill="Black" stroke="Black" />
<circle cx="324.117" cy="-240.141" r="17.91" fill="Black" stroke="Black" />
<circle cx="-422.032" cy="33.281" r="10.794" fill="Black" stroke="Black" />
<circle cx="104.277" cy="-304.778" r="25.568" fill="Black" stroke="Black" />
<circle cx="-57.04" cy="106.072" r="14.205" fill="Black" stroke="Black" />
<circle cx="-312.594" cy="-117.623" r="22.917" fill="Black" stroke="Black" />
<circle cx="-329.148" cy="-145.477" r="25.965" fill="Black" stroke="Black" />
<circle cx="418.695" cy="136.919" r="19.233" fill="Black" stroke="Black" />
<circle cx="-470.24" cy="140.477" r="13.66" fill="Black" stroke="Black" />
<circle cx="56.289" cy="390.679" r="11.77" fill="Black" stroke="Black" />
<circle cx="-253.751" cy="298.265" r="23.88" fill="Black" stroke="Black" />
<circle cx="-285.528" cy="-79.733" r="7.612" fill="Black" stroke="Black" />
<circle cx="73.761" cy="-498.773" r="16.668" fill="Black" stroke="Black" />
<circle cx="-177.569" cy="-320.107" r="11.083" fill="Black" stroke="Black" />
<circle cx="355.864" cy="-189.146" r="23.859" fill="Black" stroke="Black" />
<circle cx="180.306" cy="-242.071" r="9.534" fill="Black" stroke="Black" />
<circle cx="34.241" cy="-399.968" r="19.456" fill="Black" stroke="Black" />
<circle cx="-31.557" cy="-307.467" r="27.601" fill="Black" stroke="Black" />
<circle cx="258.352" cy="-3.405" r="14.374" fill="Black" stroke="Black" />
<circle cx="-377.334" cy="480.603" r="11.239" fill="Black" stroke="Black" />
<circle cx="-84.004" cy="-242.195" r="22.839" fill="Black" stroke="Black" />
<circle cx="-208.788" cy="-328.598" r="14.137" fill="Black" stroke="Black" />
<circle cx="8.534" cy="-173.861" r="22.95" fill="Black" stroke="Black" />
<circle cx="-282.899" cy="-347.047" r="15.772" fill="Black" stroke="Black" />
<circle cx="-57.047" cy="487.613" r="14.386" fill="Black" stroke="Black" />
<circle cx="-259.439" cy="-190.149" r="21.275" fill="Black" stroke="Black" />
<circle cx="467.553" cy="-80.321" r="12.096" fill="Black" stroke="Black" />
<circle cx="-66.435" cy="180.507" r="27.476" fill="Black" stroke="Black" />
<circle cx="386.964" cy="-189.127" r="25.042" fill="Black" stroke="Black" />
<circle cx="258.416" cy="-71.054" r="11.217" fill="Black" stroke="Black" />
<circle cx="-384.872" cy="227.623" r="11.998" fill="Black" stroke="Black" />
<circle cx="86.102" cy="-142.623" r="8.35" fill="Black" stroke="Black" />
<circle cx="-311.326" cy="-414.451" r="12.999" fill="Black" stroke="Black" />
<circle cx="359.724" cy="451.368" r="26.518" fill="Black" stroke="Black" />
<circle cx="-203.099" cy="315.275" r="20.807" fill="Black" stroke="Black" />
<circle cx="-285.204" cy="240.451" r="7.687" fill="Black" stroke="Black" />
<circle cx="230.395" cy="197.427" r="24.386" fill="Black" stroke="Black" />
<circle cx="-20.502" cy="148.48" r="7.899" fill="Black" stroke="Black" />
<circle cx="214.873" cy="124.356" r="24.934" fill="Black" stroke="Black" />
<circle cx="-309.359" cy="276.985" r="12.954" fill="Black" stroke="Black" />
<circle cx="270.978" cy="475.402" r="7.792" fill="Black" stroke="Black" />
<circle cx="497.884" cy="247.875" r="20.435" fill="Black" stroke="Black" />
<circle cx="389.607" cy="280.896" r="7.869" fill="Black" stroke="Black" />
<circle cx="107.609" cy="37.987" r="8.065" fill="Black" stroke="Black" />
<circle cx="-309.791" cy="125.825" r="7.6" fill="Black" stroke="Black" />
<circle cx="-364.955" cy="285.019" r="14.721" fill="Black" stroke="Black" />
<circle cx="94.537" cy="-411.495" r="14.118" fill="Black" stroke="Black" />
<circle cx="-145.435" cy="212.201" r="27.777" fill="Black" stroke="Black" />
<circle cx="-223.49" cy="-408.037" r="18.475" fill="Black" stroke="Black" />
<circle cx="-43.703" cy="-17.28" r="22.052" fill="Black" stroke="Black" />
<circle cx="143.852" cy="-60.93" r="22.353" fill="Black" stroke="Black" />
<circle cx="-317.7" cy="-330.399" r="20.066" fill="Black" stroke="Black" />
<circle cx="185.562" cy="-465.36" r="15.18" fill="Black" stroke="Black" />
<circle cx="-416.563" cy="-179.135" r="22.286" fill="Black" stroke="Black" />
<circle cx="-175.075" cy="-120.03" r="10.433" fill="Black" stroke="Black" />
<circle cx="480.207" cy="-428.876" r="18.405" fill="Black" stroke="Black" />
<circle cx="389.551" cy="154.21" r="23.685" fill="Black" stroke="Black" />
<circle cx="-474.561" cy="-72.243" r="21.001" fill="Black" stroke="Black" />
<circle cx="415.748" cy="-168.225" r="17.993" fill="Black" stroke="Black" />
<circle cx="-98.679" cy="-266.767" r="23.727" fill="Black" stroke="Black" />
<circle cx="235.063" cy="343.197" r="23.15" fill="Black" stroke="Black" />
<circle cx="150.541" cy="225.185" r="20.92" fill="Black" stroke="Black" />
<circle cx="-210.258" cy="-36.355" r="20.501" fill="Black" stroke="Black" />
<circle cx="-457.629" cy="394.63" r="11.031" fill="Black" stroke="Black" />
<circle cx="-422.838" cy="197.196" r="8.214" fill="Black" stroke="Black" />
<circle cx="-473.338" cy="287.684" r="26.057" fill="Black" stroke="Black" />
<circle cx="-496.766" cy="339.614" r="17.0" fill="Black" stroke="Black" />
<circle cx="-281.955" cy="-196.592" r="18.008" fill="Black" stroke="Black" />
<circle cx="-147.989" cy="455.1" r="21.142" fill="Black" stroke="Black" />
<circle cx="-299.93" cy="-4.148" r="21.152" fill="Black" stroke="Black" />
<circle cx="95.836" cy="-53.228" r="21.328" fill="Black" stroke="Black" />
<circle cx="261.878" cy="319.309" r="14.49" fill="Black" stroke="Black" />
<circle cx="280.131" cy="339.275" r="8.295" fill="Black" stroke="Black" />
<circle cx="-186.722" cy="-73.471" r="26.738" fill="Black" stroke="Black" />
<circle cx="22.423" cy="-251.69" r="9.979" fill="Black" stroke="Black" />
<circle cx="-271.345" cy="466.472" r="8.783" fill="Black" stroke="Black" />
<circle cx="-272.65" cy="30.03" r="21.609" fill="Black" stroke="Black" />
<circle cx="-307.52" cy="-247.28" r="10.588" fill="Black" stroke="Black" />
<circle cx="61.189" cy="-56.506" r="11.005" fill="Black" stroke="Black" />
<circle cx="-59.756" cy="-343.697" r="20.973" fill="Black" stroke="Black" />
<circle cx="-486.51" cy="-306.235" r="9.586" fill="Black" stroke="Black" />
<circle cx="116.181" cy="107.225" r="15.891" fill="Black" stroke="Black" />
<circle cx="-363.214" cy="-146.973" r="23.353" fill="Black" stroke="Black" />
<circle cx="-474.86" cy="459.877" r="12.861" fill="Black" stroke="Black" />
<circle cx="378.718" cy="233.168" r="14.614" fill="Black" stroke="Black" />
<circle cx="-147.826" cy="-280.632" r="7.91" fill="Black" stroke="Black" />
<circle cx="-129.203" cy="18.588" r="11.766" fill="Black" stroke="Black" />
<circle cx="305.486" cy="233.486" r="11.391" fill="Black" stroke="Black" />
<circle cx="67.99" cy="146.634" r="8.18" fill="Black" stroke="Black" />
<circle cx="148.182" cy="-340.893" r="14.609" fill="Black" stroke="Black" />
<circle cx="-86.58" cy="460.301" r="10.924" fill="Black" stroke="Black" />
<circle cx="-235.757" cy="-123.198" r="14.807" fill="Black" stroke="Black" />
<circle cx="-445.496" cy="140.055" r="9.56" fill="Black" stroke="Black" />
<circle cx="190.796" cy="-42.464" r="9.708" fill="Black" stroke="Black" />
<circle cx="178.536" cy="-89.382" r="21.309" fill="Black" stroke="Black" />
<circle cx="-326.237" cy="452.772" r="18.711" fill="Black" stroke="Black" />
<circle cx="450.0" cy="450.0" r="15.0" fill="Red" stroke="Red" />
<circle cx="-450.0" cy="-450.0" r="1.0" fill="Gray" stroke="Gray" />
</svg>

After

(image error) Size: 45 KiB

605
mapy/sprint.txt Normal file
View file

@ -0,0 +1,605 @@
-450000 -450000 1000
-500000 -500000 500000 500000
600
392795 -328831 18468
-307826 377623 19829
-442617 -154891 11264
432417 268197 24370
63112 63218 9622
145009 -244769 25481
-182475 -481847 16616
271657 16729 11598
107669 336857 19407
-262210 83341 12495
57295 -466957 8501
-486605 406957 10652
-477640 176380 15416
-175170 -203102 8825
256472 360989 13940
276792 -175871 15787
411182 -486282 19694
285329 206724 8553
-40717 -245739 11996
-104495 367324 12911
-47927 -121478 8043
-180885 -36462 10454
193344 -405060 24913
-80692 137487 13663
-439381 -399996 11190
394286 473944 25792
-410443 -12242 20710
-285133 -273097 10620
-350383 -492637 20295
-101287 -353076 9943
469567 107413 21633
-300795 -25595 12762
445112 -134854 22928
142189 453543 23358
161973 200130 17818
-27468 476664 9343
-453458 -291797 15844
-161537 476679 22862
463708 -238047 8346
-430771 305860 10816
-368436 150517 22764
217356 94848 27525
288161 497372 9874
-211861 288110 18422
-57970 34670 18013
-310308 248085 10009
-215947 -380294 22018
39754 223623 23391
99171 -80776 14531
-222750 -305515 7873
320627 123792 17295
470371 -397197 9206
243285 -97354 20326
397408 195394 23445
120110 -338393 15885
-149857 182001 16464
-331160 -197631 15846
-437729 110062 15290
-487640 40083 12546
-324223 483909 17943
-340153 -115642 28382
33462 415832 14084
-3710 -486538 16094
159225 -33740 17570
440724 -41068 13183
170428 -157966 21967
383710 364316 21325
45465 -268348 13761
-396363 437991 14600
102597 136279 10164
-3040 321144 11343
-305376 -363526 20435
299171 417759 23535
271568 -253278 15258
-348183 325450 10457
-172848 54732 24771
155144 47653 14864
378476 -166477 17592
-100937 -64881 27363
387430 47855 16212
-373414 47657 7873
34354 -370209 9701
-258645 -164399 24168
-104947 -498767 8080
395704 -233557 19626
-248537 400613 14182
-29231 -340226 17342
-245041 28389 11555
-402022 -239563 23460
162623 122807 18924
197854 -70149 21417
34605 -138191 13439
198523 -496473 8182
120653 -413646 15073
475163 344743 12137
188447 267486 13171
250266 261940 9167
405902 -418221 28030
473967 176762 7843
134888 386809 22617
-366256 206467 16806
85880 -167652 10445
332712 -83674 23828
-463567 -44840 15846
-220275 148506 25580
-270737 326937 9792
244683 -335079 19732
-117435 -411315 12161
337224 315179 12097
83020 198288 18430
333493 -453784 27339
-125596 -260323 14041
-431874 377827 21138
113891 270581 10856
404806 312528 15651
107395 -475358 13144
231370 -440922 7631
481288 19021 12826
224540 308640 22139
-228826 229270 7876
-477744 244584 22936
-193567 -101924 18488
-388749 -317126 7500
385203 -485 18395
-23806 -31947 20077
491409 -164503 20746
-131333 135034 13030
-65280 305324 22585
-78249 -281592 23486
-123388 60777 23833
-288375 146618 9394
391538 -87368 8353
284964 -420371 16029
-333908 -315912 24242
-7136 186196 12618
178477 359268 9515
-294092 -443244 7716
-19667 -402065 19921
-297240 434231 11909
353638 -272777 8056
21168 138088 7517
-315267 41144 24251
-152271 -361270 13138
-248590 -406319 15006
-5907 42047 18178
-100921 -185419 12574
460049 -335988 22563
-170765 362167 9959
-343290 100893 10834
-201109 19032 15716
101991 -265180 26475
-135249 -109061 18403
337827 -214624 24421
-68245 -417037 10058
479587 -485899 20104
-497668 472650 11753
278299 -297932 27031
-106631 433660 13298
-25590 399714 7913
248127 -23375 12327
440610 213192 14493
229840 159247 14813
80221 419756 8851
-343117 419030 13459
344904 -117364 17224
348006 246641 15813
-498378 309768 26929
458369 -195098 8829
334318 475656 10551
-349825 -416231 11522
-264175 -370527 23909
-385380 -171897 23221
-151541 250389 11227
-226674 468254 23695
-210596 -244706 8771
459892 142161 10090
496842 269363 19546
-182186 424337 11491
70770 294693 18524
334974 -42072 17024
-489838 -114691 11067
255695 -384787 22992
-428679 495764 18778
-64298 -487659 25603
73342 -223311 8281
-275735 -227412 20248
300203 261273 22813
-117082 -136068 23100
-498564 -172486 10808
-13622 -74025 17290
356533 158284 21659
52473 474233 13759
393748 127230 21981
-39701 91992 20006
-391589 -125507 16181
314051 55832 12040
-67900 257802 12308
-278931 286708 22760
-377974 -389139 10083
-440028 55382 15127
183012 -350900 8991
78638 -35838 8988
-332451 186122 12520
98152 489331 28498
53421 359166 8462
295478 -135916 13667
-253584 -35403 10915
-196933 85295 18204
310643 -336092 10192
-474007 -344638 8407
-30893 -437708 19219
-211828 188960 13029
269705 445617 12307
-90512 490959 17481
428230 56715 21058
204493 404470 8018
474522 302885 9957
224460 -360377 13101
-50048 212972 9384
-335090 -377318 24123
237325 -153124 19189
433762 -390341 22613
-16694 -216812 17868
-5565 -154947 22586
115048 65968 13423
145072 8401 11167
40493 -175931 19035
-316511 -88272 20786
-409711 80500 24235
-270159 -121192 13903
31289 -424583 19216
-462951 318763 11475
-495818 126802 19417
208160 -313623 22149
284886 -55311 9315
486694 -122787 24075
423079 -4889 15925
122079 -192730 15465
-6279 -285506 10040
132726 219463 17035
-333925 363831 12924
243850 72297 18985
367966 -315373 24172
310876 18054 25379
43235 -81269 9535
-72257 -19728 16146
495417 82812 10032
147023 -97019 11164
-256934 -335184 12364
-211254 -181612 11875
158008 318644 8107
195095 467446 8994
-430127 -104751 9915
-119574 202886 25445
352848 420097 12627
30482 292628 19631
471048 -48874 9652
475254 399807 23609
23461 -323738 8840
154099 245171 24077
-230745 -486274 12934
-140412 -313810 9507
-424535 238944 9836
-375766 368630 9440
252102 216621 18480
-341720 -40794 12893
437979 331070 13572
-274193 495422 11955
321418 214636 11129
45535 182323 16627
-260611 256412 12176
365440 288625 7737
208896 205863 22402
-4751 354719 15698
-101189 24442 13381
300441 308321 12232
-338937 247605 8509
-334104 -252858 11416
186796 -435041 26488
271380 105847 15415
431730 -87891 20804
351429 32592 17682
-76008 84915 19953
-120776 99407 24766
-48848 165416 20057
-173980 121420 18451
-311818 -219948 7941
134139 -138232 19977
147411 -313387 21323
-175576 -428456 16937
-6235 426397 13921
370621 -470139 22404
268157 -213411 8183
-303780 -165944 22891
-28176 280286 10355
181593 -112740 20519
-183432 222970 10378
103959 368392 18700
-374017 252275 16493
8160 -388374 16287
341326 85964 10829
-480602 -261262 11054
-355709 -7647 19385
143206 172886 11849
392969 434997 18007
-417463 170789 8649
-389290 334730 17466
-65223 -147091 9597
-212190 369914 19382
183021 -274592 19859
-175596 -379406 19820
-418503 -359704 9107
340751 -5936 18465
-288750 102943 8457
249125 -125436 26867
-392281 296452 24113
157697 497422 12712
-488604 211353 23925
405671 233617 15616
409023 -136338 13401
-444262 -197229 11278
359779 331073 19061
-485492 -13298 23103
102639 172792 9518
431019 -275871 11778
-314645 304002 9024
-143219 -164474 18637
8897 -109424 22816
-156408 26103 17815
213179 343489 20832
463003 254177 25155
-135246 -218957 12467
-166906 295332 8536
-230727 113720 22229
-110086 177103 13971
-327109 -458195 14527
-132829 291862 7735
-223411 425892 8417
495842 -302456 10474
384749 83034 11118
-301762 -496267 17004
-295195 -317384 11697
-499073 -72011 23612
329102 -414575 17861
-71922 370073 11162
-497386 78391 9688
425157 386645 15648
-291216 55171 23326
19181 340369 17501
-292350 15051 25045
348155 -335512 18373
10553 -451898 10592
-354462 465573 23512
-129218 487182 24323
301040 456932 14457
-477738 100641 17009
-152969 83814 23421
-416056 -270894 21679
287844 380877 19163
-47816 -195076 15070
-171720 157388 14308
77347 -436065 18650
-235921 -200738 18255
-369603 -92068 7809
-148662 -396758 10356
-125778 -41347 12859
33298 -47659 11754
-472055 -376822 20684
159246 -477525 8770
-55836 -374719 25131
-366378 -343233 26823
228236 3269 8320
103781 -13010 8542
76934 -384842 9337
299839 -10018 27843
131049 299476 16512
-92185 -307983 11248
446526 -486466 18574
-1337 231081 9093
-431632 442685 16247
-272727 366752 15537
329233 265988 20812
102746 466117 26102
129267 -165183 23727
321372 -300134 17940
151077 -192342 11292
276717 288966 19349
270936 -366851 22978
-160590 407175 19640
10363 101351 15896
-65356 -446693 9655
156072 -386094 8807
18789 496573 16096
304236 -394032 11005
469919 -458315 22829
346259 380218 14873
-464044 490620 22147
313864 347926 9025
-79480 226841 16432
-263032 128458 13904
319102 176306 10804
499269 -100857 16782
-100273 115342 19216
116749 -442491 24134
28236 -478648 10110
-30018 -174525 22639
-214182 -447567 21512
-475763 360318 7522
-327204 76734 17720
-36938 365696 7773
-432192 12046 15409
207874 -120097 19353
479671 217921 19497
-268112 435597 12228
-163079 -91068 18812
-251148 156736 8577
-203520 55787 16607
303029 -211926 12918
-123987 407868 20994
371556 -402167 10138
-285991 -398573 18454
400922 -373056 10014
49967 132037 10475
355571 -437075 24513
420758 290923 20857
9252 -226340 17815
-263261 -2267 21350
493651 -329811 19264
441763 -308889 12145
423041 100071 24210
288636 40435 9356
-234462 337764 20728
411006 -299985 15627
-51913 -46482 17250
488552 144453 19089
-451099 -236034 15338
-499465 442871 16113
133633 480182 19795
218044 499681 11805
156524 -427691 21426
-374684 173379 25590
439661 -245914 15153
292999 -91424 7787
-227765 -71149 18208
-25479 24474 22020
-32095 433939 7803
12735 -20696 10211
-34999 58786 23508
-446624 271799 18237
442957 -438916 21469
-417141 -45226 11608
-454274 422165 8205
-93796 -386546 25019
-406532 265960 19502
-190358 -457861 20952
169813 -57224 16485
203292 55153 17648
-426673 -315337 8855
420372 159002 20712
224041 242719 8034
191910 95286 23974
140865 -282536 26559
163853 428854 18740
497686 -252069 19583
367478 -56821 11510
-233430 -276126 13245
-203233 -148255 11070
241967 -267830 9119
457678 -268965 7586
-47052 -274437 21635
-122813 340303 7570
401051 -264958 11738
424892 -221412 22017
436059 -355138 20128
410104 -55424 10043
188565 144906 24838
-351538 -220424 8187
23132 254342 16163
-315855 -278623 19425
343396 189193 20723
14847 455948 7564
212100 27715 9055
-86767 -335991 10123
-138543 -475865 7743
245684 292392 16876
-360274 -296654 10878
-410417 401005 22266
38109 88323 18188
312293 88552 12978
-69468 -80216 9765
360615 -146898 10331
-171283 328958 8432
258239 415267 7945
69695 92155 22131
-107252 262206 14171
105416 -231756 16081
-248703 -233753 23470
16243 21191 9153
179311 223736 17747
-191391 -353702 23726
-153661 -185634 14126
273211 -127757 21477
21555 367027 22446
220112 381474 13054
-381248 400068 9521
324117 -240141 17910
-422032 33281 10794
104277 -304778 25568
-57040 106072 14205
-312594 -117623 22917
-329148 -145477 25965
418695 136919 19233
-470240 140477 13660
56289 390679 11770
-253751 298265 23880
-285528 -79733 7612
73761 -498773 16668
-177569 -320107 11083
355864 -189146 23859
180306 -242071 9534
34241 -399968 19456
-31557 -307467 27601
258352 -3405 14374
-377334 480603 11239
-84004 -242195 22839
-208788 -328598 14137
8534 -173861 22950
-282899 -347047 15772
-57047 487613 14386
-259439 -190149 21275
467553 -80321 12096
-66435 180507 27476
386964 -189127 25042
258416 -71054 11217
-384872 227623 11998
86102 -142623 8350
-311326 -414451 12999
359724 451368 26518
-203099 315275 20807
-285204 240451 7687
230395 197427 24386
-20502 148480 7899
214873 124356 24934
-309359 276985 12954
270978 475402 7792
497884 247875 20435
389607 280896 7869
107609 37987 8065
-309791 125825 7600
-364955 285019 14721
94537 -411495 14118
-145435 212201 27777
-223490 -408037 18475
-43703 -17280 22052
143852 -60930 22353
-317700 -330399 20066
185562 -465360 15180
-416563 -179135 22286
-175075 -120030 10433
480207 -428876 18405
389551 154210 23685
-474561 -72243 21001
415748 -168225 17993
-98679 -266767 23727
235063 343197 23150
150541 225185 20920
-210258 -36355 20501
-457629 394630 11031
-422838 197196 8214
-473338 287684 26057
-496766 339614 17000
-281955 -196592 18008
-147989 455100 21142
-299930 -4148 21152
95836 -53228 21328
261878 319309 14490
280131 339275 8295
-186722 -73471 26738
22423 -251690 9979
-271345 466472 8783
-272650 30030 21609
-307520 -247280 10588
61189 -56506 11005
-59756 -343697 20973
-486510 -306235 9586
116181 107225 15891
-363214 -146973 23353
-474860 459877 12861
378718 233168 14614
-147826 -280632 7910
-129203 18588 11766
305486 233486 11391
67990 146634 8180
148182 -340893 14609
-86580 460301 10924
-235757 -123198 14807
-445496 140055 9560
190796 -42464 9708
178536 -89382 21309
-326237 452772 18711
1
450000 450000 15000

22
mapy/test.svg Normal file
View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1000" height="1000" viewBox="-500.0 -500.0 1000 1000">
<defs>
</defs>
<rect x="-500.0" y="-500.0" width="1000" height="1000" fill="White" />
<circle cx="-433.455" cy="323.615" r="118.285" fill="Black" stroke="Black" />
<circle cx="131.005" cy="-450.1" r="78.44" fill="Black" stroke="Black" />
<circle cx="-471.54" cy="-227.205" r="136.31" fill="Black" stroke="Black" />
<circle cx="292.86" cy="466.125" r="107.82" fill="Black" stroke="Black" />
<circle cx="426.1" cy="-268.28" r="85.235" fill="Black" stroke="Black" />
<circle cx="-48.65" cy="101.86" r="94.205" fill="Black" stroke="Black" />
<circle cx="-84.895" cy="411.69" r="115.305" fill="Black" stroke="Black" />
<circle cx="-82.17" cy="-303.555" r="78.13" fill="Black" stroke="Black" />
<circle cx="-447.19" cy="42.975" r="38.595" fill="Black" stroke="Black" />
<circle cx="201.645" cy="-251.24" r="56.76" fill="Black" stroke="Black" />
<circle cx="464.59" cy="303.79" r="45.905" fill="Red" stroke="Red" />
<circle cx="-396.8" cy="-481.74" r="40.55" fill="Red" stroke="Red" />
<circle cx="104.94" cy="323.18" r="76.86" fill="Red" stroke="Red" />
<circle cx="-240.145" cy="-122.73" r="104.49" fill="Red" stroke="Red" />
<circle cx="0.0" cy="0.0" r="5.0" fill="Gray" stroke="Gray" />
</svg>

After

(image error) Size: 1.3 KiB

18
mapy/test.txt Normal file
View file

@ -0,0 +1,18 @@
0 0 1000
-100000 -100000 100000 100000
10
-86691 64723 23657
26201 -90020 15688
-94308 -45441 27262
58572 93225 21564
85220 -53656 17047
-9730 20372 18841
-16979 82338 23061
-16434 -60711 15626
-89438 8595 7719
40329 -50248 11352
4
92918 60758 9181
-79360 -96348 8110
20988 64636 15372
-48029 -24546 20898