Commit 3a3da8b0 authored by Karol Actun's avatar Karol Actun
Browse files

finished version

parent 43ba61b2
......@@ -3,5 +3,5 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (swarm-sim)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.7 (swarm-sim)" jdkType="Python SDK" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
......
......@@ -3,8 +3,8 @@
## Different number creates a different random sequence
seedvalue = 12
## Maximum round number in swarm-world
max_round = 100
## Maximum round number in swarm-world, 0 = infinit
max_round = 0
## 1 = Call of particles in randmom order
## 0 = Call of particles in added order in scenario
......@@ -21,23 +21,85 @@ visualization = 1
#gui
gui = default_gui
# .obj (Wavefront) filenames in lib/visualization/models
particle_model_file = particle.obj
tile_model_file = tile.obj
marker_model_file = marker.obj
# matter colors (r,g,b,a)
particle_color = (1.0, 0.0, 0.0, 1.0)
tile_color = (0.0, 1.0, 0.0, 1.0)
marker_color = (0.0, 0.0, 1.0, 1.0)
grid_color = (1.0, 1.0, 1.0, 0.5)
# Grid Configs. uncomment your choice!
;# Quadratic Grid grid default configs:
;grid_class = QuadraticGrid
;# .obj (Wavefront) filenames in lib/visualization/models
;particle_model_file = 2d_particle.obj
;tile_model_file = 2d_quad_tile.obj
;marker_model_file = 2d_marker.obj
;grid_size = 1000
; end of Quadratic grid configs
;# Triangular grid default configs:
;grid_class = TriangularGrid
;# .obj (Wavefront) filenames in lib/visualization/models
;particle_model_file = 2d_particle.obj
;tile_model_file = 2d_hex_tile.obj
;marker_model_file = 2d_marker.obj
;grid_size = 100
; end of Triangular grid configs
;
;# cubic grid default configs:
;grid_class = CubicGrid
;particle_model_file = 3d_particle_low_poly.obj
;tile_model_file = 3d_cube_tile.obj
;marker_model_file = 3d_marker.obj
;grid_size = 10
; end of cubic grid configs
# ccp grid default configs:
grid_class = CCPGrid
particle_model_file = 3d_particle.obj
tile_model_file = 3d_ccp_tile.obj
marker_model_file = 3d_marker.obj
grid_size = 10
# end of ccp grid configs
# matter default colors (rgba)
particle_color = (0.8, 0.3, 0.3, 1.0)
tile_color = (0.3, 0.3, 0.8, 1.0)
marker_color = (0.3, 0.8, 0.3, 1.0)
grid_color = (0.0, 0.0, 0.0, 1.0)
cursor_color = (0.5, 0.5, 0.5, 0.5)
center_color = (1.0, 0.0, 0.0, 0.5)
# background (rgb)
background_color = (0.8, 0.8, 0.8)
# color of grid lines (rgba)
line_color = (0.0, 0.0, 0.0, 1.0)
# length/scaling of the grid lines (max should be 1,1,1)
line_scaling = (1.0, 1.0, 1.0)
# flag for showing the lines
show_lines = True
# color of grid locations (rgba)
location_color = (0.0, 0.0, 0.0, 1.0)
# size/scaling of the location model. wouldn't make it bigger than 0.2, 0.2, 0.2
location_scaling = (0.05, 0.05, 0.05)
# flag for showing the location models
show_locations = True
# flag for showing the center of the grid
show_center = True
# camera focus color
focus_color = (1.0, 1.0, 1.0, 0.5)
# show camera focus
show_focus = True
# Camera init values
look_at = (0.0, 0.0, 0.0)
phi = -90
theta = 0
radius = 10
fov = 40
cursor_offset = -10
render_distance = 1000
[World]
## cubic = CubicGrid (3D - easy)
## hexagonal = HexagonalGrid (2D - original grid)
## ccp = CloseCubicPacking (3D - complex)
grid_class = cubic
grid_size = 10
## False = Unlimited world size
## True = limited world size
......@@ -49,7 +111,7 @@ size_x = 2000.0
size_y = 2000.0
## Maximum number of particles that can be created while simulating
max_particles = 1000000
max_particles = 100000000
[Matter]
## with memory (mm) limitation 1=Yes 0=No
......@@ -62,33 +124,6 @@ particle_mm_size = 2
tile_mm_size = 2
[File]
##Examples##
##Moving
#scenario = lonely_particle
#scenario = n_particle_in_line
#solution = random_walk
#solution = round_walk
## Creating and Deleting
#scenario = lonely_particle
#solution = create_delete
## Take and Drop
#scenario = between_particle_one_tile_particle
#solution= take_drop_aims
## Read and Write
#scenario = two_particles_tiles_markers
#solution = read_write
## Scanning for matters
#scenario = particles_tiles_markers_ring
#solution= scanning_for_all_aims
## All interfaces
#scenario = test_interfaces
scenario = test_interfaces3d
#scenario = hexagon_border
solution = test_all_the_interfaces
scenario = rings_of _matter
solution = random_walk_with_take_and_drop
from grids.Grid import Grid
class CCPGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT_UP": (-1.0, 1.0, 0.0),
"FORWARD_UP": (0.0, 1.0, 1.0),
"RIGHT_UP": (1.0, 1.0, 0.0),
"BACK_UP": (0.0, 1.0, -1.0),
"LEFT_FORWARD": (-1.0, 0.0, 1.0),
"RIGHT_FORWARD": (1.0, 0.0, 1.0),
"RIGHT_BACK": (1.0, 0.0, -1.0),
"LEFT_BACK": (-1.0, 0.0, -1.0),
"LEFT_DOWN": (-1.0, -1.0, 0.0),
"FORWARD_DOWN": (0.0, -1.0, 1.0),
"RIGHT_DOWN": (1.0, -1.0, 0.0),
"BACK_DOWN": (0.0, -1.0, -1.0)}
def get_box(self, width):
locations = []
for x in range(-int(width / 2), int(width / 2)):
for y in range(-int(width / 2), int(width / 2)):
for z in range(-int(width / 2), int(width / 2)):
if self.is_valid_location((x, y, z)):
locations.append((x, y, z))
return locations
def is_valid_location(self, location):
x = location[0]
y = location[1]
z = location[2]
if y % 2.0 == 0:
if x % 2.0 == z % 2.0 == 0 or x % 2.0 == z % 2.0 == 1:
return True
else:
if x % 2.0 == 1 and z % 2.0 == 0 or x % 2.0 == 0 and z % 2.0 == 1:
return True
return False
def get_nearest_location(self, coordinates):
x = round(coordinates[0])
y = round(coordinates[1])
z = round(coordinates[2])
if y % 2.0 == 0:
if x % 2.0 != z % 2.0:
z = z + 1
else:
if x % 2.0 == z % 2.0:
z = z + 1
return x, y, z
def get_dimension_count(self):
return 3
def get_distance(self, start, end):
dx = abs(start[0] - end[0])
dy = abs(start[1] - end[1])
dz = abs(start[2] - end[2])
if dy > dx + dz:
return dy
if dx > dy + dz:
return dx
if dz > dx + dy:
return dz
return (dx + dy + dz) / 2.0
def get_center(self):
return 0, 0, 0
from grids.Grid import Grid
class CubicGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT": (-1, 0, 0),
"RIGHT": (1, 0, 0),
"UP": (0, 1, 0),
"DOWN": (0, -1, 0),
"FORWARD": (0, 0, 1),
"BACK": (0, 0, -1)}
def get_box(self, width):
locations = []
for x in range(int(-width / 2), int(width / 2)):
for y in range(int(-width / 2), int(width / 2)):
for z in range(int(-width / 2), int(width / 2)):
locations.append((x, y, z))
return locations
def is_valid_location(self, location):
if location[0] % 1 == 0 and location[1] % 1 == 0 and location[2] % 1 == 0:
return True
else:
return False
def get_nearest_location(self, coordinates):
return (round(coordinates[0]),
round(coordinates[1]),
round(coordinates[2]))
def get_dimension_count(self):
return 3
def get_distance(self, start, end):
return abs(start[0] - end[0]) + abs(start[1] - end[1]) + abs(start[2] - end[2])
def get_center(self):
return 0, 0, 0
from abc import ABC, abstractmethod
class Grid(ABC):
@property
@abstractmethod
def size(self):
pass
@property
@abstractmethod
def directions(self):
pass
@abstractmethod
def is_valid_location(self, location):
"""
checks if given location is a valid location for matter in this grid
:param location: (float, float, float)
:return: true = location is valid, false = location invalid
"""
pass
@abstractmethod
def get_nearest_location(self, coordinates):
"""
calculates the nearest location to given coordinates
:param coordinates: (float, float, float)
:return: valid location
"""
pass
def get_directions_dictionary(self):
"""
returns a dictionary of the directions, with direction names (string) as keys
and the direction vectors (3d tuple) as values
:return: dictionary with - 'string: (float, float,float)'
"""
return self.directions
def get_directions_list(self):
"""
returns a list of the direction vectors
:return: list of 3d tuples - '(float, float, float)'
"""
return list(self.directions.values())
def get_directions_names(self):
"""
returns a list of direction names
:return: list of strings
"""
return list(self.directions.keys())
def get_lines(self):
"""
FOR VISUALIZATION!
calculates line data in this grids directions for the visualization.
output is a list of start and end points. the start point is always the center of this grid and the end points
are the directions but only half in length
:return: list of vectors, [(sx,sy,sz), (ex,ey,ez), (sx,sy,sz), (ea,eb,ec), ...]
"""
lines = []
for d in self.get_directions_list():
lines.append(self.get_center())
hd = (d[0] * 0.5, d[1] * 0.5, d[2] * 0.5)
lines.append(hd)
return lines
@abstractmethod
def get_box(self, width):
"""
calculates locations in a box
:return: list of 3d coordinates: [(x_start_l0, y_start_l0), (x_end_l0, y_end_l0), (x_start_l1, y_start_l1), ...)
"""
pass
@abstractmethod
def get_dimension_count(self):
"""
returns the amount of dimensions
:return: integer, amount of dimensions (3 or 2 presumably)
"""
pass
@abstractmethod
def get_distance(self, start, end):
"""
the metric or distance function for this grid
:param start: location, (float, float, float) tuple, start of path
:param end: location, (float, float, float) tuple, end of path
:return: integer, minimal amount of steps between start and end
"""
pass
@staticmethod
def get_location_in_direction(position, direction):
"""
calculates a new position from current position and direction
:param position: location, (float, float, float) tuple, current position
:param direction: location, (float, float, float) tuple, direction
:return: location, (float, float, float) tuple, new position
"""
new_pos = []
for i in range(len(position)):
new_pos.append(position[i]+direction[i])
return tuple(new_pos)
def get_center(self):
"""
returns the center of the grid. usually (0,0,0)
:return: location, (float, float, float) tuple
"""
return 0.0, 0.0, 0.0
def get_scaling(self):
"""
returns the x,y,z scaling for the visualization. usually (1,1,1) = no scaling
:return: x,y,z scaling values: float, float, float
"""
return 1.0, 1.0, 1.0
def get_adjacent_locations(self, location):
"""
calculates a set of adjacent locations of the given location
:param location: the location of which the neighboring locations should be calculated
:return: a set of locations
"""
n = set()
for d in self.get_directions_list():
n.add(self.get_location_in_direction(location, d))
return n
def _get_adjacent_locations_not_in_set(self, location, not_in_set):
"""
the same as 'get_neighboring_locations', but doesn't return locations which are in the given 'not_in_set'.
:param location: the location of which the neighboring locations should be calculated
:param not_in_set: set of locations, which should not be included in the result
:return: a set of locations
"""
result = set()
for d in self.get_directions_list():
n = self.get_location_in_direction(location, d)
if n not in not_in_set:
result.add(n)
return result
def get_n_sphere(self, location, radius):
"""
calculates the n-sphere of this grid
:param location: center of the circle/sphere
:param radius: radius of the circle/sphere
:return: set of locations
"""
result = set()
ns = self.get_adjacent_locations(location)
current_ns = ns
result.update(ns)
for i in range(radius):
tmp = set()
for n in current_ns:
ns = self._get_adjacent_locations_not_in_set(n, result)
tmp.update(ns)
result.update(ns)
current_ns = tmp
return result
def get_n_sphere_border(self, location, radius):
"""
calculates the border of an n-sphere around the center with the given radius
:param location: center of the ring
:param radius: radius of the ring
:return: set of locations
"""
if radius == 0:
r = set()
r.add(location)
return r
seen = set()
ns = self.get_adjacent_locations(location)
current_ns = ns
seen.update(ns)
seen.add(location)
for i in range(radius-1):
tmp = set()
for n in current_ns:
ns = self._get_adjacent_locations_not_in_set(n, seen)
seen.update(ns)
tmp.update(ns)
current_ns = tmp
return current_ns
from grids.Grid import Grid
class QuadraticGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT": (-1, 0, 0),
"RIGHT": (1, 0, 0),
"UP": (0, 1, 0),
"DOWN": (0, -1, 0)}
def get_box(self, width):
locations = []
for x in range(int(-width / 2), int(width / 2)):
for y in range(int(-width / 2), int(width / 2)):
locations.append((x, y, 0.0))
return locations
def is_valid_location(self, location):
if location[0] % 1 == 0 and location[1] % 1 == 0:
return True
else:
return False
def get_nearest_location(self, coordinates):
return (round(coordinates[0]),
round(coordinates[1]), 0.0)
def get_dimension_count(self):
return 2
def get_distance(self, start, end):
return abs(start[0] - end[0]) + abs(start[1] - end[1])
def get_center(self):
return 0, 0, 0
import math
from grids.Grid import Grid
class TriangularGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"NE": (0.5, 1, 0),
"E": (1, 0, 0),
"SE": (0.5, -1, 0),
"SW": (-0.5, -1, 0),
"W": (-1, 0, 0),
"NW": (-0.5, 1, 0)}
def get_box(self, width):
locs = []
for y in range(-int(width/2),int(width/2)):
for x in range(-int(width / 2), int(width / 2)):
if y % 2 == 0:
locs.append((x, y, 0.0))
else:
locs.append((x+0.5, y, 0.0))
return locs
def is_valid_location(self, location):
if not location[2] == 0.0:
return False
if location[1] % 2.0 == 0.0:
if location[0] % 1.0 == 0.0:
return True
else:
if location[0] % 1.0 == 0.5:
return True
return False
def get_nearest_location(self, coordinates):
nearest_y = round(coordinates[1])
if nearest_y % 2 == 0:
nearest_x = round(coordinates[0])
else:
if coordinates[0] < 0:
nearest_x = int(coordinates[0]) - 0.5
else:
nearest_x = int(coordinates[0]) + 0.5
return nearest_x, nearest_y, 0
def get_directions_dictionary(self):
return self.directions
def get_dimension_count(self):
return 2
def get_distance(self, start, end):
dx = abs(start[0]-end[0])
dy = abs(start[1]-end[1])
if dx*2 >= dy:
return (dx*2+dy)/2
else: