world.py 19.5 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
Ahmad Reza's avatar
Ahmad Reza committed
12
from lib.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
        """
Ahmad Reza's avatar
Ahmad Reza committed
29
        random.seed(config_data.seed_value)
Ahmad Reza's avatar
Ahmad Reza committed
30
31
        self.__round_counter = 1
        self.__end = False
Ahmad Reza's avatar
Ahmad Reza committed
32

33
        self.init_particles=[]
34
        self.particle_id_counter = 0
35
36
37
38
39
40
        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
41

42
43
44
45
46
47
        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
48
49
        self.new_tile = None

50
51
52
53
54
55
        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
56

57
        self.config_data = config_data
58

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

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

        if self.config_data.random_order:
68
69
            random.shuffle(self.particles)

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

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

80
    def success_termination(self):
Ahmad Reza's avatar
Ahmad Reza committed
81
        self.csv_round.success()
82
        self.set_end()
Ahmad Reza's avatar
Ahmad Reza committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

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

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

    def set_end(self):
        """
        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

    def inc_round_cnter(self):
        """
        Increases the the round counter by

        :return:
        """
        self.__round_counter +=  1

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

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

120
    def get_amount_of_particles(self):
121
        """
Ahmad Reza's avatar
Ahmad Reza committed
122
        Returns the actual number of particles in the world
123
124
125

        :return: The actual number of Particles
        """
126
        return len(self.particles)
127
128
129

    def get_particle_list(self):
        """
Ahmad Reza's avatar
Ahmad Reza committed
130
        Returns the actual number of particles in the world
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

        :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

152
    def get_amount_of_tiles(self):
153
        """
Ahmad Reza's avatar
Ahmad Reza committed
154
        Returns the actual number of particles in the world
155
156
157

        :return: The actual number of Particles
        """
158
        return len(self.tiles)
159
160
161

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

Ahmad Reza's avatar
Ahmad Reza committed
164
        :return: a list of all the tiles in the world
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        """
        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

184
    def get_amount_of_markers(self):
185
        """
Ahmad Reza's avatar
Ahmad Reza committed
186
        Returns the actual number of markers in the world
187

188
        :return: The actual number of markers
189
        """
190
        return len(self.markers)
191

192
    def get_marker_list(self):
193
        """
Ahmad Reza's avatar
Ahmad Reza committed
194
        Returns the actual number of markers in the world
195

196
        :return: The actual number of markers
197
        """
198
        return self.markers
199

200
    def get_marker_map_coords(self):
201
        """
202
        Get a dictionary with all markers mapped with their actual coordinates
203

204
        :return: a dictionary with markers and their coordinates
205
        """
206
        return self.marker_map_coords
207

208
    def get_marker_map_id(self):
209
        """
210
        Get a dictionary with all markers mapped with their own ids
211

212
        :return: a dictionary with markers and their own ids
213
        """
214
        return self.marker_map_id
215
216
217
218
219
220
221
222
223
224
225

    def get_coords_in_dir(self, coords, dir):
        """
        Returns the coordination data of the pointed directions

        :param coords: particles actual staying coordination
        :param dir: The direction. Options:  E, SE, SW, W, NW, or NE
        :return: The coordinaiton of the pointed directions
        """
        return coords[0] + x_offset[dir], coords[1] + y_offset[dir]

226
    def get_world_x_size(self):
227
228
        """

Ahmad Reza's avatar
Ahmad Reza committed
229
        :return: Returns the maximal x size of the world
230
        """
Ahmad Reza's avatar
Ahmad Reza committed
231
        return self.config_data.size_x
232

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

    def get_tile_deleted(self):
        return self.__tile_deleted

    def get_particle_deleted(self):
        return self.__particle_deleted

245
246
    def get_marker_deleted(self):
        return self.__marker_deleted
247
248
249
250
251
252
253

    def set_tile_deleted(self):
        self.__tile_deleted = False

    def set_particle_deleted(self):
        self.__particle_deleted=False

254
255
    def set_marker_deleted(self):
        self.__marker_deleted = False
256

257
    def add_particle(self, x, y, color=black, alpha=1):
258
        """
Ahmad Reza's avatar
Ahmad Reza committed
259
        Add a particle to the world database
260
261
262
263
264
265

        :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
266
        :return: Added Matter; False: Unsuccsessful
267
268
269
        """
        if alpha < 0 or alpha >1:
            alpha = 1
Ahmad Reza's avatar
Ahmad Reza committed
270
        if len(self.particles) < self.config_data.max_particles:
271
            if check_coords(x,y) == True:
272
                if (x,y) not in self.get_particle_map_coords():
273
274
275
                    self.particle_id_counter += 1
                    new_particle = particle.Particle(self, x, y, color, alpha, self.particle_id_counter)
                    print(new_particle.number)
276
277
278
279
280
                    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
281
                    self.csv_round.update_particle_num(len(self.particles))
282
283
284
                    self.init_particles.append(new_particle)
                    new_particle.created=True
                    logging.info("Created particle at %s", new_particle.coords)
285
                    return new_particle
286
287
288
289
290
291
292
293
294
295
296
                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
