world.py 19.7 KB
Newer Older
Ahmad Reza's avatar
Ahmad Reza committed
1
"""The world module provides the interface of the simulation world. In the simulation world
2
all the data of the particles, tiles, and markers are stored.
3
It also have the the coordination system and stated the maximum of the x and y coordinate.
Ahmad Reza's avatar
Ahmad Reza committed
4

5
 .. todo:: What happens if the maximum y or x axis is passed? Either the start from the other side or turns back.
Ahmad Reza's avatar
Ahmad Reza committed
6
"""
7
import importlib
Ahmad Reza's avatar
Ahmad Reza committed
8
import random
9
import math
10
import logging
11
from lib import csv_generator, particle, tile, marker, vis
12
from lib.swarm_sim_header import *
13
14


Ahmad Reza's avatar
Ahmad Reza committed
15
class World:
16
    def __init__(self, config_data):
Ahmad Reza's avatar
Ahmad Reza committed
17
        """
Ahmad Reza's avatar
Ahmad Reza committed
18
        Initializing the world constructor
Ahmad Reza's avatar
Ahmad Reza committed
19
        :param seed: seed number for new random numbers
20
        :param max_round: the max round number for terminating the worldulator
Ahmad Reza's avatar
Ahmad Reza committed
21
        :param solution: The name of the solution that is going to be used
22
23
        :param size_x: the maximal size of the x axes
        :param size_y: the maximal size of the y axes
24
        :param world_name: the name of the world file that is used to build up the world
25
26
        :param solution_name: the name of the solution file that is only used for the csv file
        :param seed: the seed number it is only used here for the csv file
Ahmad Reza's avatar
Ahmad Reza committed
27
        :param max_particles: the maximal number of particles that are allowed to be or created in this world
Ahmad Reza's avatar
Ahmad Reza committed
28
29
30
        """
        self.__round_counter = 1
        self.__end = False
Ahmad Reza's avatar
Ahmad Reza committed
31

32
        self.init_particles=[]
33
        self.particle_id_counter = 0
34
35
36
37
38
39
        self.particles = []
        self.particles_created = []
        self.particle_rm = []
        self.particle_map_coords = {}
        self.particle_map_id = {}
        self.__particle_deleted=False
Ahmad Reza's avatar
Ahmad Reza committed
40

41
42
43
44
45
46
        self.tiles = []
        self.tiles_created = []
        self.tiles_rm = []
        self.tile_map_coords = {}
        self.tile_map_id = {}
        self.__tile_deleted=False
Ahmad Reza's avatar
Ahmad Reza committed
47
48
        self.new_tile = None

49
50
51
52
53
54
        self.markers = []
        self.markers_created = []
        self.marker_map_coords = {}
        self.marker_map_id = {}
        self.markers_rm = []
        self.__marker_deleted = False
Ahmad Reza's avatar
Ahmad Reza committed
55

56
        self.config_data = config_data
57

Ahmad Reza's avatar
Ahmad Reza committed
58
59
60
        self.csv_round = csv_generator.CsvRoundData(scenario=config_data.scenario,
                                                    solution=config_data.solution,
                                                    seed=config_data.seed_value,
61
                                                    directory=config_data.direction_name)
Ahmad Reza's avatar
Ahmad Reza committed
62
63

        mod = importlib.import_module('scenario.' + self.config_data.scenario)
Ahmad Reza's avatar
Ahmad Reza committed
64
        mod.scenario(self)
Ahmad Reza's avatar
Ahmad Reza committed
65

Ahmad Reza's avatar
Ahmad Reza committed
66
        if self.config_data.particle_random_order:
67
68
            random.shuffle(self.particles)

Ahmad Reza's avatar
Ahmad Reza committed
69
70
        if config_data.visualization:
            self.window = vis.VisWindow(config_data.window_size_x, config_data.window_size_y, self)
71

Ahmad Reza's avatar
Ahmad Reza committed
72
73
    def csv_aggregator(self):
        self.csv_round.aggregate_metrics()
74
        particle_csv = csv_generator.CsvParticleFile(self.config_data.direction_name)
Ahmad Reza's avatar
Ahmad Reza committed
75
        for particle in self.particles:
76
77
            particle_csv.write_particle(particle)
        particle_csv.csv_file.close()
Ahmad Reza's avatar
Ahmad Reza committed
78

