229 lines
8.5 KiB
Python
229 lines
8.5 KiB
Python
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)
|
|
|
|
self._herbivores = Population(Herbivore, self, 40)
|
|
|
|
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)
|