297
        """ Removes a particle with a given particle id from the world database
298
299
300
301
302
303
304
305
306
307
308
309
310
311


        :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
312
313
            self.csv_round.update_particle_num(len(self.particles))
            self.csv_round.update_metrics(particle_deleted=1)
314
315
316
317
318
319
320
            self.__particle_deleted = True
            return True
        else:
            return False

    def remove_particle_on(self, coords):
        """
Ahmad Reza's avatar
Ahmad Reza committed
321
        Removes a particle on a give coordinat from to the world database
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

        :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
337
338
            self.csv_round.update_particle_num(len(self.particles))
            self.csv_round.update_metrics( particle_deleted=1)
339
340
341
342
343
344
345
            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
346
        Adds a tile to the world database
347
348
349
350

        :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
351
        :return: Successful added matter; False: Unsuccsessful
352
        """
353
        if alpha < 0 or alpha >1:
354
            alpha = 1
355
        if check_coords(x,y) == True:
356
            if (x,y) not in self.tile_map_coords:
Ahmad Reza Cheraghi's avatar
Ahmad Reza Cheraghi committed
357
                self.new_tile=tile.Tile(self, x, y, color, alpha)
358
359
                print("Before adding ", len(self.tiles) )
                self.tiles.append(self.new_tile)
Ahmad Reza's avatar
Ahmad Reza committed
360
                self.csv_round.update_tiles_num(len(self.tiles))
361
362
363
364
365
366
                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()
367
                return self.new_tile
368
369
370
371
372
373
374
375
376
            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
377
        Adds a tile to the world database
378
379
380
381
382
383

        :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
        """
384
        if check_coords(x, y) == True:
385
            if (x, y) not in self.tile_map_coords:
Ahmad Reza Cheraghi's avatar
Ahmad Reza Cheraghi committed
386
                self.new_tile = tile.Tile(self, x, y, color, alpha)
387
388
389
390
391
                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
392
                print("world.add_tile",self.new_tile.coords)
393
394
395
396
397
398
399
400
401
                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
402
        Removes a tile with a given tile_id from to the world database
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420

        :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
421
422
            self.csv_round.update_tiles_num(len(self.tiles))
            self.csv_round.update_metrics(tile_deleted=1)
423
424
425
426
427
428
429
            self.__tile_deleted = True
            return True
        else:
            return False

    def remove_tile_on(self, coords):
        """
Ahmad Reza's avatar
Ahmad Reza committed
430
        Removes a tile on a give coordinat from to the world database
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

        :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
446
447
            self.csv_round.update_tiles_num(len(self.tiles))
            self.csv_round.update_metrics( tile_deleted=1)
448
449
450
451
452
            self.__tile_deleted = True
            return True
        else:
            return False

453
    def add_marker(self, x, y, color=black, alpha=1):
454
        """
Ahmad Reza's avatar
Ahmad Reza committed
455
        Add a tile to the world database
456
457
458
459
460
461
462
463

        :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
464
        if check_coords(x, y) == True:
465
            if (x, y) not in self.marker_map_coords:
466
                self.new_marker = marker.Marker(self, x, y, color, alpha)
467
468
469
                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
470
                self.csv_round.update_markers_num(len(self.markers))
471
472
473
474
475
                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
476
            else:
477
                logging.info("on x %f and y %f coordinates is a marker already", x, y)
478
479
480
                return False
        else:
            logging.info("for x %f and y %f not possible to draw ", x, y)
481
482
            return False

483
    def remove_marker(self, id):
484
        """
Ahmad Reza's avatar
Ahmad Reza committed
485
        Removes a tile with a given tile_id from to the world database
486

487
        :param id: The markers id that should be removec
488
489
        :return:  True: Successful removed; False: Unsuccessful
        """
490
491
492
493
494
        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)
495

496
497
            self.markers_rm.append(rm_marker)
            logging.info("Deleted marker with marker id %s on %s", str(id), str(rm_marker.coords))
498
            try:
499
                del self.marker_map_coords[rm_marker.coords]
500
501
502
            except KeyError:
                pass
            try:
503
                del self.marker_map_id[id]
504
505
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
506
507
            self.csv_round.update_markers_num(len(self.markers))
            self.csv_round.update_metrics( marker_deleted=1)
508
            self.__marker_deleted = True
509
510
511
512
            return True
        else:
            return False

513
    def remove_marker_on(self, coords):
514
        """
Ahmad Reza's avatar
Ahmad Reza committed
515
        Removes a marker on a give coordinat from to the world database
516
517
518
519

        :param coords: A tupel that includes the x and y coorindates
        :return: True: Successful removed; False: Unsuccessful
        """
520
521
522
        if coords in self.marker_map_coords:
            self.markers.remove(self.marker_map_coords[coords])
            self.markers_rm.append(self.marker_map_coords[coords])
523
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
524
                del self.marker_map_id[self.marker_map_coords[coords].get_id()]
525
526
527
            except KeyError:
                pass
            try:  # cher: added so the program does not crashed if it does not find any entries in the map
528
                del self.marker_map_coords[coords]
529
530
            except KeyError:
                pass
Ahmad Reza's avatar
Ahmad Reza committed
531
532
            self.csv_round.update_markers_num(len(self.markers))
            self.csv_round.update_metrics( marker_deleted=1)
533
            self.__marker_deleted = True
534
535
536
            return True
        else:
            return False