From afade5987e79e2a1f4245af2c92cd4901e462b92 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 18:26:21 +0100
Subject: [PATCH] game logic for tomato soup. is not generalized to all soups
 or cookable objects

---
 overcooked_simulator/counters.py              | 36 ++++++++++++++-----
 overcooked_simulator/game_items.py            | 36 ++++++++++++++++---
 .../overcooked_environment.py                 |  2 +-
 overcooked_simulator/player.py                |  2 +-
 4 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/overcooked_simulator/counters.py b/overcooked_simulator/counters.py
index 538c666f..b77bc0ca 100644
--- a/overcooked_simulator/counters.py
+++ b/overcooked_simulator/counters.py
@@ -26,7 +26,7 @@ class Counter:
         self.pos: npt.NDArray[float] = pos
         self.occupied_by: Optional[Item] = occupied_by
 
-    def pick_up(self):
+    def pick_up(self, on_hands: bool = True):
         """Gets called upon a player performing the pickup action. If the counter can give something to
         the player, it does so. In the standard counter this is when an item is on the counter.
 
@@ -113,19 +113,23 @@ class ServingWindow(Counter):
 
     def drop_off(self, item) -> Item | None:
         reward = 5
+        print(item)
         # TODO define rewards
         self.game_score.increment_score(reward)
         return None
 
     def can_score(self, item):
-        if isinstance(item, Plate) and isinstance(item.holds, ProgressibleItem):
-            return item.holds.finished
+        if isinstance(item, Plate):
+            if isinstance(item.holds, ProgressibleItem):
+                return item.holds.finished
+            else:
+                return bool(item.holds)
 
     def can_drop_off(self, item: Item) -> bool:
         return self.can_score(item)
 
-    def pick_up(self):
-        return None
+    def pick_up(self, on_hands: bool = True):
+        pass
 
 
 class PlateReturn(Counter):
@@ -133,7 +137,7 @@ class PlateReturn(Counter):
         super().__init__(pos)
         self.occupied_by = [Plate()]
 
-    def pick_up(self):
+    def pick_up(self, on_hands: bool = True):
         """Gets called upon a player performing the pickup action. Gives back a plate (possibly with ingredient.
 
         Returns: A plate possibly with an ingredient on it.
@@ -179,7 +183,7 @@ class TomatoDispenser(Counter):
     def __init__(self, pos):
         super().__init__(pos)
 
-    def pick_up(self):
+    def pick_up(self, on_hands: bool = True):
         return Tomato()
 
     def drop_off(self, item: Item) -> Item | None:
@@ -190,7 +194,7 @@ class TomatoDispenser(Counter):
 
 
 class Trash(Counter):
-    def pick_up(self):
+    def pick_up(self, on_hands: bool = True):
         pass
 
     def drop_off(self, item: Item) -> Item | None:
@@ -209,6 +213,17 @@ class Stove(Counter):
             occupied_by = Pot()
         super().__init__(pos, occupied_by)
 
+    def pick_up(self, on_hands: bool = True):
+        if on_hands:
+            if self.occupied_by:
+                occupied_by = self.occupied_by
+                self.occupied_by = None
+                return occupied_by
+            return None
+        if self.occupied_by and self.occupied_by.holds:
+            soup = self.occupied_by.holds.pop(0)
+            return soup
+
     def drop_off(self, item) -> Item | None:
         if isinstance(item, (Pot, Pan)):
             self.occupied_by = item
@@ -222,3 +237,8 @@ class Stove(Counter):
         if self.occupied_by:
             return self.occupied_by.can_combine(item)
         return False
+
+    def progress(self):
+        """Called by environment step function for time progression"""
+        if self.occupied_by and self.occupied_by.can_cook():
+            self.occupied_by.progress()
diff --git a/overcooked_simulator/game_items.py b/overcooked_simulator/game_items.py
index cb75a7b4..dc2375a2 100644
--- a/overcooked_simulator/game_items.py
+++ b/overcooked_simulator/game_items.py
@@ -7,6 +7,9 @@ class Item:
     def combine(self, other):
         pass
 
+    def __repr__(self):
+        return self.__class__.__name__
+
 
 class Plate(Item):
     def __init__(self, holds: Item = None):
@@ -15,8 +18,12 @@ class Plate(Item):
 
         super().__init__()
 
-    def can_combine(self, other: Item):
-        return self.holds is None and not isinstance(other, Plate)
+    def can_combine(self, other: Item) -> bool:
+        if self.holds is None:
+            if isinstance(other, (Pot, Pan)):
+                return other.finished
+            return not isinstance(other, Plate)
+        return False
 
     def combine(self, other):
         self.holds = other
@@ -32,19 +39,23 @@ class ProgressibleItem(Item):
         self.progressed_steps = steps_needed if finished else 0
         self.steps_needed = steps_needed
         self.finished = finished
+        self.finished_name = "Cutted"
         super().__init__()
 
     def progress(self):
         """Progresses the item process as long as it is not finished."""
         if self.progressed_steps >= self.steps_needed:
             self.finished = True
-            self.progressed_steps = 0
+            self.finished_call()
         if not self.finished:
             self.progressed_steps += 1
 
+    def finished_call(self):
+        pass
+
     def __repr__(self):
         if self.finished:
-            return f"{self.__class__.__name__}()"
+            return f"{self.finished_name}{self.__class__.__name__}()"
         else:
             return f"{self.__class__.__name__}(progress={int(self.progressed_steps / self.steps_needed * 100)}%)"
 
@@ -69,6 +80,7 @@ class Pot(ProgressibleItem):
     def __init__(self, holds: Item = None):
         self.holds = [] if holds is None else holds
         super().__init__(steps_needed=1500)
+        self.finished_name = "Cooked"
 
     def can_combine(self, other):
         # TODO based on recipes
@@ -79,9 +91,25 @@ class Pot(ProgressibleItem):
             and all([isinstance(h, Tomato) for h in self.holds])
         )
 
+    def finished_call(self):
+        self.holds = [TomatoSoup()]
+
     def combine(self, other):
         self.holds.append(other)
 
+    def can_cook(self) -> bool:
+        return self.holds and len(self.holds) == 3
+
+    def __repr__(self):
+        if self.finished:
+            return f"{self.finished_name}{self.__class__.__name__}({self.holds})"
+        else:
+            return f"{self.__class__.__name__}({self.holds},progress={int(self.progressed_steps / self.steps_needed * 100)}%)"
+
+
+class TomatoSoup(Item):
+    ...
+
 
 class Pan(ProgressibleItem):
     def __init__(self):
diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py
index 48f67595..8d1650e6 100644
--- a/overcooked_simulator/overcooked_environment.py
+++ b/overcooked_simulator/overcooked_environment.py
@@ -324,7 +324,7 @@ class Environment:
         and time limits.
         """
         for counter in self.counters:
-            if isinstance(counter, CuttingBoard):
+            if isinstance(counter, (CuttingBoard, Stove)):
                 counter.progress()
 
     def get_state(self):
diff --git a/overcooked_simulator/player.py b/overcooked_simulator/player.py
index 1213d5ee..8b126070 100644
--- a/overcooked_simulator/player.py
+++ b/overcooked_simulator/player.py
@@ -81,7 +81,7 @@ class Player:
             self.holding = counter.drop_off(self.holding)
 
         elif self.holding.can_combine(counter.occupied_by):
-            returned_by_counter = counter.pick_up()
+            returned_by_counter = counter.pick_up(on_hands=False)
             self.holding.combine(returned_by_counter)
 
     def perform_interact_hold_start(self, counter: Counter):
-- 
GitLab