From e5c53653c34a3fd1694cb7c59b5b0aaed8db8760 Mon Sep 17 00:00:00 2001 From: Vadzim Valchkovich Date: Fri, 16 Jun 2023 00:18:34 +0200 Subject: [PATCH] genetic algorithm preparation #2 --- agent.py | 9 +-- src/Engine.py | 17 +++++- src/controller/LayoutController.py | 97 +++++++++++++++++++++++++----- src/controller/StateController.py | 2 + src/obj/Kitchen.py | 5 ++ src/obj/Waiter.py | 23 ++++++- 6 files changed, 130 insertions(+), 23 deletions(-) diff --git a/agent.py b/agent.py index e97a787..660b8dd 100644 --- a/agent.py +++ b/agent.py @@ -13,15 +13,16 @@ store = ImageController(SQUARE_SIZE) waiter = Waiter([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE, store) kitchen = Kitchen([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE, store) engine = Engine(SCREEN_SIZE, SQUARE_SIZE, kitchen, waiter, ACTION_DURATION) -layout = LayoutController(engine, store).create_and_subscribe(COUNT_OF_OBJECTS) +layout = LayoutController(engine, store).create_and_subscribe( + radius=2, neighbors_count=3, block_chance=30) -# engine.loop() +engine.loop() -# ''' +''' def example_stop(action_clock: int) -> bool: return action_clock < 1000 print(engine.train_loop(example_stop)) -# ''' +''' diff --git a/src/Engine.py b/src/Engine.py index 16be145..da2f699 100644 --- a/src/Engine.py +++ b/src/Engine.py @@ -1,3 +1,4 @@ +import copy import time import pygame from queue import PriorityQueue @@ -81,18 +82,32 @@ class Engine: print(colored("Simulation started", "green")) real_action_duration = self.action_duration + real_waiter_state = self.waiter.makeCopy() + self.action_duration = 0 + self.serviced_tables = 0 self.is_simulation = True self.predictor_c.is_simulation = True while stop_condition(self.action_clock): self.action() + result = self.serviced_tables + self.action_duration = real_action_duration + self.serviced_tables = 0 self.is_simulation = False self.predictor_c.is_simulation = False + self.waiter.applyState(real_waiter_state) + self.kitchen.restoreDefaultState() - return self.serviced_tables + self.unsubscribe_all() + + return result + + def unsubscribe_all(self): + self.objects: list[Object] = [] + self.goal: Goal = None def user_interaction(self): self.user_c.handler(engine=self) diff --git a/src/controller/LayoutController.py b/src/controller/LayoutController.py index 874c4d2..1c2a374 100644 --- a/src/controller/LayoutController.py +++ b/src/controller/LayoutController.py @@ -1,4 +1,6 @@ import random +import time +import numpy as np from src.obj.Block import Block from src.obj.Table import Table @@ -14,34 +16,97 @@ class LayoutController(): self.enginie = engine self.store = store - def create_and_subscribe(self, count): + def create_and_subscribe(self, radius: int, neighbors_count: int, block_probability: int): ''' That function generate a location and a type of objects and subscribe they to action list in the engine - `param: count (int)` - number of objects to be created + `param: radius (int)` - radius in blocks in which we will consider neighbors + `param: neighbors_count (int)` - allowed number of neighbors + `param: block_probability (int)` - probability that the object will be a block in percents ''' num_squares = self.enginie.num_squares square_size = self.enginie.square_size screen_size = self.enginie.screen_size + + pos_matrix = np.full((num_squares, num_squares), -1) + + def getFreeSquare(m): + for i in range(num_squares): + for j in range(num_squares): + if m[i][j] == -1: + return [i, j] + return None + + def neighbors(m, p, r): + n = [] + for ri in range(r + 1): + if (p[0] + ri) >= num_squares: + break + for rj in range(r + 1): + if (p[1] + rj) >= num_squares: + break + + if m[p[0]+ri][p[1]+rj] == -1: + n.append([p[0]+ri, p[1]+rj]) + return n + + def condition(m, p, radius, count): + + counter = count + + for ri in range(radius + 1): + if (p[0] + ri) >= num_squares: + break + for rj in range(radius + 1): + if (p[1] + rj) >= num_squares: + break + if m[p[0]+ri][p[1]+rj] == 1: + counter -= 1 + + return counter > 0 + + pos_matrix[0][0] = 1 + fringe = [[0, 0]] + explored = [] + + while fringe: + + explored.append(random.choice(fringe)) + fringe.remove(explored[-1]) + + n = neighbors(pos_matrix, explored[-1], radius) + while n and condition(pos_matrix, explored[-1], radius, neighbors_count): + child = random.choice(n) + pos_matrix[child[0]][child[1]] = 1 + fringe.append(child) + n.remove(child) + + for child in n: + pos_matrix[child[0]][child[1]] = 0 + + n = [] + + if not fringe: + f = getFreeSquare(pos_matrix) + if f: + fringe.append(f) + + pos_matrix[0][0] = 0 + store = self.store objects = [] - for _ in range(count): - - pos = [0, 0] - - while any([o.on(pos) for o in objects]) or pos == [0, 0]: - pos = [random.randint(1, num_squares - 1), - random.randint(1, num_squares - 1)] - - if (random.randint(0, 1)): - objects.append( - Block(pos, 0, square_size, screen_size, store)) - else: - objects.append( - Table(pos, 0, square_size, screen_size, store)) + for i in range(num_squares): + for j in range(num_squares): + if pos_matrix[i][j] == 1: + if (random.randint(0, 100) >= block_probability): + objects.append( + Block([i, j], 0, square_size, screen_size, store)) + else: + objects.append( + Table([i, j], 0, square_size, screen_size, store)) for o in objects: self.enginie.subscribe(o) diff --git a/src/controller/StateController.py b/src/controller/StateController.py index 4549e88..d0c6f9e 100644 --- a/src/controller/StateController.py +++ b/src/controller/StateController.py @@ -78,6 +78,8 @@ class StateController: if not engine.is_simulation: print(colored("Not found", "red")) + engine.clock_increment(1000) + return False def succ(self, state: TemporaryState, engine): diff --git a/src/obj/Kitchen.py b/src/obj/Kitchen.py index 7944f76..b9a4432 100644 --- a/src/obj/Kitchen.py +++ b/src/obj/Kitchen.py @@ -10,6 +10,11 @@ class Kitchen(Object): self.done: list(Table) = [] self.mark = None + def restoreDefaultState(self): + self.cooking: list(Table) = [] + self.done: list(Table) = [] + self.mark = None + def updateMark(self): if self.done: self.setMark("dish_done") diff --git a/src/obj/Waiter.py b/src/obj/Waiter.py index 10201e7..dff063b 100644 --- a/src/obj/Waiter.py +++ b/src/obj/Waiter.py @@ -13,8 +13,27 @@ class Waiter(Object): self.memory_capacity = 4 self.basket = basket self.memory = memory - self.prev_position = copy.deepcopy(self.position) - self.prev_orientation = copy.copy(self.orientation) + + def makeCopy(self): + return Waiter( + copy.deepcopy(self.position), + copy.copy(self.orientation), + copy.copy(self.square_size), + copy.deepcopy(self.screen_size), + self.store, + copy.deepcopy(self.basket), + copy.deepcopy(self.memory), + copy.copy(self.battery) + ) + + def applyState(self, state): + self.position = state.position + self.orientation = state.orientation + self.battery = state.battery + self.basket_capacity = state.basket_capacity + self.memory_capacity = state.memory_capacity + self.basket = state.basket + self.memory = state.memory def changeState(self, state): if state.agent_role == "blank":