{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Grow a Garden!\n", "\n", "- Players will simulate the experience of gardening by planting, growing, and harvesting virtual plants.\n", "- Players will choose which plants to grow, tend to them, and eventually harvest them.\n", "- The game will incorporate various stages of plant growth, from seeds to mature plants, and players will need to care for their plants at each stage.\n", "\n", "**Features:**\n", "- Planting: Choose a plant from your inventory and plant it.\n", "- Tending: Care for your plants to help them grow.\n", "- Harvesting: Once a plant is mature, harvest it to add to your inventory.\n", "- Foraging: Look for new seeds to expand your plant collection." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by importing the `random` library so we can include some unpredictability for elements in the game." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import random" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Plant Class" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating the Plant Class and Attributes\n", "This class represents the base `Plant` in the garden, with attributes to define the plant's `name`, the amount of fruits or vegetables that can be harvested from a mature plant as `harvest_yield`, the growth stages this plant goes through, the current growth stage, and whether or not the plant is currently `harvestable`.\n", "\n", "### Adding Methods to the Plant Class\n", "The Plant class has two methods: `grow` and `harvest`.\n", "- `grow()`: updates the plant's `current_growth_stage` attribute if it is not already on the final growth stage. If the plant is ready for harvest, this method also updates the `harvestable` attribute to `True`.\n", "- `harvest()`: Sets the `harvestable` attribute to `False` and returns the `harvest_yield`. The remainder of harvest-related actions will happen in the `Gardener` class" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class Plant:\n", " def __init__(self, name, harvest_yield):\n", " self.name = name\n", " self.harvest_yield = harvest_yield\n", " self.growth_stages = [\"seed\", \"sprout\", \"mature\", \"flower\", \"fruit\", \"harvest-ready\"]\n", " self.current_growth_stage = self.growth_stages[0] # Initial growth stage is seed\n", " self.harvestable = False\n", "\n", " def grow(self):\n", " current_index = self.growth_stages.index(self.current_growth_stage)\n", " if self.current_growth_stage == self.growth_stages[-1]:\n", " print(f\"{self.name} is already fully grown!\")\n", " elif current_index < len(self.growth_stages) - 1:\n", " self.current_growth_stage = self.growth_stages[current_index + 1]\n", " if self.current_growth_stage == \"harvest-ready\":\n", " self.harvestable = True\n", "\n", " def harvest(self):\n", " if self.harvestable:\n", " self.harvestable = False\n", " return self.harvest_yield\n", " else:\n", " return None" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define Specific Plant Types\n", "Plant subclasses will be the heart of the game, representing as many plants as we want to create subclasses for. Below, we can see that the `Tomato` subclass inherits everything from `Plant`, but `Lettuce` and `Carrot` override the inherited `growth_stages` attribute because these types of plant do not flower or fruit before they are \"harvest-ready.\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "class Tomato(Plant):\n", " def __init__(self):\n", " super().__init__(\"Tomato\", 10)\n", "\n", "class Lettuce(Plant):\n", " def __init__(self):\n", " super().__init__(\"Lettuce\", 5)\n", " self.growth_stages = [\"seed\", \"sprout\", \"mature\", \"harvest-ready\"]\n", "\n", "class Carrot(Plant):\n", " def __init__(self):\n", " super().__init__(\"Carrot\", 8)\n", " self.growth_stages = [\"seed\", \"sprout\", \"mature\", \"harvest-ready\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Selecting Inventory Items\n", "This is a helper function that will go through a dictionary or list, display the keys or list items to the user as a numbered list, and then prompt the user to select an item by number. The function returns the corresponding item.\n", "\n", "### Continuous Prompting for Selecting Items\n", "An important aspect of this helper function is its ability to continuously prompt users until they select valid input. This helps account for input errors and ensures that users provide valid selections." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def select_item(items):\n", " # Determine if items is a dictionary or a list\n", " if type(items) == dict:\n", " item_list = list(items.keys())\n", " elif type(items) == list:\n", " item_list = items\n", " else:\n", " print(\"Invalid items type.\")\n", " return None\n", " # Print out the items\n", " for i in range(len(item_list)):\n", " try:\n", " item_name = item_list[i].name\n", " except:\n", " item_name = item_list[i]\n", " print(f\"{i + 1}. {item_name}\")\n", "\n", " # Get user input\n", " while True:\n", " user_input = input(\"Select an item: \")\n", " try:\n", " user_input = int(user_input)\n", " if 0 < user_input <= len(item_list):\n", " return item_list[user_input - 1]\n", " else:\n", " print(\"Invalid input.\")\n", " except:\n", " print(\"Invalid input.\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining the Gardener Class\n", "The `Gardener` class models the player, who can plant, tend, harvest, and forage plants. The class has three attributes:\n", "- `name` represents the gardener's name\n", "- `planted_plants` is a list of any plants the gardener has currently planted\n", "- `inventory` is a dictionary where the keys are the item names and the values are the quantity of the item.\n", "\n", "We have also created a `plant_dict` before the `__init__` method to connect each plant subclass to a string so that it is easier to instantiate new objects for each type.\n", "\n", "### Extending the Gardener Class Functionality\n", "The `Gardener` class has four methods:\n", "- `plant()`: This method allows the gardener to plant a plant from their inventory. It prompts the user to select a plant from their inventory, then adds the plant to the `planted_plants` list and removes it from the `inventory` dictionary.\n", "- `tend()`: This method allows the gardener to tend to their plants. It prompts the user to select a plant from their planted plants, then calls the `grow()` method on that plant.\n", "- `harvest()`: This method allows the gardener to harvest a plant. It prompts the user to select a plant from their planted plants, then calls the `harvest()` method on that plant. It then adds the harvest yield to the gardener's inventory.\n", "\n", "### Introducing Randomness: Foraging for Seeds\n", "The `forage()` method allows the gardener to forage for seeds. It randomly selects a plant type from the `plant_dict` and adds it to the gardener's inventory." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "class Gardener:\n", " \"\"\"Represents a gardener who can plant and harvest plants.\"\"\"\n", "\n", " plant_dict = {\"tomato\": Tomato, \"lettuce\": Lettuce, \"carrot\": Carrot}\n", "\n", " def __init__(self, name):\n", " self.name = name\n", " self.planted_plants = []\n", " self.inventory = {}\n", "\n", " def plant(self):\n", " selected_plant = select_item(self.inventory)\n", " if selected_plant in self.inventory and self.inventory[selected_plant] > 0:\n", " self.inventory[selected_plant] -= 1\n", " if self.inventory[selected_plant] == 0:\n", " del self.inventory[selected_plant]\n", " new_plant = self.plant_dict[selected_plant]()\n", " self.planted_plants.append(new_plant)\n", " print(f\"{self.name} planted a {selected_plant}!\")\n", " else:\n", " print(f\"{self.name} doesn't have any {selected_plant} to plant!\")\n", "\n", " def tend(self):\n", " for plant in self.planted_plants:\n", " if plant.harvestable:\n", " print(f\"{plant.name} is ready to be harvested!\")\n", " else:\n", " plant.grow()\n", " print(f\"{plant.name} is now a {plant.current_growth_stage}!\")\n", " \n", " def harvest(self):\n", " selected_plant = select_item(self.planted_plants)\n", " if selected_plant.harvestable == True:\n", " if selected_plant.name in self.inventory:\n", " self.inventory[selected_plant.name] += selected_plant.harvest()\n", " else:\n", " self.inventory[selected_plant.name] = selected_plant.harvest()\n", " print(f\"You harvested a {selected_plant.name}!\")\n", " self.planted_plants.remove(selected_plant)\n", " else:\n", " print(f\"You can't harvest a {selected_plant.name}!\")\n", "\n", " def forage_for_seeds(self):\n", " seed = random.choice(all_plant_types)\n", " if seed in self.inventory:\n", " self.inventory[seed] += 1\n", " else:\n", " self.inventory[seed] = 1\n", " print(f\"{self.name} found a {seed} seed!\")\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setting Up the Main Game Loop\n", "The main game loop will be the core of the game, where the player can choose what actions to take. The loop will continue until the player chooses to quit the game." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setting Game-Level Variables\n", "We will need to set up some variabels to keep track of contants in the game. `all_plant_types` is a list of all the plant types we have created. `valid_commands` is a list of all the commands the player can use. There is also a `gardener_name` variable that collects the player's name and a `gardener` variable that will be used to instantiate the `Gardener` class.\n", "\n", "There is also print statements that welcome the player to the game and explain the commands." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "all_plant_types = [\"tomato\", \"lettuce\", \"carrot\"]\n", "valid_commands = [\"plant\", \"tend\", \"harvest\", \"forage\", \"help\", \"quit\"]\n", "\n", "# Print welcome message\n", "print(\"Welcome to the garden! You will act as a virtual gardener.\\nForage for new seeds, plant them, and then watch them grow!\\nStart by entering your name.\")\n", "\n", "# Create gardener\n", "gardener_name = input(\"What is your name? \")\n", "print(f\"Welcome, {gardener_name}! Let's get gardening!\\nType 'help' for a list of commands.\")\n", "gardener = Gardener(gardener_name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The Main Game Loop\n", "The main game loop will continue until the player chooses to quit the game. The loop will prompt the player to enter a command, then call the appropriate method on the `Gardener` class." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Welcome to the garden! You will act as a virtual gardener.\n", "Forage for new seeds, plant them, and then watch them grow!\n", "Start by entering your name.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What is your name? Jane Doe\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Welcome, Jane Doe! Let's get gardening!\n", "Type 'help' for a list of commands.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? help\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "*** Commands ***\n", "plant\n", "tend\n", "harvest\n", "forage\n", "help\n", "quit\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? forage\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Jane Doe found a lettuce seed!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? plant\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1. lettuce\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Select an item: 1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Jane Doe planted a lettuce!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? tend\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Lettuce is now a sprout!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? tend\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Lettuce is now a mature!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? tend\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Lettuce is now a harvest-ready!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? harvest\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "1. Lettuce\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Select an item: 1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "You harvested a Lettuce!\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "What would you like to do? quit\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Goodbye!\n" ] } ], "source": [ "\n", "\n", "# Main game loop\n", "while True:\n", " player_action = input(\"What would you like to do? \")\n", " player_action = player_action.lower()\n", " if player_action in valid_commands:\n", " if player_action == \"plant\":\n", " gardener.plant()\n", " elif player_action == \"tend\":\n", " gardener.tend()\n", " elif player_action == \"harvest\":\n", " gardener.harvest()\n", " elif player_action == \"forage\":\n", " gardener.forage_for_seeds()\n", " elif player_action == \"help\":\n", " print(\"*** Commands ***\")\n", " for command in valid_commands:\n", " print(command)\n", " elif player_action == \"quit\":\n", " print(\"Goodbye!\")\n", " break\n", " else:\n", " print(\"Invalid command.\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.6" } }, "nbformat": 4, "nbformat_minor": 4 }