79
    def set_successful_end(self):
Ahmad Reza's avatar
Ahmad Reza committed
80
        self.csv_round.success()
81
        self.set_end()
Ahmad Reza Cheraghi's avatar
Ahmad Reza Cheraghi committed
82
83
84
85
86
87
88
89
        
    def get_max_round(self):
        """
        The max round number
    
        :return: maximum round number
        """
        return self.config_data.max_round
Ahmad Reza's avatar
Ahmad Reza committed
90
91
92
93
94
95
96
97
98

    def get_actual_round(self):
        """
        The actual round number

        :return: actual round number
        """
        return self.__round_counter

99
100
101
102
103
104
105
106
    def get_max_round(self):
        """
        The max round number

        :return: maximum round number
        """
        return self.config_data.max_round

107
    def set_unsuccessful_end(self):
Ahmad Reza's avatar
Ahmad Reza committed
108
109
110
111
112
113
114
115
116
117
118
        """
        Allows to terminate before the max round is reached
        """
        self.__end=True

    def get_end(self):
        """
            Returns the end parameter values either True or False
        """
        return self.__end

119
    def inc_round_counter_by(self, number=1):
Ahmad Reza's avatar
Ahmad Reza committed
120
121
122
123
124
        """
        Increases the the round counter by

        :return:
        """
125
        self.__round_counter +=  number
Ahmad Reza's avatar
Ahmad Reza committed
126
127
128
129
130
131
132
133
134

    def get_solution(self):
        """
        actual solution name

        :return: actual solution name
        """
        return self.__solution

135
    def get_amount_of_particles(self):
136
        """
Ahmad Reza's avatar
Ahmad Reza committed
137
        Returns the actual number of particles in the world
138
139
140

        :return: The actual number of Particles
        """
141
        return len(self.particles)
142
143
144

    def get_particle_list(self):
        """
Ahmad Reza's avatar
Ahmad Reza committed
145
        Returns the actual number of particles in the world
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

        :return: The actual number of Particles
        """
        return self.particles

    def get_particle_map_coords(self):
        """
        Get a dictionary with all particles mapped with their actual coordinates

        :return: a dictionary with particles and their coordinates
        """
        return self.particle_map_coords

    def get_particle_map_id(self):
        """
        Get a dictionary with all particles mapped with their own ids

        :return: a dictionary with particles and their own ids
        """
        return self.particle_map_id

167
    def get_amount_of_tiles(self):
168
        """
Ahmad Reza's avatar
Ahmad Reza committed
169
        Returns the actual number of particles in the world
170
171
172

        :return: The actual number of Particles
        """
173
        return len(self.tiles)
174
175
176

    def get_tiles_list(self):
        """
Ahmad Reza's avatar
Ahmad Reza committed
177
        Returns the actual number of tiles in the world
178

Ahmad Reza's avatar
Ahmad Reza committed
179
        :return: a list of all the tiles in the world
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
        """
        return self.tiles

    def get_tile_map_coords(self):
        """
        Get a dictionary with all tiles mapped with their actual coordinates

        :return: a dictionary with particles and their coordinates
        """
        return self.tile_map_coords

    def get_tile_map_id(self):
        """
        Get a dictionary with all particles mapped with their own ids

        :return: a dictionary with particles and their own ids
        """
        return self.tile_map_id

199
    def get_amount_of_markers(self):
200
        """
Ahmad Reza's avatar
Ahmad Reza committed
201
        Returns the actual number of markers in the world
202

203
        :return: The actual number of markers
204
        """
205
        return len(self.markers)
206

207
    def get_marker_list(self):
208
        """
Ahmad Reza's avatar
Ahmad Reza committed
209
        Returns the actual number of markers in the world
210

211
        :return: The actual number of markers
212
        """
213
        return self.markers
214

215
    def get_marker_map_coords(self):
216
        """
217
        Get a dictionary with all markers mapped with their actual coordinates
218

219
        :return: a dictionary with markers and their coordinates
220
        """
221
        return self.marker_map_coords
222

223
    def get_marker_map_id(self):
224
        """
225
        Get a dictionary with all markers mapped with their own ids
226

227
        :return: a dictionary with markers and their own ids
228
        """
229
        return self.marker_map_id
230

231
    def get_world_x_size(self):
