xuebaunion@vip.163.com
3551 Trousdale Rkwy, University Park, Los Angeles, CA
留学生论文指导和课程辅导
无忧GPA:https://www.essaygpa.com
工作时间:全年无休-早上8点到凌晨3点

微信客服:xiaoxionga100

微信客服:ITCS521
Hacker Assignment 3 Semester 2, 2021 CSSE1001/CSSE7030 Due date:
16:00, 29th of October, 2021 GMT+10 1 Introduction The third assignment
will be a culmination of all your existing knowledge of the course
content. Your task will be to make a game with a Graphical User
Interface (GUI). The game of Hacker is conceptually similar to Space
Invaders, the player is fixed vertically while entities progress verti-
cally towards the player (See Figure 1). This assignment is split into 3
tasks of increasingly difficulty. As tasks increase, their total marks
decrease. Task 3 is for CSSE7030 students only. Student’s are expected
to follow the Apple Model-View-Controller (MVC) design pattern. You are
not allowed to import any modules Figure 1: A preview of an in-progress
game. The Player is represented by a purple square with ‘P’. Other
entities are indicated with ‘B’, ‘C’, and ‘D’ squares. other than the
following: 1 • tkinter (and all tkinter submodules) • random • Pillow •
a3_support Importing any module not listed here will result in a
deduction of up to 100% 2 Terminology Destroyable (D) Red entity that
players must destroy before it reaches the top row where the player is
located. Collectable (C) Blue entity that players must collect. By
default, collecting 7 Collectables will cause the Player to win the
game. Blocker (B) Grey entity that players cannot shoot through. Shot
type There are 2 shot types in the game - destroy and collect. Rules on
what can be destroyed and collected can be seen in the Model Class
descriptions (Section 5.2). 3 Overview and Game Rules The goal of the
game is to collect a specified amount of collectable entities without
having a destroyable entity reach the player’s row. If a red destroyable
entity reaches the player’s row then the game is over. If any other
entity reaches the top row then the game continues as normal. Players
mainly interact with the game by moving non-player entities on the grid.
It is important to note that the player never moves and remains centred
on the grid in the top row. Entities are rotated left and right and
wrap around to the other side of the grid if they are moved off an edge
(See Figure 2). Every 2 seconds, non-player entities step 1 space closer
to the player and a new bottom row containing randomly generated
entities will appear. This is known as a ‘step event’. 4 Getting Started
Download a3.zip from Blackboard — this archive contains the necessary
files to start this as- signment. Some support code has been included to
assist with implementing the program. Once extracted, the a3.zip
archive will provide the following files/directories: a3.py File to run
your program. Write your code in this file. Do not change any provided
functions found in this file. Note: You are required to use the methods
provided in this file. a3 support.py Constants, functions, and classes
you may find helpful for writing the engine. Read the docstrings in
order to understand how to use them in your solution. Do not make
changes to this file. 2 Figure 2: Before and after of rotating the grid
right. Upon rotating right, the blue entity is moved to the other edge
as if these edges were connected. images Folder containing images used
for Task 2 and 3 functionality. Note: Task 3 is the CSSE7030 task. 5
Task 1 - Basic Model and View The following sub-sections outline the
gameplay requirements (Section 5.1), as well as the rec- ommended
structure for your code (5.2, 5.3). Remember to test individual methods
as you write them. Within this section we outline methods that you must
write for the model, and some methods that may be useful to write in the
view classes for Task 1. In the view classes, type hints are omitted,
as it is up to you to determine what these should be. 5.1 Basic Gameplay
User input events should cause behaviour as per Table 1. Event
Behaviour Key Press: ‘A’ or ‘a’ All non-player entities rotate left one
square. Key Press: ‘D’ or ‘d’ All non-player entities rotate right one
square. Key Press: ‘SPACE’ Shoot a destroy shot. Key Press: ‘ENTER’
Shoot a collect shot. Table 1: Task 1 events and their corresponding
behaviours. The entities can rotate independently of the step event.
That is, the entities can rotate multiple times within the space of a
single step event. When the player wins or loses the game they should be
informed of the outcome via a messagebox that pops up on the screen.
Once this messagebox is closed, the game is ended and the application
should terminated. 3 Figure 3: Basic class diagram. 5.2 Model Classes
This section outlines classes and functions you need to implement that
represent the model of the game. The class diagram below depicts these
classes with the basic relationships between them (See Figure 3). •
Solid arrows indicate inheritance (i.e. the “is-a” relationship). •
Dashed arrows indicate composition (i.e. the “has-a” relationship).
5.2.1 Entity Entity is an abstract class that is used to represent any
element that can appear on the game’s grid. • display(self) -> str:
Return the character used to represent this entity in a text-based grid.
An instance of the abstract Entity class should never be placed in the
grid, so this method should only be implemented by subclasses of Entity.
To indicate that this method needs to be implemented by subclasses,
this method should raise a NotImplementedError. • __repr__(self) ->
str}: Return a representation of this entity. This should be inherited
by each subclass but should instead display the class name of that
subclass rather than always Entity’. >>> e n t i t y = Entity (
) >>> repr ( e n t i t y ) ’ Ent ity ( ) ’ 5.2.2 Player A
subclass of Entity representing a Player within the game. •
display(self) -> str: Return the character representing a player: ’P’
5.2.3 Destroyable A subclass of Entity representing a Destroyable
within the game. A destroyable can be destroyed by the player but not
collected. • display(self) -> str: Return the character representing a
destroyable: ’D’ 4 5.2.4 Collectable A subclass of Entity representing a
Collectable within the game. A collectable can be destroyed or
collected by the player. • display(self) -> str: Return the character
representing a collectable: ’C’ 5.2.5 Blocker A subclass of Entity
representing a Blocker within the game. A blocker cannot be destroyed or
collected by the player. • display(self) -> str: Return the
character representing a blocker: ’B’ 5.2.6 Grid The Grid class is used
to represent the 2D grid of entities. The top left position of the grid
is indicated by (0, 0). • __init__(self, size: int) -> None: A grid
is constructed with a size representing the number of rows (equal to the
number of columns) in the grid. Entities should be stored in a
dictionary. Initially a grid does not contain any entities. •
get_size(self) -> int: Return the size of the grid. •
add_entity(self, position: Position, entity: Entity) -> None: Add a
given entity into the grid at a specified position. This entity is only
added if the position is valid. If an entity already exists at the
specified position, this method will replace the current entity at the
specified position. • get_entities(self) -> Dict[Position, Entity]:
Return the dictionary containing grid entities. Updating the returned
dictionary should have no side-effects. • get_entity(self, position:
Position) -> Optional[Entity]: Return a entity from the grid at a
specific position or None if the position does not have a mapped entity.
• remove_entity(self, position: Position) -> None: Remove an entity
from the grid at a specified position. • serialise(self) ->
Dict[Tuple[int, int], str]: Convert dictionary of Position and Entities
into a simplified, serialised dictionary mapping tuples to characters,
and return this serialised mapping. Tuples are represented by the x and y
coordinates of a Positions and Entities are represented by their
‘display()‘ character. • in_bounds(self, position: Position) -> bool:
Return a boolean based on whether the position is valid in terms of the
dimensions of the grid. Return True iff: 5 ? x ≥ 0 and x < grid size
? y ≥ 1 and y < grid size • __repr__(self) -> str: Return a
representation of this Grid. >>> g r id = Grid (5 )
>>> repr ( g r i d ) ’ Grid (5 ) ’ 5.2.7 Game The Game handles
the logic for controlling the actions of the entities within the grid. •
__init__(self, size: int) -> None: A game is constructed with a size
representing the dimensions of the playing grid. A game should be
constructed with at least the following variable: ? Flag representing
whether the game is won or lost • get_grid(self) -> Grid: Return the
instance of the grid held by the game. • get_player_position(self) ->
Position: Return the position of the player in the grid (top row,
centre column). This position should be constant. •
get_num_collected(self) -> int: Return the total of Collectables
acquired. • get_num_destroyed(self) -> int: Return the total of
Destroyables removed with a shot. • get_total_shots(self) -> int:
Return the total of shots taken. • rotate_grid(self, direction: str)
-> None: Rotate the positions of the entities within the grid
depending on the direction they are being rotated. Valid directions are
specified by the constants found in the a3_support file. Entity
positions rotate as seen in Figure 2. – Left rotation moves all entities
by an offset of (-1, 0) – Right rotation moves all entities by an
offset of (1, 0) • _create_entity(self, display: str) -> Entity: Uses
a display character to create an Entity. Raises a NotImplementedError
if the character parsed into as the display is not an existing Entity. •
generate_entities(self) -> None: (provided) Generate random entities
for each step of the game. • step(self) -> None: This method moves
all entities on the board by an offset of (0, -1). Once entities have
been moved, new entities should be added to the grid (using
generate_entities). Entities should not be re-added to the grid if they
have moved out of bounds. 6 • fire(self, shot_type: str) -> None:
Handles the firing/collecting actions of a player towards an entity
within the grid. A shot is fired from the players position and
iteratively moves down the grid. shot_type refers to whether a collect
or destroy shot has been fired (refer to Entity de- scriptions for how
different entities react to being hit by different types). Valid
shot_type constants can be found in the a3_support file. • has_won(self)
-> bool: Return True if the player has won the game. •
has_lost(self) -> bool: Returns True if the game is lost (a
Destroyable has reached the top row). 5.3 View Classes You must
implement view classes for both a) the game grid and b) the game
statistics (left and right sections of Figure 1 respectively). Because
these widgets can both be represented by grids of rectangles, you should
create an abstract class to factor out the shared functionality. Note:
View classes should not be resizable. 5.3.1 AbstractField AbstractField
is an abstract view class which inherits from tk.Canvas and provides
base func- tionality for other view classes. An AbstractField can be
thought of as a grid with a set number of rows and columns, which
supports creation of text at specific positions based on row and column.
The number of rows may differ from the number of columns, and the cells
may be non-square. You must define the constructor for the
AbstractField class as: • __init__(self, master, rows, cols, width,
height, **kwargs): The parameters rows and cols are the number of rows
and columns in the grid, width and height are the width and height of
the height of the grid (and hence the width and height of the tk.Canvas,
measured in pixels) and **kwargs signifies that any additional named
arguments supported by tk.Canvas should also be supported by
AbstractField. The following methods may be useful to include in the
AbstractField class. • get_bbox(self, position): Returns the bounding
box for the position; this is a tuple containing information about the
pixel positions of the edges of the shape, in the form (x_min, y_min,
x_max, y_max). • pixel to position(self, pixel): Converts the (x, y)
pixel position (in graphics units) to a (row, column) position. •
get_position_center(self, position): Gets the graphics coordinates for
the center of the cell at the given (row, column) position. •
annotate_position(self, position, text): Annotates the center of the
cell at the given (row, column) position with the provided text. 5.3.2
GameField GameField is a visual representation of the game grid which
inherits from AbstractField. Entities are drawn on the map using
coloured rectangles at different (row, column) positions. You must
annotate the rectangles of all entities with their display() characters
(as per Figure 1). You 7 must use the create_rectangle and create_text
methods from tk.Canvas to achieve this. The colours representing each
entity are found in a3_support. The FIELD_COLOUR constant indicates the
background colour of the view. You must define the constructor for the
GameField class as: • __init__(self, master, size, width, height,
**kwargs): The size parameter is the number of rows (= number of
columns) in the grid, width and height are the width and height of the
grid (in pixels) and **kwargs signifies that any additional named
arguments supported by tk.Canvas should also be supported by GameField.
It may be useful to add the following methods to the GameField class: •
draw_grid(self, entities): Draws the entities (found in the Grid’s
entity dictionary) in the game grid at their given position using a
coloured rectangle with superimposed text identifying the entity (this
includes the Player entity). • draw_player_area(self): Draws the grey
area a player is placed on. This colour is found in a3_support file as
the PLAYER_AREA constant. 5.3.3 ScoreBar ScoreBar is a visual
representation of shot statistics from the player which inherits from
AbstractField. For Task 1, this bar displays the number of collectables
acquired and the number of destroyables shot as seen in Figure 1. The
ScoreBar’s statistics values must update in real time. You must define
the constructor for the ScoreBar class as: • __init__(self, master,
rows, **kwargs): rows is the number of rows contained in the ScoreBar
canvas. This should match the size of the grid. By default, columns
should be set to 2. Relevant support file constants should be used for
window sizing and **kwargs signifies that any additional named arguments
supported by tk.Canvas should also be supported by ScoreBar. Finally,
the background colour of the ScoreBar can be found in a3_support as
SCORE_COLOUR. 5.3.4 HackerController HackerController acts as the
controller for the Hacker game. The constructor should be defined as: •
__init__(self, master, size): The parameter master represents the master
window and size represents the number of rows (= number of columns) in
the game map. This method should draw the title label (see a3_support
for font, colour and size details), ini- tialise the Game model, and
instantiate and pack the GameField and ScoreBar. Finally, this method
should initiate the game’s ‘step’ The following are suggested methods to
include in this class: • handle_keypress(self, event): This method
should be called when the user presses any key during the game. It must
handle error checking and event calling and execute methods to update
both the model and the view accordingly. • draw(self, game): Clears and
redraws the view based on the current game state. • handle_rotate(self,
direction): Handles rotation of the entities and redrawing the game. It
may be easiest for the handle_keypress method to call handle_rotate with
the relevant arguments. 8 • handle_fire(self, shot_type): Handles the
firing of the specified shot type and redraw- ing of the game. It may be
easiest for the handle_keypress method to call handle_fire with the
relevant arguments. • step(self): The step method is called every 2
seconds. This method triggers the step method for the game and updates
the view accordingly. Note: The .after method for tkinter widgets may be
useful when trying to get this method to run every 2 seconds. 6 Task 2 -
Images, StatusBar and Filemenu Extensions Task 2 requires you to add
additional features to enhance the game’s look and functionality. Fig-
ure 4 gives an example of the game at the end of Task 2. Figure 4: Task 2
GUI Note: Your Task 1 functionality must still be testable. When your
program is run with the TASK constant in a3_support.py set to 1, the
game should display only Task 1 features. When your program is run with
the TASK constant set to 2, the game should display all attempted task 2
features. There should be no Task 2 features visible when running the
game in Task 1 mode. To separate Task 1 and 2, you must create a new
interface class that extends the functionality of the HackerController
class named AdvancedHackerController. 9 6.1 Images Create a new view
class, ImageGameField, that extends your existing GameField class. This
class should behave similarly to GameField, except that images should be
used to display each square rather than rectangles (see the provided
images folder). The game map should be set up as an ImageGameField in
Task 2, but you should still provide a functional GameField class that
allows us to test your Task 1 functionality when TASK=1 6.2 StatusBar
Add a StatusBar class that inherits from tk.Frame. In this frame, you
should include: • A shot counter, displaying how many shots overall the
player has made in the current game. • A game timer displaying the
number of minutes and seconds the user has been playing the current
game. • A ‘Pause/Play’ button, which either pauses or resumes the game.
(Button text will toggle on every press) 6.3 File Menu Add a file menu
with the options described in Table 2. Note that on Windows this will
appear at the top of the game window, whereas on Mac this will appear at
the top of your screen. For saving and loading files, you must design
an appropriate text (.txt) file format to store information about game
state. Reasonable actions by the user (e.g. trying to load a non-game
file) should be handled appropriately (e.g. with a pop-up to inform the
user that something went wrong). Any error output messages caused by
reasonable behaviour in the GUI will be marked down. Option Behaviour
New game Start a new Hacker game Save game Prompt the user for the
location to save their file (using an appropriate method of your
choosing) and save all necessary information to replicate the current
state of the game. Load game Prompt the user for the location of the
file to load a game from and load the game described in that file. Quit
Prompt the player via a messagebox to ask whether they are sure they
would like to quit. If no, do nothing. If yes, quit the game (window
should close and program should terminate). Table 2: File menu options. 7
Task 3 - CSSE7030 (Masters) Task 7.1 Model This section outlines the
class and functions you need to extend to the original model outline in
Task 1. 10 7.1.1 Bomb A subclass of Entity representing a Bomb within
the game that player’s can destroy other entities with. A bomb removes
all entities within a ‘splash damage’ radius. The SPLASH constant refers
to the specific offsets. A bomb can be destroyed but cannot be
collected. • display(self) -> str: Return the character representing a
bomb: ’B’ 7.1.2 Game The relevant function in Game will need to be
extended to accommodate for the Bombs splash damage functionality. This
method will need to check for TASK=3 in order to work and the commented
section in generate_entities() will need to be uncommented. The Game
class will also be extended to allow players to have one extra life.
This means players will start with an extra life. 7.2 View The updates
to the model seen in the previous section will be visualised as seen in
Figure 5. Defining another subclass would be beneficial for the
implementation of the extended features. Note: These features should
only be displayed when TASK=3. Figure 5: Complete Masters game 11 8
Assessment and Marking Criteria 8.1 Marking Breakdown Your total grade
for this assessment piece will be a combination of your functionality
and style marks. You are not required to attend an interview for this
assignment. 8.2 Functionality Marking Your program’s functionality will
be marked out of a total of 50 marks. As in assignment 0, your
assignment will be put through a series of tests and your functionality
mark will be proportional to the number of tests you pass. You will be
given a subset of the functionality tests before the due date for the
assignment. Your assignment will be tested on the functionality of
gameplay features. The automated tests will play the game and attempt to
identify components of the game, how these components operate will then
be tested. Well before submission, run the functionality tests to
ensure com- ponents of your application can be identified If the
autograder is unable to identify components, you will be marked
accordingly, even if your assignment is functional. The tests provided
prior to submission will help you ensure that all components can be
identified by the autograder. You need to perform your own testing of
your program to make sure that it meets all spec- ifications given in
the assignment. Only relying on the provided tests is likely to result
in your program failing in some cases and you losing some functionality
marks. Your program must run in the Python interpreter (the IDLE
environment). Partial solutions will be marked, but if there are errors
in your code that cause the interpreter to fail to execute your program,
you will get zero for functionality marks. If there is a part of your
code that causes the interpreter to fail, comment out the code so that
the remainder can run. Your program must run using the Python 3.9
interpreter. If it runs in another environment (e.g. Python 3.8 or
PyCharm) but not in the Python 3.9 interpreter, you will get zero for
the functionality mark. 8.3 Style Marking The style of your assignment
will be assessed by a tutor. Style will be marked according to the style
rubric provided with the assignment. The style mark will also be out of
50. 8.4 Assignment Submission This assignment follows the assignment
submission policy as assignment 0. Please refer to the assignment 0 task
sheet. You must submit your assignment as a single Python file called
a3.py (use this name – all lower case), and nothing else. Your
submission will be automatically run to determine the func- tionality
mark. If you submit a file with a different name, the tests will fail
and you will get zero for functionality. Do not submit the a3 support.py
file, or any other files. Do not submit any sort of archive file (e.g.
zip, rar, 7z, etc.). 12 8.5 Plagiarism This assignment follows the same
plagiarism policy is as per assignment 0. Please refer to the assignment
0 task sheet. 13