From ac4517abf242578d3a7d749e7041f0098cc3a159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Schr=C3=B6der?= <fschroeder@techfak.uni-bielefeld.de> Date: Tue, 19 Dec 2023 18:41:15 +0100 Subject: [PATCH] add logic required for burger. add also simple burger assets and pan. --- overcooked_simulator/counters.py | 6 +- .../game_content/item_info.yaml | 20 ++++- .../game_content/layouts/basic.layout | 14 ++-- overcooked_simulator/game_items.py | 74 ++++++++++++++---- .../overcooked_environment.py | 18 ++++- .../pygame_gui/visualization.yaml | 76 +++++++++++++++++++ 6 files changed, 176 insertions(+), 32 deletions(-) diff --git a/overcooked_simulator/counters.py b/overcooked_simulator/counters.py index dfe0b24e..f3c0f1bc 100644 --- a/overcooked_simulator/counters.py +++ b/overcooked_simulator/counters.py @@ -131,9 +131,9 @@ class ServingWindow(Counter): ): if isinstance(item.content, Meal) and item.content.progressed_steps: return item.content.finished - - # TODO: Salad can be always be served. Check, if all needed parts are present. - if item.content.name in ["Salad"]: + if not item.item_info.steps_needed and len( + item.content.item_info.needs + ) == len(item.content.parts): return True return False diff --git a/overcooked_simulator/game_content/item_info.yaml b/overcooked_simulator/game_content/item_info.yaml index 4693e59d..cacbf3a8 100644 --- a/overcooked_simulator/game_content/item_info.yaml +++ b/overcooked_simulator/game_content/item_info.yaml @@ -13,12 +13,25 @@ Onion: is_cuttable: True steps_needed: 700 -RawPatty: +Meat: + type: Ingredient + is_cuttable: True + steps_needed: 500 + +CookedPatty: + type: Meal + steps_needed: 500 + needs: [ ChoppedMeat ] + finished_progress_name: CookedPatty + equipment: Pan + +Bun: type: Ingredient Burger: type: Meal needs: [ Bun, ChoppedLettuce, ChoppedTomato, CookedPatty ] + equipment: Plate Salad: type: Meal @@ -36,7 +49,7 @@ OnionSoup: type: Meal finished_progress_name: OnionSoup steps_needed: 500 - needs: [ ChoppedOnion , ChoppedOnion, ChoppedOnion ] + needs: [ ChoppedOnion, ChoppedOnion, ChoppedOnion ] equipment: Pot Plate: @@ -44,3 +57,6 @@ Plate: Pot: type: Equipment + +Pan: + type: Equipment \ No newline at end of file diff --git a/overcooked_simulator/game_content/layouts/basic.layout b/overcooked_simulator/game_content/layouts/basic.layout index 8d31dac9..cccb7a9d 100644 --- a/overcooked_simulator/game_content/layouts/basic.layout +++ b/overcooked_simulator/game_content/layouts/basic.layout @@ -1,11 +1,11 @@ _________________ -_CCUCTNLCC_______ -_C_______C_______ -_C_______C_______ +_#QU#TNLB#_______ +_#_______M_______ +_#_______#_______ _W_______________ -_C__A__A_________ +_#__A__A_________ _P_______________ -_C_______C_______ -_C_______X_______ -_CCBBCCCCC_______ +_#_______#_______ +_#_______X_______ +_##CC#####_______ _________________ diff --git a/overcooked_simulator/game_items.py b/overcooked_simulator/game_items.py index 55b6f745..52c79b99 100644 --- a/overcooked_simulator/game_items.py +++ b/overcooked_simulator/game_items.py @@ -20,7 +20,7 @@ class ItemInfo: needs: list[ItemInfo] = dataclasses.field(compare=False, default_factory=list) equipment: ItemInfo | None = dataclasses.field(compare=False, default=None) - _start_items: list[ItemInfo] = dataclasses.field( + _start_meals: list[ItemInfo] = dataclasses.field( compare=False, default_factory=list ) @@ -32,7 +32,7 @@ class ItemInfo: return self.finished_progress_name.replace("*", self.name) return self.name - def create_item(self) -> Item: + def create_item(self, parts=None) -> Item: match self.type: case ItemType.Ingredient: if self.is_cuttable: @@ -53,22 +53,32 @@ class ItemInfo: steps_needed=self.steps_needed, finished_name=self.get_finished_name(), item_info=self, + parts=parts, ) - def add_start_item_to_equipment(self, start_item: ItemInfo): - self._start_items.append(start_item) + def add_start_meal_to_equipment(self, start_item: ItemInfo): + self._start_meals.append(start_item) - def can_start_meal(self, start_item: Item): + def sort_start_meals(self): + self._start_meals.sort(key=lambda item_info: len(item_info.needs)) + + def can_start_meal(self, items: list[Item]): # TODO check specific order / only specific start items - return any( - [start_item.name == s for meal in self._start_items for s in meal.needs] - ) + return items and self._return_start_meal(items) is not None + + def start_meal(self, items: list[Item]) -> Item: + return self._return_start_meal(items).create_item(parts=items) - def start_meal(self, start_item: Item) -> Item: - for meal in self._start_items: - for s in meal.needs: - if s == start_item.name: - return meal.create_item() + def _return_start_meal(self, items: list[Item]) -> ItemInfo | None: + for meal in self._start_meals: + satisfied = [False for _ in range(len(items))] + for i, p in enumerate(items): + for _, n in enumerate(meal.needs): + if not satisfied[i] and p.name == n: + satisfied[i] = True + break + if all(satisfied): + return meal class Item: @@ -149,14 +159,23 @@ class CookingEquipment(Item): self.content = content def can_combine(self, other): + if other is None: + return False if self.content is None: if isinstance(other, CookingEquipment): return other.can_release_content() # TODO check other is start of a meal, create meal if isinstance(other, Meal) and self.name == "Plate": return not other.steps_needed or other.finished - return self.item_info.can_start_meal(other) - return self.content.can_combine(other) + return self.item_info.can_start_meal([other]) + if self.content.can_combine(other): + return True + if isinstance(other, CookingEquipment) and other.content: + other = other.content + return self.item_info.can_start_meal( + [other] + + ([self.content] if self.content.progressed_steps else self.content.parts) + ) def combine(self, other): if self.content is None: @@ -167,7 +186,30 @@ class CookingEquipment(Item): self.content = other return # find starting meal for other - self.content = self.item_info.start_meal(other) + self.content = self.item_info.start_meal([other]) + return + if not self.content.can_combine(other): + if isinstance(other, CookingEquipment) and other.content: + content = other.release() + self.content = self.item_info.start_meal( + [content] + + ( + [self.content] + if self.content.progressed_steps + else self.content.parts + ) + ) + return other + else: + self.content = self.item_info.start_meal( + [other] + + ( + [self.content] + if self.content.progressed_steps + else self.content.parts + ) + ) + return self.content.combine(other) def can_progress(self, counter_type="Stove") -> bool: diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py index ff5be6b8..c4242b80 100644 --- a/overcooked_simulator/overcooked_environment.py +++ b/overcooked_simulator/overcooked_environment.py @@ -16,7 +16,7 @@ from overcooked_simulator.counters import ( ServingWindow, Stove, ) -from overcooked_simulator.game_items import ItemInfo +from overcooked_simulator.game_items import ItemInfo, ItemType # if TYPE_CHECKING: from overcooked_simulator.player import Player @@ -70,8 +70,8 @@ class Environment: self.game_score = GameScore() self.SYMBOL_TO_CHARACTER_MAP = { - "C": Counter, - "B": CuttingBoard, + "#": Counter, + "C": CuttingBoard, "X": Trash, "W": lambda pos: ServingWindow(pos, self.game_score), "T": lambda pos: Dispenser(pos, self.item_info["Tomato"]), @@ -84,6 +84,12 @@ class Environment: pos, self.item_info["Pot"].create_item(), ), # Stove with pot: U because it looks like a pot + "Q": lambda pos: Stove( + pos, + self.item_info["Pan"].create_item(), + ), # Stove with pot: U because it looks like a pot + "B": lambda pos: Dispenser(pos, self.item_info["Bun"]), + "M": lambda pos: Dispenser(pos, self.item_info["Meat"]), } ( @@ -106,7 +112,11 @@ class Environment: for item_name, item_info in item_lookup.items(): if item_info.equipment: item_info.equipment = item_lookup[item_info.equipment] - item_info.equipment.add_start_item_to_equipment(item_info) + item_info.equipment.add_start_meal_to_equipment(item_info) + for item_name, item_info in item_lookup.items(): + if item_info.type == ItemType.Equipment: + # first select meals with smaller needs / ingredients + item_info.sort_start_meals() return item_lookup def parse_layout_file(self, layout_file: Path): diff --git a/overcooked_simulator/pygame_gui/visualization.yaml b/overcooked_simulator/pygame_gui/visualization.yaml index df6f702c..ba2f0dee 100644 --- a/overcooked_simulator/pygame_gui/visualization.yaml +++ b/overcooked_simulator/pygame_gui/visualization.yaml @@ -1,3 +1,5 @@ +# colors: https://www.webucator.com/article/python-color-constants-module/ + Kitchen: ground_tiles_color: sgigray76 background_lines: gray79 @@ -58,6 +60,20 @@ OnionDispenser: height: 0.8 width: 0.8 +MeatDispenser: + parts: + - color: indianred1 + type: rect + height: 0.8 + width: 0.8 + +BunDispenser: + parts: + - color: sandybrown + type: rect + height: 0.8 + width: 0.8 + ServingWindow: parts: @@ -92,6 +108,15 @@ Onion: radius: 0.25 color: deeppink4 +Bun: + parts: + - type: circle + radius: 0.3 + color: black + - type: circle + radius: 0.25 + color: navajowhite2 + Lettuce: parts: - type: circle @@ -101,6 +126,16 @@ Lettuce: radius: 0.25 color: emeraldgreen +Meat: + parts: + - type: circle + radius: 0.3 + color: black + - type: circle + radius: 0.25 + color: hotpink + + ChoppedLettuce: parts: - type: circle @@ -157,6 +192,33 @@ ChoppedOnion: color: deeppink4 center_offset: [ 5, 0 ] +ChoppedMeat: + parts: + - type: circle + radius: 0.3 + color: black + center_offset: [ -5, 0 ] + - type: circle + radius: 0.25 + color: indianred1 + center_offset: [ -5, 0 ] + - type: circle + radius: 0.3 + color: black + - type: circle + radius: 0.25 + color: indianred1 + +CookedPatty: + parts: + - type: circle + radius: 0.3 + color: black + - type: circle + radius: 0.25 + color: salmon4 + + TomatoSoup: parts: - type: image @@ -186,3 +248,17 @@ Pot: - type: image path: images/pot.png size: 0.8 + +Pan: + parts: + - type: circle + radius: 0.4 + color: black + - type: circle + radius: 0.35 + color: sgigray16 + - color: orange4 + type: rect + height: 0.5 + width: 0.1 + center_offset: [ -0.8, -0.05 ] \ No newline at end of file -- GitLab