232
233
        """

Ahmad Reza's avatar
Ahmad Reza committed
234
        :return: Returns the maximal x size of the world
235
        """
Ahmad Reza's avatar
Ahmad Reza committed
236
        return self.config_data.size_x
237

238
    def get_world_y_size(self):
239
        """
Ahmad Reza's avatar
Ahmad Reza committed
240
        :return: Returns the maximal y size of the world
241
        """
Ahmad Reza's avatar
Ahmad Reza committed
242
        return self.config_data.size_y
243

244
245
246
247
248
249
    def get_world_size(self):
        """
        :return: Returns the maximal (x,y) size of the world as a tupel
        """
        return (self.config_data.size_x, self.config_data.size_y)

250
251
252
253
254
255
    def get_tile_deleted(self):
        return self.__tile_deleted

    def get_particle_deleted(self):
        return self.__particle_deleted

256
257
    def get_marker_deleted(self):
        return self.__marker_deleted
258
259
260
261
262
263
264

    def set_tile_deleted(self):
        self.__tile_deleted = False

    def set_particle_deleted(self):
        self.__particle_deleted=False

265
266
    def set_marker_deleted(self):
        self.__marker_deleted = False
267

268
    def add_particle(self, x, y, color=black, alpha=1):
269
        """
Ahmad Reza's avatar
Ahmad Reza committed
270
        Add a particle to the world database
271
272
273
274
275
276

        :param x: The x coordinate of the particle
        :param y: The y coordinate of the particle
        :param state: The state of the particle. Default: S for for Stopped or Not Moving. Other options
                      are the moving directions: E, SE, SW, W, NW, NE
        :param color: The color of the particle. Coloroptions: black, gray, red, green, or blue
277
        :return: Added Matter; False: Unsuccsessful
278
279
280
        """
        if alpha < 0 or alpha >1:
            alpha = 1
Ahmad Reza's avatar
Ahmad Reza committed
281
        if len(self.particles) < self.config_data.max_particles:
282
            if check_values_are_coordinates(x,y) == True:
283
                if (x,y) not in self.get_particle_map_coords():
284
285
286
                    self.particle_id_counter += 1
                    new_particle = particle.Particle(self, x, y, color, alpha, self.particle_id_counter)
                    print(new_particle.number)
287
288
289
290
291
                    self.particles_created.append(new_particle)
                    self.particle_map_coords[new_particle.coords] = new_particle
                    self.particle_map_id[new_particle.get_id()] = new_particle
                    self.particles.append(new_particle)
                    new_particle.touch()
Ahmad Reza's avatar
Ahmad Reza committed
292
                    self.csv_round.update_particle_num(len(self.particles))
293
294
295
                    self.init_particles.append(new_particle)
                    new_particle.created=True
                    logging.info("Created particle at %s", new_particle.coords)
296
                    return new_particle
297
298
299
300
301
302
303
304
305
306
307
                else:
                    print("for x %f and y %f not not possible because Particle exist   ", x, y)
                    return False
            else:
                 print ("for x %f and y %f not possible to draw ", x, y)
                 return False
        else:
            logging.info("Max of particles reached and no more particles can be created")
            return False

    def remove_particle(self,id):
Ahmad Reza's avatar
Ahmad Reza committed
308
        """ Removes a particle with a given particle id from the world database
309
310
311
312
313
314
315
316
317
318
319
320
321
322


        :param particle_id: particle id
        :return: True: Successful removed; False: Unsuccessful
        """
        rm_particle = self.particle_map_id[id]
        if rm_particle:
            self.particles.remove(rm_particle)
            try:
                del self.particle_map_coords[rm_particle.coords]
                del self.particle_map_id[id]
            except:
                pass
            self.particle_rm.append(rm_particle)
Ahmad Reza's avatar
Ahmad Reza committed
323
324
            self.csv_round.update_particle_num(len(self.particles))
            self.csv_round.update_metrics(particle_deleted=1)
