关键词 > CSSE1001/CSSE7030

CSSE1001/CSSE7030 Assignment 2 Semester 2, 2022

发布时间:2022-09-26

Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

Assignment 2

Semester 2, 2022

CSSE1001/CSSE7030

1 Introduction

Garden Gnome is a single-player simulator game where a player must take care of house plants for 15 days. The player must keep more than half their plants alive for this duration. Items are be rewarded throughout the days to assist the player, and are applied when needed. See Figure 1 for a sample game.

In Assignment 2, you will create an extensible object-oriented implementation of Garden Gnome which employs a text-based interface.

You are required to implement a collection of classes and methods as specified in Section 5 of this document. Your program’s output must match the expected output exactly; minor differences in output (such as white-space or casing) will cause tests to fail, resulting in zero marks for that test. Any changes to this document will be listed in a changelog at the end of the document.

Figure 1:  A snippet from a functional game of Garden Gnome.  Each room in the house is separated by walls (represented by #) and each room can have four plants eac represented by a single character.

2 Getting Started

Download a2 .zip from Blackboard this archive contains the necessary files to start this assignment.

Once extracted, the a2 .zip archive will provide the following files/directories:

a2.py

The game engine.  This is the only file you submit and modify.  Do not make changes to any other files.

a2_support.py

Provided classes implementing functionality to render the text interface.

constants.py

Constants you may find helpful when writing your assignment.

houses

A folder containing several text files of playable houses.

example_simulations

A folder containing example output from running the completed assignment.

3 Gameplay

The objective is to have more than half the plants alive at day 15. For example, if the game started with ten plants, six plants are required to be alive at day 15 to win the game.

Gameplay occurs according to the following steps:

1. Prompt user with“Enter house  file: ”. Presume the file exists at the location given relative to where a2 .py is saved. For instance, houses/house1 .txt.

2. Display house and prompt user with“Enter  a move: ”. The list of valid moves are given below. Assume invalid moves may be entered, but ignore them.

3. Progress to next day when n is entered.

4. Break on lose or win, otherwise go to step 2.

Figure 2: All available moves.

3.1 Room and position system

The room and position system used for the simulator is depicted in Figure 4.  For example in the “Balcony”  room there are always four possible positions to place plants, 0,  1, 2, and 3, from left to right, each room has 4 columns at different elevations.   Positions are represented as a single  int.   Note that this is just an example; you must not assume that you will always have a Balcony room.

4 Class overview and relationships

• Hollow-arrowheads indicate inheritance (i.e. the“is-a”relationship).

• Dotted arrows indicates composition (i.e. the“has-a”relationship). An arrow marked with denotes that each instance of the class at the base of the

arrow contains exactly one instance of the class at the head of the arrow. An arrow marked with denotes that each instance of the class at the base of the arrow may contain many instances of the class at the head of the arrow. E.g. a Model instance may contain many different Room instances, but only one Inventory instance.

• Green classes are abstract classes.  You should only ever instantiate the blue

Figure 3: Example behaviour when user input is invalid.

Figure 4: Room and position system for a Balcony

classes in your program, though you should instantiate the green classes to test them before beginning work on their subclasses.

• The class surrounded by a pink box is provided to you in a2_support .py.

Figure 5: Basic class relationship diagram for the classes which need to be implemented for this assignment.

Note that all view classes have been provided to you.  You are only required to implement a number of modelling classes and a single controller class which unites these modelling classes with the existing View view class.

5 Implementation

5.1 Model classes

This section outlines the model classes you must implement, along with their required methods.   The classes are laid out in the order in which it is recommended you attempt them (with some exceptions that are discussed in the relevant sections). It is strongly recommended that you ensure a class is working via testing the implementation yourself before moving on to another class (particularly if that class is a superclass of the next class you will attempt).

Entity

(“bstr“ct cl“ss)

Abstract base class for any entity. Provides base functionality for all entities in the game.

get_class_name(self)  ->  str                                            (method)

Return the class name of this entity’s class.

get_id(self)  ->  str                                                           (method)

Return the single character id of this entity’s class.  See constants .py for the ID value of all tiles and entities.

__str__ (self)  ->  str                                                         (method)

Return the string representation for this Entity.

__repr__ (self)  ->  str                                                       (method)

Return the text that would be required to make a new instance of this class that looks identical (where possible) to self.

Note: you are only required to replicate information that can be set via arguments to the __init__ method for the relevant class. For instance, in the Plant subclass of Entity described later in this document, you are not required to provide the syntax for setting the new Plant instance’s water, health, age, and repellent.  Only the name needs to be communicated in the __repr__ output, because this is the only attribute that can be replicated via the Plant .__init__ method.

Plant

(class)

Inherits from Entity

Plant is an Entity that is planted by the user. A plant has water and health points

(HP) which start at 10, age starting at 0, and no repellent. A plant’s drink rate and sun level are determined by the name of the plant See constants .py for the drink rate and sun level of all plants.

__init__ (self, name:  str)  -> None                                 (method)

Setup the plant with a given plant name. See constants .py for the plant names.

get_name(self)  ->  str

Return name of the plant.

get_drink_rate(self)  ->  float

Return water drinking rate of the plant

decrease_water(self,  amount:  float)  -> None

Decrease the plants water by a specified amount.

drink_water(self)  -> None

(method) (method) (method)

(method)

Reduce water levels by plant’s drink rate. If water levels is zero (or less than zero) the plant’s HP reduces by 1.

get_sun_levels(self)  -> tuple[int,  int]                      (method)

Return the acceptable sun level of the plant with the lower and upper range.

get_health(self)  ->  int

Return the plant’s current HP.

add_health(self,  amount:  int)  -> None

Add to the plant’s health levels by a specified amount.

decrease_health(self,  amount:  int  =  1)  -> None

(method) (method)

(method)

Decrease the plants health by a specified amount, decrease by 1 by default.

get_water(self)  ->  float

Return the water levels of the plant.

water_plant(self)  -> None

Add to the plant’s water level by 1.

set_repellent(self,  applied: bool)  -> None

(method) (method)

(method)

Apply or remove repellent from plant.

has_repellent(self)  -> bool

Return True if the plant has repellent, False otherwise.

get_age(self)  ->  int

Return how many days this plant has been planted.

increase_age(self)  -> None

Increase the number of days this plant has been planted by 1.

is_dead(self)  -> bool

(method) (method) (method)

(method)

Return True if the plant’s health is less than or equals to zero, False otherwise.

>>> plant  =  Plant( 'Rebutia')

>>> plant .get_name()

'Rebutia'

>>> plant .get_health()

10

>>> plant .get_water()

10.0

>>> plant .get_drink_rate()

0.1

>>> plant .decrease_water(0 .2)

>>> plant .get_water()

9.8

>>> plant .drink_water()

>>> plant .get_water()

9.700000000000001

>>> plant .water_plant()

>>> plant .get_water()

10.700000000000001

>>> plant .add_health(1)

>>> plant .get_health()

11

>>> plant .add_health(4)

>>> plant .get_health()

15

Item

(“bstr“ct cl“ss)

Inherits from Entity

Abstract subclass of Entity which provides base functionality for all items in the game.

apply(self, plant: Plant)  -> None                    (abstract method)

Applies the items effect, if any, to the given plant. Raise NotImplementedError.

Water

(cl“ss)

Inherits from Item

Adds to plant’s water level by 1 when applied.

Fertiliser

(cl“ss)

Inherits from Item

Adds to plant’s health by 1 when applied.

PossumRepellent

(class)

Inherits from Item

Cancel a possum attach when applied.

Inventory

(class)

An Inventory contains and manages a collection of items and plant.

__init__ (self,  initial_items:  Optional[list[Item]]  =  None, initial_plants:  Optional[list[Plant]]  =  None)

->  None                                                                                             (method)

Sets up initial inventory.  If no initial_items or initial_plants are provided, inventory starts with an empty dictionary for the entities.  Otherwise, the initial dictionary is set up from the  initial_items and initial_plants lists to be a dictionary mapping entity names to a list of entity instances with that name. Note: Plant is a plant object at age 0.

add_entity(self,  entity:  Item  | Plant)  -> None         (method)

Adds the given item or plant to this inventory’s collection of entities.

get_entities(self,  entity_type:  str)

->  dict[str,  list[Item   |  Plant]]                                         (method)

Returns the a dictionary mapping entity (item or plant) names to the instances of the entity with that name in the inventory, respectively. Note: entity_type:  The type can either be ’Plant’or ’Item’.

remove_entity(self,  entity_name:  str)

->  Optional[Item   |  Plant]                                                        (method)

Removes one instance of the entity (item or plant) with the given name from inventory,if one exists. If no entity exists in the inventory with the given name, then this method

returns None.


__str__ (self)  ->  str


(method)


Returns a string containing information about quantities of items available in the inventory.






Pot


(class)


Pot is an Entity that has growing conditions information and an instance of plant.


__init__ (self)  -> None


(method)


Sets up an empty pot.

set_sun_range(self,  sun_range:  tuple[int,  int])

->  None                                                                                             (method)

Sets the sun range experienced by the pot.

get_sun_range(self)  -> tuple[int,  int]                        (method)

Returns the sun range experienced by the pot.

set_evaporation(self,  evaporation:  float)  -> None   (method)

Sets the evaporation rate of the pot.

get_evaporation(self)  ->  float                                       (method)

Returns the evaporation rate of the pot.

put_plant(self, plant: Plant)  -> None                         (method)






Adds an instance of a plant to the pot.

look_at_plant(self)  ->  Optional[Plant]

Returns the plant in the pot and without removing it.

remove_plant(self)  ->  Optional[Plant]

Returns the plant in the pot and removes it from the pot.

progress(self)  -> None



(method) (method)

(method)


Progress the state of the plant and check if the current plant is suitable in the given conditions. Decrease the plant’s water levels based on the evaporation. The health of the plant should decrease by 1:

• If the sun is not in a suitable range

• If the plant’s water levels is below zero.

animal_attack(self)  -> None                                            (method)

Decreases the health of the plant by the animal attack damage dealt if a plant is in the pot and print out: There has been  an  animal  attack! Do nothing if there is no plant in the pot. Attack should fail if plant has animal repellent.  It should not affect the plant’s health and print out: There has been  an  animal  attack!  But luckily  the  {plant_name} has  repellent .






Room


(class)


A Room instance represents the space in which plants can be planted and the instances of plants within the room.

__init__ (self, name:  str)  -> None                                 (method)

Set up an empty room of given room name. Note: Make use of constants.py .

get_plants(self)  ->  dict[int, Plant  | None]              (method)



Return the Plant instances in this room. with the keys being the positions and value being the corresponding plant, None if no plant is in the position.


get_number_of_plants(self)  ->  int

Return the total number of live plants in the room.

add_pots(self, pot_data:  dict[int, Pot])  -> None


(method)

(method)


Add a pots to the room. Each key corresponds to a position in the room, with each value being an instance of a pot.

get_pots(self)  ->  dict[int, Pot]                                   (method)

Return all pots within the room.

get_pot(self, position:  int)  -> Pot                             (method)

Return the Pot instance at the given position.

add_plant(self, position:  int, plant: Plant)  -> None (method)

Add a plant instance to Pot at a given position if no plant exist at that position. Do nothing if a plant is already there. The given position can be 0, 1, 2, or 3.

get_name(self)  ->  str                                                       (method)

Return the name of this room instance.

remove_plant(self, position:  int)  ->  Optional[Plant] (method)

Return a Plant at a given position from a Pot, None if no plant exists. Removes the plant from a pot at the given position.

progress_plant(self, pot: Pot)  -> bool                        (method)

Return True if pot is not empty and triggers a given pot to check on plant condition and plant to age. False if pot is empty.

progress_plants(self)  -> None                                        (method)

Progress each pot with the progress_plant method in ascending order of position. i.e.  pot at position 0, pot at position 1, pot at position 2, then pot at position

3.


__str__ (self)  ->  str

Return the string representation of this room.

__repr__ (self)  ->  str


(method)

(method)



Return a string that could be copied and pasted to construct a new Room instance with the same name as this Room instance.

>>>  room  =  Room( 'Bedroom')

>>>  room .get_plants()

{0:  None,  1:  None,  2:  None,  3:  None}

>>>  room .get_number_of_plants()

0

>>> pot  =  Pot()

>>> pot .put_plant(Plant( 'Rebutia'))

>>> pots  =  {0: pot,  1:  Pot(),  2:  Pot(),  3:  Pot()}

>>>  room .add_pots(pots)

>>>  room .get_plants()

{0:  Plant( 'Rebutia'),  1:  None,  2:  None,  3:  None}

>>>  room .get_number_of_plants()

1

>>>  room .get_pots()

{0:  Pot(),  1:  Pot(),  2:  Pot(),  3:  Pot()}

>>>  room .get_pot(0) .look_at_plant()

Plant( 'Rebutia')

>>>  room .get_pot(1) .look_at_plant()

>>>  room .add_plant(2,  Plant( 'Cereus '))

>>>  room .get_plants()

{0:  Plant( 'Rebutia'),  1:  None,  2:  Plant( 'Cereus '),  3:  None} >>>  room .get_pot(2) .look_at_plant()

Plant( 'Cereus ')

>>>  room .get_number_of_plants()

2

>>>  room .get_name()

'Bedroom'

>>> plant  =  room .remove_plant(0)

>>> plant .get_name()

'Rebutia'

>>> plant  =  room .remove_plant(1)

>>> print(plant)

None

>>>  room .add_plant(2,  Plant( 'Cereus '))






OutDoor


(class)


An OutDoor is a Room but outdoors.

progress_plant(self, pot: Pot)  -> bool                        (method)



Returns True if pot is not empty and triggers a given pot to check on plant condition       and plant to age. False if pot is empty. Checks to see if an animal attack has occured. Note: Make use of the a2_support.dice_roll() function and that a2_support.dice_roll() is only called once within this progress_plant() method and if the pot is empty,       a2_support.dice_roll() should not be called.






Model


(class)


This is the model class that the controller uses to understand and mutate the house

state.  The model keeps track of multiple Room instances and an inventory.  The Model class must provide the interface through which the controller can request information about the house state, and request changes to the house state.

__init__ (self, house_file:  str)  -> None                      (method)

Sets up the model from the given house_file, which is a path to a file containing house information  (e.g.   houses/house1 .txt).   Once you have written the Room class, you can uncomment the provided load_house function and use it to aid in your implemention of the this method.



get_rooms(self)  ->  dict[str, Room]                               (method)

Returns all rooms with room name as keys with a corresponding room instance.


get_all_rooms(self)  ->  list[Room]

Returns a list of all the room instances.

get_inventory(self)  ->  Inventory

Returns the inventory.

get_days_past(self)  ->  int

Returns the number of days since the start.


(method)

(method)


(method)


next(self,  applied_items:  list[tuple[str,  int,  Item]])  -> None (method)

Move to the next day, if there are items in the list of applied items (room name, position,  item to be applied) then apply all affects.   Add fertiliser and possum repellent to the inventory every 3 days.  Progress all plants in all rooms.  Ensure that progress_plants is called on each room in the same sequence rooms are given by the load_house function.

move_plant(self,  from_room_name:  str,  from_position:  int,

to_room_name:  str,  to_position:  int)  ->  None                (method)

Move a plant from a room at a given position to a room with the given position.

plant_plant(self,  plant_name:  str,  room_name:  str,  position: int)

->  None

Plant a plant in a room at a given position.

swap_plant(self,  from_room_name:  str,  from_position:  int,

to_room_name:  str,  to_position:  int)  ->  None                (method)

Swap the two plants from a room at a given position to a room with the given position.


get_number_of_plants_alive(self)  ->  int

Return the number of plants that are alive in all rooms.

has_won(self)  -> bool


(method)

(method)