From 06c33962035b085b4721448aee5e09b15619b844 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Schr=C3=B6der?=
 <fschroeder@techfak.uni-bielefeld.de>
Date: Thu, 7 Dec 2023 15:28:30 +0100
Subject: [PATCH] changed pick_up method to return the item in the players
 hand. Plates are now stackable on the PlateReturn. occupied by is now a list
 in the plate return

---
 overcooked_simulator/counters.py              | 52 +++++++++++--------
 overcooked_simulator/game_items.py            |  4 +-
 .../overcooked_environment.py                 | 36 +++++++++----
 overcooked_simulator/player.py                | 10 ++--
 overcooked_simulator/pygame_gui/pygame_gui.py |  8 ++-
 5 files changed, 68 insertions(+), 42 deletions(-)

diff --git a/overcooked_simulator/counters.py b/overcooked_simulator/counters.py
index 49cbd6f0..8e0722de 100644
--- a/overcooked_simulator/counters.py
+++ b/overcooked_simulator/counters.py
@@ -30,7 +30,7 @@ class Counter:
         self.occupied_by = None
         return give_player
 
-    def can_drop_off(self, item: HoldableItem):
+    def can_drop_off(self, item: HoldableItem) -> bool:
         """Checks whether an item by the player can be dropped of. More relevant for example with
         ingredient dispensers, which should always be occupied and cannot take an item.
 
@@ -42,7 +42,7 @@ class Counter:
         """
         return self.occupied_by is None or self.occupied_by.can_combine(item)
 