325
326
327
328
329
330
331
            self.__particle_deleted = True
            return True
        else:
            return False

    def remove_particle_on(self, coords):
        """
Ahmad Reza's avatar
Ahmad Reza committed
332
        Removes a particle on a give coordinat from to the world database
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

        :param coords: A tupel that includes the x and y coorindates
        :return: True: Successful removed; False: Unsuccessful
        """
        if coords in self.particle_map_coords:
            self.particles.remove(self.particle_map_coords[coords])
            self.particle_rm.append(self.particle_map_coords[coords])
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.particle_map_id[self.particle_map_coords[coords].get_id()]
            except KeyError:
                pass
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.particle_map_coords[coords]
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
348
349
            self.csv_round.update_particle_num(len(self.particles))
            self.csv_round.update_metrics( particle_deleted=1)
350
351
352
353
354
355
356
            self.__particle_deleted = True
            return True
        else:
            return False

    def add_tile(self, x, y, color=gray, alpha=1):
        """
Ahmad Reza's avatar
Ahmad Reza committed
357
        Adds a tile to the world database
358
359
360
361

        :param color:
        :param x: the x coordinates on which the tile should be added
        :param y: the y coordinates on which the tile should be added
362
        :return: Successful added matter; False: Unsuccsessful
363
        """
364
        if alpha < 0 or alpha >1:
365
            alpha = 1
366
        if check_values_are_coordinates(x,y) == True:
367
            if (x,y) not in self.tile_map_coords:
Ahmad Reza Cheraghi's avatar
Ahmad Reza Cheraghi committed
368
                self.new_tile=tile.Tile(self, x, y, color, alpha)
369
370
                print("Before adding ", len(self.tiles) )
                self.tiles.append(self.new_tile)
Ahmad Reza's avatar
Ahmad Reza committed
371
                self.csv_round.update_tiles_num(len(self.tiles))
372
373
374
375
376
377
                self.tile_map_coords[self.new_tile.coords] = self.new_tile
                self.tile_map_id[self.new_tile.get_id()] = self.new_tile

                print("Afer adding ", len(self.tiles), self.new_tile.coords )
                logging.info("Created tile with tile id %s on coords %s",str(self.new_tile.get_id()), str(self.new_tile.coords))
                self.new_tile.touch()
378
                return self.new_tile
379
380
381
382
383
384
385
386
387
            else:
                logging.info ("on x %f and y %f coordinates is a tile already", x, y)
                return False
        else:
             logging.info ("for x %f and y %f not possible to draw ", x, y)
             return False

    def add_tile_vis(self, x, y, color=gray, alpha=1):
        """
Ahmad Reza's avatar
Ahmad Reza committed
388
        Adds a tile to the world database
389
390
391
392
393
394

        :param color:
        :param x: the x coordinates on which the tile should be added
        :param y: the y coordinates on which the tile should be added
        :return: True: Successful added; False: Unsuccsessful
        """
395
        if check_values_are_coordinates(x, y) == True:
396
            if (x, y) not in self.tile_map_coords:
Ahmad Reza Cheraghi's avatar
Ahmad Reza Cheraghi committed
397
                self.new_tile = tile.Tile(self, x, y, color, alpha)
398
399
400
401
402
                self.tiles.append(self.new_tile)

                self.tile_map_coords[self.new_tile.coords] = self.new_tile
                self.tile_map_id[self.new_tile.get_id()] = self.new_tile

Ahmad Reza's avatar
Ahmad Reza committed
403
                print("world.add_tile",self.new_tile.coords)
404
405
406
407
408
409
410
411
412
                logging.info("Created tile with tile id %s on coords %s", str(self.new_tile.get_id()),
                             str(self.new_tile.coords))
                return True
            else:
                logging.info("on x %f and y %f coordinates is a tile already", x, y)
                return False

    def remove_tile(self,id):
        """
Ahmad Reza's avatar
Ahmad Reza committed
413
        Removes a tile with a given tile_id from to the world database
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431

        :param tile_id: The tiles id that should be removec
        :return:  True: Successful removed; False: Unsuccessful
        """
        if id in self.tile_map_id:
            rm_tile = self.tile_map_id[id]
            rm_tile.touch()
            self.tiles.remove(rm_tile)
            self.tiles_rm.append(rm_tile)
            logging.info("Deleted tile with tile id %s on %s", str(rm_tile.get_id()), str(rm_tile.coords) )
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.tile_map_id[rm_tile.get_id()]
            except KeyError:
                pass
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.tile_map_coords[rm_tile.coords]
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
432
433
            self.csv_round.update_tiles_num(len(self.tiles))
            self.csv_round.update_metrics(tile_deleted=1)
