import time from typing import Tuple from Objects.Cube.Cube import Cube from Objects.World import World import numpy as np import random class LabyrinthWorld(World): randomBuffer = 0 batchsize = 1000 randomBuffer = max(4 * batchsize, randomBuffer) def __init__(self, chunk_size_x: int, chunk_size_y: int, chunk_size_z: int, chunk_n_x: int, chunk_n_y: int, chunk_n_z: int, programs: dict): self.board_shape = (chunk_size_x * chunk_n_x, chunk_size_y * chunk_n_y) self.board = np.zeros(self.board_shape) super(LabyrinthWorld, self).__init__(chunk_size_x, chunk_size_y, chunk_size_z, chunk_n_x, chunk_n_y, chunk_n_z, programs) self.max_room_dim = 20 self.min_room_dim = 6 self.max_room_num = 32 self.max_corridors = 4 * self.max_room_num self.max_crates = self.max_room_num self.model = None self.lastUpdate = time.time() self.nextTrain = self.randomBuffer self.round = 1 # self.evolve_timer = 10 self.evolve_timer = 1500 self.trailMix = np.zeros(self.board_shape) self.grass = np.zeros(self.board_shape) self.hunter_grass = np.zeros(self.board_shape) self.subjectDict = {} self._hunters = None self._herbivores = None @property def hunters(self): if self._hunters is None: return [] return self._hunters.subjects @property def herbivores(self): if self._herbivores is None: return [] return self._herbivores.subjects @property def subjects(self): return self.hunters + self.herbivores def generate(self, seed: int = None, sea_plate_height: int = 50, continental_plate_height: int = 200): board = np.zeros(self.board_shape) random.seed(seed) np.random.seed(seed) # find random starting point px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim) py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim) # 0, 0 is top left right = (1, 0) left = (-1, 0) up = (0, -1) down = (0, 1) # place rooms room_num = 0 corridor_num = 0 while room_num < self.max_room_num and corridor_num < self.max_corridors: # try to place Room w = random.randint(self.min_room_dim, self.max_room_dim) h = random.randint(self.min_room_dim, self.max_room_dim) can_place_room = np.sum( board[px - int(w / 2.0):px + int(w / 2.0), py - int(h / 2.0):py + int(h / 2.0)] == 1) == 0 and px - int( w / 2.0) >= 0 and px + int(w / 2.0) < self.board_shape[0] and \ py - int(h / 2.0) >= 0 and py + int(h / 2.0) < self.board_shape[1] if can_place_room: # place Room board[px - int(w / 2.0):px + int(w / 2.0), py - int(h / 2.0):py + int(h / 2.0)] = 1 room_num += 1 else: # move && place Corridor directions = [] while len(directions) == 0: movable = [] corridor_length = random.randint(self.min_room_dim, self.max_room_dim) if px - corridor_length >= 0: movable.append(left) if board[px - 1, py] != 2: directions.append(left) if px + corridor_length < self.board_shape[0]: movable.append(right) if board[px + 1, py] != 2: directions.append(right) if py - corridor_length >= 0: movable.append(up) if board[px, py - 1] != 2: directions.append(up) if py + corridor_length < self.board_shape[1]: movable.append(down) if board[px, py + 1] != 2: directions.append(down) if len(directions) != 0: if len(directions) > 1: d = directions[random.randint(0, len(directions) - 1)] else: d = directions[0] changed = False for _ in range(corridor_length): if board[px, py] != 1 and board[px, py] != 2: board[px, py] = 2 if (-d[0], -d[1]) not in movable or board[px - d[0], py - d[1]] != 2: changed = True px += d[0] py += d[1] if changed: corridor_num += 1 else: if len(movable) != 0: if len(movable) > 1: d = movable[random.randint(0, len(movable) - 1)] else: d = movable[0] for _ in range(corridor_length): px += d[0] py += d[1] crates = 0 while crates < self.max_crates: px = random.randint(0, (self.board_shape[0] - 1)) py = random.randint(0, (self.board_shape[1] - 1)) if board[px, py] == 1: board[px, py] = 3 crates += 1 board[board == 2] = 1 print((room_num, self.max_room_num)) print((corridor_num, self.max_corridors)) self.board = board # setting up the board for x_pos in range(0, self.board_shape[0]): for y_pos in range(0, self.board_shape[1]): for z_pos in range(0, 1): self.put_object(x_pos, y_pos, z_pos, Cube().setColor(1, 1, 1)) # adding subjects from labirinth_ai.Subject import Hunter, Herbivore from labirinth_ai.Population import Population self._hunters = Population(Hunter, self, 10, do_evolve=False) self._herbivores = Population(Herbivore, self, 40, do_evolve=False) self.subjectDict = self.build_subject_dict() def generate_free_coordinates(self) -> Tuple[int, int]: while True: px = random.randint(self.max_room_dim, self.board_shape[0] - self.max_room_dim) py = random.randint(self.max_room_dim, self.board_shape[1] - self.max_room_dim) if self.board[px, py] == 1: return px, py def build_subject_dict(self): subject_dict = {} for x in range(self.board_shape[0]): for y in range(self.board_shape[1]): subject_dict[(x, y)] = [] for sub in self.subjects: subject_dict[(sub.x, sub.y)].append(sub) return subject_dict def update(self): if self.round % self.evolve_timer == 0: print('Evolve population') self.round = 0 self._hunters.evolve() self._herbivores.evolve() self.subjectDict = self.build_subject_dict() self.round += 1 # start = time.time() for sub in self.subjects: sub.calculateAction(self) for sub in self.subjects: if sub.alive: sub.update(self) sub.tick += 1 kill_table = {} live_table = {} for sub in self.subjects: if sub.name not in kill_table.keys(): kill_table[sub.name] = 0 live_table[sub.name] = 0 kill_table[sub.name] += sub.kills live_table[sub.name] += sub.lives if not sub.alive: px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim) py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim) while self.board[px, py] == 0: px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim) py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim) sub.respawnUpdate(px, py, self) self.trailMix *= 0.99 self.grass = np.minimum(self.grass + 0.01 * (self.board != 0), 3) self.hunter_grass = np.minimum(self.hunter_grass + 0.01 * (self.board != 0), 3) self.trailMix *= (self.trailMix > 0.01)