-    def drop_off(self, item: HoldableItem):
+    def drop_off(self, item: HoldableItem) -> HoldableItem | None:
         """Takes the thing dropped of by the player.
 
         Args:
@@ -55,6 +55,7 @@ class Counter:
             self.occupied_by = item
         elif self.occupied_by.can_combine(item):
             self.occupied_by.combine(item)
+        return None
 
     def interact_start(self):
         """Starts an interaction by the player. Nothing happens for the standard counter."""
@@ -100,14 +101,14 @@ class CuttingBoard(Counter):
 
 
 class ServingWindow(Counter):
-    def drop_off(self, item):
-        return 5
+    def drop_off(self, item) -> HoldableItem | None:
+        return None
 
     def can_score(self, item):
         if isinstance(item, Plate) and isinstance(item.holds, ProgressibleItem):
             return item.holds.finished
 
-    def can_drop_off(self, item: HoldableItem):
+    def can_drop_off(self, item: HoldableItem) -> bool:
         return self.can_score(item)
 
     def pick_up(self):
@@ -120,7 +121,7 @@ class ServingWindow(Counter):
 class PlateReturn(Counter):
     def __init__(self, pos):
         super().__init__(pos)
-        self.occupied_by = Plate()
+        self.occupied_by = [Plate()]
 
     def pick_up(self):
         """Gets called upon a player performing the pickup action. Gives back a plate (possibly with ingredient.
@@ -128,20 +129,28 @@ class PlateReturn(Counter):
         Returns: A plate possibly with an ingredient on it.
 
         """
-        give_player = self.occupied_by
-        self.occupied_by = Plate()
+        give_player = self.occupied_by.pop()
+        if not self.occupied_by:
+            self.occupied_by.append(Plate())
         return give_player
 
-    def drop_off(self, item: HoldableItem):
+    def drop_off(self, item: HoldableItem) -> HoldableItem | None:
         """Takes the ingredient dropped of by the player.
 
         Args:
             item: The ingredient to be placed on the counter.
         """
-        if item is Plate() and self.occupied_by is Plate():
-            self.occupied_by = None
-
-    def can_drop_off(self, item: HoldableItem):
+        if isinstance(item, Plate):
+            if self.occupied_by[-1].holds:
+                return item
+            self.occupied_by.append(item)
+            return None
+        if self.occupied_by[-1].can_combine(item):
+            self.occupied_by[-1].combine(item)
+            return None
+        return item
+
+    def can_drop_off(self, item: HoldableItem) -> bool:
         """Checks whether an ingredient by the player can be dropped of.
 
         Args:
@@ -152,8 +161,8 @@ class PlateReturn(Counter):
         """
         # possibility to drop off empty plate on empty plate return
         return (
-            isinstance(self.occupied_by, Plate) and isinstance(item, Plate)
-        ) or self.occupied_by.can_combine(item)
+            isinstance(self.occupied_by[-1], Plate) and isinstance(item, Plate)
+        ) or self.occupied_by[-1].can_combine(item)
 
     def __repr__(self):
         return "PlateReturn"
@@ -166,10 +175,10 @@ class TomatoDispenser(Counter):
     def pick_up(self):
         return Tomato()
 
-    def drop_off(self, item: HoldableItem):
-        return 0
+    def drop_off(self, item: HoldableItem) -> HoldableItem | None:
+        return None
 
-    def can_drop_off(self, item: HoldableItem):
+    def can_drop_off(self, item: HoldableItem) -> bool:
         return False
 
     def __repr__(self):
@@ -180,12 +189,13 @@ class Trash(Counter):
     def pick_up(self):
         pass
 
-    def drop_off(self, item: HoldableItem):
+    def drop_off(self, item: HoldableItem) -> HoldableItem | None:
         if isinstance(item, Plate):
             item.holds = None
-        return -1
+            return item
+        return None
 
-    def can_drop_off(self, item: HoldableItem):
+    def can_drop_off(self, item: HoldableItem) -> bool:
         return True
 
     def __repr__(self):
diff --git a/overcooked_simulator/game_items.py b/overcooked_simulator/game_items.py
index 91286708..986692a6 100644
--- a/overcooked_simulator/game_items.py
+++ b/overcooked_simulator/game_items.py
@@ -9,9 +9,9 @@ class HoldableItem:
 
 
 class Plate(HoldableItem):
-    def __init__(self):
+    def __init__(self, holds: HoldableItem = None):
         self.clean = True
-        self.holds = None
+        self.holds = holds
 
         super().__init__()
 
diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py
index 1150547e..8074de7f 100644
--- a/overcooked_simulator/overcooked_environment.py
+++ b/overcooked_simulator/overcooked_environment.py
@@ -13,20 +13,22 @@ from overcooked_simulator.counters import (
     Counter,
     CuttingBoard,
     Trash,
-    ServingWindow,
     TomatoDispenser,
+    ServingWindow,
     PlateReturn,
 )
 
-SYMBOL_TO_CHARACTER_MAP = {
-    "C": Counter,
-    "B": CuttingBoard,
-    "X": Trash,
-    "W": ServingWindow,
-    "T": TomatoDispenser,
-    "P": PlateReturn,
-    "E": None,
-}
+
+class GameScore:
+    def __init__(self):
+        self.score = 0
+
+    def increment_score(self, score: int):
+        self.score += score
+        print(self.score)
+
+    def read_score(self):
+        return self.score
 
 
 class Action:
@@ -57,6 +59,18 @@ class Environment:
         self.players: dict[str, Player] = {}
         self.counter_side_length: int = 40
         self.layout_path: Path = layout_path
+
+        self.game_score = GameScore()
+        self.SYMBOL_TO_CHARACTER_MAP = {
+            "C": Counter,
+            "B": CuttingBoard,
+            "X": Trash,
+            "W": lambda pos: ServingWindow(pos, self.game_score),
+            "T": TomatoDispenser,
+            "P": PlateReturn,
+            "E": None,
+        }
+
         self.counters: list[Counter] = self.create_counters(self.layout_path)
         self.score: int = 0
         self.world_width: int = 800
@@ -82,7 +96,7 @@ class Environment:
             for character in line:
                 character = character.capitalize()
                 pos = np.array([current_x, current_y])
-                counter_class = SYMBOL_TO_CHARACTER_MAP[character]
+                counter_class = self.SYMBOL_TO_CHARACTER_MAP[character]
                 if counter_class is not None:
                     counter = counter_class(pos)
                     counters.append(counter)
diff --git a/overcooked_simulator/player.py b/overcooked_simulator/player.py
index 69c65e5c..ab028d71 100644
--- a/overcooked_simulator/player.py
+++ b/overcooked_simulator/player.py
@@ -3,8 +3,8 @@ from typing import Optional
 import numpy as np
 import numpy.typing as npt
 
-from overcooked_simulator.counters import Counter, Trash
-from overcooked_simulator.game_items import HoldableItem, Plate
+from overcooked_simulator.counters import Counter
+from overcooked_simulator.game_items import HoldableItem
 
 
 class Player:
@@ -78,11 +78,7 @@ class Player:
             self.holding = counter.pick_up()
 
         elif counter.can_drop_off(self.holding):
-            if isinstance(counter, Trash) and isinstance(self.holding, Plate):
-                self.holding.holds = None
-            else:
-                counter.drop_off(self.holding)
-                self.holding = None
+            self.holding = counter.drop_off(self.holding)
 
         elif self.holding.can_combine(counter.occupied_by):
             returned_by_counter = counter.pick_up()
diff --git a/overcooked_simulator/pygame_gui/pygame_gui.py b/overcooked_simulator/pygame_gui/pygame_gui.py
index be8b4238..0d61d2e5 100644
--- a/overcooked_simulator/pygame_gui/pygame_gui.py
+++ b/overcooked_simulator/pygame_gui/pygame_gui.py
@@ -284,7 +284,13 @@ class PyGameGUI:
             pygame.draw.rect(self.screen, YELLOW, board_rect)
 
         if counter.occupied_by is not None:
-            self.draw_item(counter.pos, counter.occupied_by)
+            if isinstance(counter.occupied_by, list):
+                for i, o in enumerate(counter.occupied_by):
+                    self.draw_item(
+                        np.abs([counter.pos[0], counter.pos[1] - (i * 3)]), o
+                    )
+            else:
+                self.draw_item(counter.pos, counter.occupied_by)
 
     def draw_counters(self, state):
         """Visualizes the counters in the environment.
-- 
GitLab