434
435
436
437
438
439
440
            self.__tile_deleted = True
            return True
        else:
            return False

    def remove_tile_on(self, coords):
        """
Ahmad Reza's avatar
Ahmad Reza committed
441
        Removes a tile on a give coordinat from to the world database
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

        :param coords: A tupel that includes the x and y coorindates
        :return: True: Successful removed; False: Unsuccessful
        """
        if coords in self.tile_map_coords:
            self.tiles.remove(self.tile_map_coords[coords])
            self.tiles_rm.append(self.tile_map_coords[coords])
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.tile_map_id[self.tile_map_coords[coords].get_id()]
            except KeyError:
                pass
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
                del self.tile_map_coords[coords]
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
457
458
            self.csv_round.update_tiles_num(len(self.tiles))
            self.csv_round.update_metrics( tile_deleted=1)
459
460
461
462
463
            self.__tile_deleted = True
            return True
        else:
            return False

464
    def add_marker(self, x, y, color=black, alpha=1):
465
        """
Ahmad Reza's avatar
Ahmad Reza committed
466
        Add a tile to the world database
467
468
469
470
471
472
473
474

        :param color:
        :param x: the x coordinates on which the tile should be added
        :param y: the y coordinates on which the tile should be added
        :return: True: Successful added; False: Unsuccsessful
        """
        if alpha < 0 or alpha >1:
            alpha = 1
475
        if check_values_are_coordinates(x, y) == True:
476
            if (x, y) not in self.marker_map_coords:
477
                self.new_marker = marker.Marker(self, x, y, color, alpha)
478
479
480
                self.markers.append(self.new_marker)
                self.marker_map_coords[self.new_marker.coords] = self.new_marker
                self.marker_map_id[self.new_marker.get_id()] = self.new_marker
Ahmad Reza's avatar
Ahmad Reza committed
481
                self.csv_round.update_markers_num(len(self.markers))
482
483
484
485
486
                logging.info("Created marker with id %s on coords %s", str(self.new_marker.get_id()), str(self.new_marker.coords))

                self.new_marker.created = True
                self.new_marker.touch()
                return self.new_marker
487
            else:
488
                logging.info("on x %f and y %f coordinates is a marker already", x, y)
489
490
491
                return False
        else:
            logging.info("for x %f and y %f not possible to draw ", x, y)
492
493
            return False

494
    def remove_marker(self, id):
495
        """
Ahmad Reza's avatar
Ahmad Reza committed
496
        Removes a tile with a given tile_id from to the world database
497

498
        :param id: The markers id that should be removec
499
500
        :return:  True: Successful removed; False: Unsuccessful
        """
501
502
503
504
505
        if id in self.marker_map_id:
            rm_marker = self.marker_map_id[id]
            rm_marker.touch()
            if rm_marker in self.markers:
                self.markers.remove(rm_marker)
506

507
508
            self.markers_rm.append(rm_marker)
            logging.info("Deleted marker with marker id %s on %s", str(id), str(rm_marker.coords))
509
            try:
510
                del self.marker_map_coords[rm_marker.coords]
511
512
513
            except KeyError:
                pass
            try:
514
                del self.marker_map_id[id]
515
516
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
517
518
            self.csv_round.update_markers_num(len(self.markers))
            self.csv_round.update_metrics( marker_deleted=1)
519
            self.__marker_deleted = True
520
521
522
523
            return True
        else:
            return False

524
    def remove_marker_on(self, coords):
525
        """
Ahmad Reza's avatar
Ahmad Reza committed
526
        Removes a marker on a give coordinat from to the world database
527
528
529
530

        :param coords: A tupel that includes the x and y coorindates
        :return: True: Successful removed; False: Unsuccessful
        """
531
532
533
        if coords in self.marker_map_coords:
            self.markers.remove(self.marker_map_coords[coords])
            self.markers_rm.append(self.marker_map_coords[coords])
534
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
535
                del self.marker_map_id[self.marker_map_coords[coords].get_id()]
536
537
538
            except KeyError:
                pass
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
539
                del self.marker_map_coords[coords]
540
541
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
542
543
            self.csv_round.update_markers_num(len(self.markers))
            self.csv_round.update_metrics( marker_deleted=1)
544
            self.__marker_deleted = True
545
546
547
            return True
        else:
            return False