Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1/2] Customers #35

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

[1/2] Customers #35

wants to merge 13 commits into from

Conversation

lsuyean
Copy link
Contributor

@lsuyean lsuyean commented Jul 17, 2024

Overview

In this PR, I implement Gamemodes and Customers into Robotouille.

Previously, stepping in the environment was controlled using the step() function within the State class. However, this was problematic because it was controlling more than just updates to the state, especially with new modules like Movement. Now, there is a new module called GameMode that controls all modules within Robotouille.

The GameMode class also lets Robotouille have win conditions. In this PR, I implement a basic gamemode called `Classic' where the player must serve a number of customers within a certain amount of time.

Changes Made

Customers

  • Added new assets for customers, the customer table, and customer spawn
    • Customer spawn asset is temporary, is currently a screenshot of the floor tiling. Should be replaced by a transparent asset in the future so that it does not render in game.
  • Implemented Customer class which keeps track about information about the customers and steps them in the environment
  • Edited domain.py and domain_builder.py to now keep track of npc_actions, all actions that the npc can do as defined in the domain
  • Edited movement.py to also move customers
  • Edited state.py to keep track of customers and customer_actions
  • Added recipes.json where recipes can be specified
  • Edited robotouille.json to include Customer type, predicates, and actions
  • Edited builder.py and object_enmus.py to include Customer type
  • Added new environments customer.json and multi_customer.json to test customers
  • Edited renderer.py, canvas.py, robotouille_env.py and robotouille_config.json to render customers

GameMode

  • Implemented GameMode class that serves as the overall control of the game, keeps track of win conditions, and steps all the modules in the game
  • Implemented Classic subclass where a player must satisfy all recipes before a given time
  • Moved stepping logic of the Movement class from state.py to classic.py
  • Edited all environments to now also specify the gamemode
  • Added a new file env_utils.py to prevent circular imports when creating the GameMode and Customers
  • Edited robotouille_simulator.py to pass pygame.time into the gamemode class
  • Gamemode now also contains all information that was previously stored as class variables in the Player, Station, and Customer class

Changes to Containers

  • Added new actions for stacking in robotouille.json so that containers can now be picked up and placed with items on it
  • Added new inputs for new stacking actions in input.json
  • Edited canvas.py to properly render containers and items stacked on containers

Changes to Robotouille Domain

  • Implemented a new predicate based deletion effect, where for a predicate and one argument, all objects where the predicate is true for that argument is deleted

Test Coverage

Tested with all environments

Next Steps

  • Find a nicer solution for customers leaving the game (should reach the edge of the environment)

Screenshots

RobotouilleSimulator2024-12-1000-23-32-ezgif com-video-to-gif-converter

@lsuyean lsuyean requested a review from chalo2000 November 10, 2024 21:17
@lsuyean lsuyean changed the title Customers [1/2] Customers Nov 16, 2024
Copy link
Contributor

@chalo2000 chalo2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for the immense effort on this! I've left a couple of comments and have requested changes just so I can take another look at your responses and minor changes.

order to them.
"""

customers = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turn these into instance variables so we don't have networking issues

if not self._are_valid_types(pred.types, object_types):
raise ValueError(f"Predicate {pred.name} has invalid types.")

for action in self.actions:
for action in action_def:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

combine for loop into 1 more for loop

for action_def in [action_def, npc_action_def]:
  ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edited accordingly

@@ -0,0 +1,52 @@
from backend.customer import Customer
class GameMode(object):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for future, you can import ABC class to make abstract class. look at this reference

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used ABC for Gamemode and SpecialEffect

player_destinations = [data.path[-1] for name, data in Movement.metadata.items() if data.path and name != player.name]
player_customer_locations = [p.pos for p in Player.players.values() if p != player]
player_customer_locations += [c.pos for c in Customer.customers.values() if c != customer and c.in_game]
# player_customer_destinations = [data.path[-1] for name, data in Movement.metadata.items() if data.path and name != player.name and name != customer.name]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete

player_customer_locations += [c.pos for c in Customer.customers.values() if c != customer and c.in_game]
# player_customer_destinations = [data.path[-1] for name, data in Movement.metadata.items() if data.path and name != player.name and name != customer.name]
player_customer_destinations = []
for name, data in Movement.metadata.items():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unclear, comment more and make it clearer

@@ -500,30 +524,33 @@ def _get_player_sprite(self, direction):
AssertionError: If the direction is invalid
"""
if direction == (0, 1):
return self.config["player"]["robot"]["back"]
return self.config[type]["robot"]["back"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so ['customer']['robot'][...] is a customer asset? customer isn't a robot. regardless we are hardcoding the "robot" asset anyways; either make this clearer that we are hardcoding by removing ["robot"] and renaming assets or put a TODO to fix this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the function to take in a name argument

@@ -486,12 +509,13 @@ def _draw_stations(self, surface):
self._draw_image(surface, asset_info["name"], np.array([j, i - offset]) * self.pix_square_size, self.pix_square_size)


def _get_player_sprite(self, direction):
def _get_player_or_customer_image_name(self, direction, type):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking throughout the codebase and repeatedly seeing player_or_customer is tiring. it would be good for us to rename this to some catch all like character (customer is a non-playable character while player is a playable character).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced with character

@@ -10,6 +10,15 @@
}
},

"customer": {
"robot": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may as well remove the "robot" key for the time being until we have different assets to make this hardcoding more evident.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it to girl so that the choose_character_image_name() function can take in a name

from domain.domain_builder import build_domain
from utils.robotouille_utils import trim_item_ID
from backend.gamemodes.classic import Classic
from .env_utils import build_identity_predicates, build_location_predicates, build_stacking_predicates, build_goal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for organizing this better. we'll eventually want to reintegrate PDDL and since these are used by builder.py it's good to keep them in one place and switch between creating PDDL predicates or our State predicates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noted!

animate (bool): Whether or not to animate the movement of the players.

Returns:
gamemode(GameMode): The gamemmode of the environment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space between gamemode (GameMode) and misspelled gamemode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added space and fixed typo

Copy link
Contributor

@chalo2000 chalo2000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving additional comment after testing the customer environments.

"goal": [
{
"predicate": "iscookable",
"args": ["lettuce"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also just played through these and realized the goal is unrealizable. What is the plan for checking that these environments are done?

Copy link
Contributor Author

@lsuyean lsuyean Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, did this to make it easier to debug. Edited the goals accordingly to close when all customers have finished eating.

@lsuyean lsuyean requested a review from chalo2000 December 10, 2024 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants