ECS 34 编程指南

【ECS 34 编程指南】ECS 34: Programming Assignment #6
Contents
1 Changelog 1
2 General Submission Details 1
3 Grading Breakdown 2
4 Submitting on Gradescope 2
4.1 Regarding Autograder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.1.1 Memory Leaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5 Prerequisite Concepts 3
5.1 The Curses Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5.2 More on C++ Classes: Inheritance, Polymorphism, etc. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3 Model View Controller (MVC) Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
6 Your Task: Game 4
1 Changelog
You should always refer to the latest version of this document.
? v.1: Initial version.
? v.2:
– Stated that you can find the main.cpp used in the examples on Canvas.
– In red and when talking about the format of the game input file, explicitly stated that the dimensions of the
screen/viewport do not count the border of the screen (i.e. the asterisks).
? v.3:
– Clarified (in red) that collecting the last item on last move is victory.
– As I suggested I would, I pushed the deadline back. It is now Saturday night instead of Wednesday night.
2 General Submission Details
Partnering on this assignment is prohibited. If you have not already, you should read the section on
academic misconduct in the syllabus.
This assignment is due the night of Saturday, December 12. Gradescope will say 12:30 AM on Sunday, December 13, due
to the “grace period” (as described in the syllabus). Be careful about relying on the grace period for extra time; this could be
risky.
You should use the -Wall, -Werror, and -std=c++11 flags when compiling. The autograder will use these flags when it
compiles your code.
?This content is protected and may not be shared, uploaded, or distributed.
1
3 Grading Breakdown
TBA
4 Submitting on Gradescope
You have infinite submissions until the deadline.
During the 10/02 lecture, I talked about how to change the active submission, just in case that is something that you
find yourself wanting to do.
You are given the following C++ files:
? building.cpp
? building.hpp
? controller.hpp
? curses_controller.cpp
? curses_controller.hpp
? curses_view.cpp
? curses_view.hpp
? game.cpp
? game.hpp
? interface_type.hpp
? item.cpp
? item.hpp
? map_segment.cpp
? map_segment.hpp
? print_controller.cpp
? print_controller.hpp
? print_view.cpp
? print_view.hpp
? view.cpp
? view.hpp
You must submit all header and source files needed by your game to Gradescope, including (and limited
to, unless you add files) all of the files above. Do not submit a file that contains an implementation of main(). The
autograder will compile all of the files that you provide together with its own file that has an implementation of main(). You
can add your own header/source files if you want.
To make submitting so many files to Gradescope easier, I have provided a shell script called zip_submission.sh on Canvas
that you can run to create a ZIP file called submission.zip that contains all of the files that you are supposed to submit. When
you submit a ZIP file, Gradescope automatically extracts the contents of the archive. Below is an example of how you would
run the script. If you do not give the shell script execute permissions, then you will have to do /bin/bash zip_submission.sh to
run it instead.
1 $ cat zip_submission . sh
2 #!/ bin / bash
3
4 zip submission . zip \
5 building . cpp \
6 building . hpp \
7 controller . hpp \
8 curses_controller . cpp \
9 curses_controller . hpp \
10 curses_view . cpp \
11 curses_view . hpp \
12 game . cpp \
13 game . hpp \
14 interface_type . hpp \
15 item . cpp \
16 item . hpp \
17 map_segment . cpp \
18 map_segment . hpp \
19 print_controller . cpp \
20 print_controller . hpp \
21 print_view . cpp \
22 print_view . hpp \
2
23 view . cpp \
24 view . hpp
25 $ ./ zip_submission . sh
26 adding : building . cpp ( deflated ...) # Omitted deflation percentages ; they ’ re different for everyone .
27 adding : building . hpp ( deflated ...)
28 adding : controller . hpp ( deflated ...)
29 adding : curses_controller . cpp ( deflated ...)
30 adding : curses_controller . hpp ( deflated ...)
31 adding : curses_view . cpp ( deflated ...)
32 adding : curses_view . hpp ( deflated ...)
33 adding : game . cpp ( deflated ...)
34 adding : game . hpp ( deflated ...)
35 adding : interface_type . hpp ( deflated ...)
36 adding : item . cpp ( deflated ...)
37 adding : item . hpp ( deflated ...)
38 adding : map_segment . cpp ( deflated ...)
39 adding : map_segment . hpp ( deflated ...)
40 adding : print_controller . cpp ( deflated ...)
41 adding : print_controller . hpp ( deflated ...)
42 adding : print_view . cpp ( deflated ...)
43 adding : print_view . hpp ( deflated ...)
44 adding : view . cpp ( deflated ...)
45 adding : view . hpp ( deflated ...)
46 $ ls submission . zip
47 submission . zip
48 $
4.1 Regarding Autograder
Your output must match mine exactly.
The autograder will only check print mode. I will check curses mode after the deadline.
There is a description about how to interpret some of the autograder error messages in the directions for the first two
programming assignments. I will not repeat that description here.
4.1.1 Memory Leaks
Probably at least one autograder test case will check for memory leaks.
5 Prerequisite Concepts
5.1 The Curses Library
You should read about and understand the curses library. There are probably many good resources on this library. I
personally recommend the tutorial (here) written by Professor Matloff, a professor in the Computer Science department here.
The curses library is a C library. However, C++ easily supports it. You will need to include ; there is no
. When passing a std::string object to a function that takes a char * variable as argument, you may find the c_str()
(or data()) method useful.
The CSIF has the curses library installed. If you do not have the curses library installed on your end and do not wish to
use the CSIF, you will have to look up how to install it on your own. On my Ubuntu machine, this wasn’t that hard. I did
also briefly try the curses library on my Windows machine (using the Windows Subsystem for Linux as the terminal), and
that seemed to work fine. I still don’t own a Mac and thus don’t know about Macs. You might also find the man docs for the
curses library useful, but those are a separate installation.
You must use the -lcurses flag when compiling an application that uses the curses library with g++. The flag must be at
the end of the command. If you are using a makefile or something that causes you to use multiple g++ commands instead of
a single one, then I think you only need to have the -lcurses flag in the command that compiles the executable.
Below is a list of curses functions that I used in my own code. You may find others useful.
? The “boilerplate” function calls: cbreak(), noecho(), endwin(), clear(), refresh()
? To get the cursor out of the way: curs_set(0)
? To get input: getch()
? Drawing strings: mvaddstr()
If you are running a curses application that does not properly clean up (whether due to the application crashing or due
to you not calling the appropriate functions to clean up), then you may notice your terminal will act strange, e.g. the cursor
3
won’t be visible. There are ways to fix this with usually not more than a command or two, but it varies from terminal to
terminal. You can use the reset command too.
I don’t think you’ll need to use a debugger while coding the curses portions. But just in case, here’s some potentially
helpful information. Section 6.2.1 of The Art of Debugging with GDB, DDD, and Eclipse by Norm Matloff and Peter Jay
Salzman talks about how to debug curses programs with a debugger. You should be able to access this book electronically
through the Shields library portal here.
5.2 More on C++ Classes: Inheritance, Polymorphism, etc.
You should read about and understand the topics in chapter 5 (“Runtime Polymorphism”) of C++ Crash Course: A
Fast-Paced Introduction by Josh Lospinoso, the required textbook in this course.
Note on whether inheritance is a good feature: There is some debate in the computer science community regarding
whether inheritance (called “implementation inheritance” by your book) is a good feature for programming languages to
have. When I was just learning to program around 2012, it seemed to be accepted that multiple inheritance (the ability for a
class to inherit from more than one superclass / base class) was bad but inheritance in general was OK. In fact, Java does not
support multiple inheritance for this reason. Nowadays, it feels more as if even inheritance (not just multiple inheritance) is
considered bad, as modern programming languages such as Go and Rust (two alternatives to C and C++ in many situations)
don’t even allow inheritance. The net benefits of object-oriented programming and significant use of classes are also debated.
As is the case with these subjects and many others – e.g. exceptions, global variables, goto statements, unit testing – much is
subjective when it comes to good programming practices. I say all this because in this assignment, you will be working with
many classes and some use of inheritance. In some cases, you may feel that this leads to a nice organization of the code and
other benefits. In other cases, you may feel that the organization and subsequent constraints impede development or that
certain classes (e.g. Building) may have caused more annoyance than benefit. You should form your own opinions on all of
this.
Other notes regarding C++:
? You should be comfortable looking up library functions. Personally, I had to look up many constructors and/or methods
supported by std::vector and std::string, and I suggest that you at least glance at these and see what functions have
already been written for you so that you don’t end up reinventing the wheel.
? protected keyword: You should also look up the protected keyword. I don’t think the book talks about it. It is used in
the provided view.hpp.
? header: If you happened to look at chapter 17 (which you don’t have to read), you may be familiar with
the header. There is one part of this assignment where I felt that that header would have been useful.
Unfortunately, it doesn’t seem to be the case that g++ supports it right now because its part of C++171 and not C++11.
5.3 Model View Controller (MVC) Pattern
To some extent, I set up the classes to follow the MVC pattern, which you can read more about online, e.g. on Wikipedia
here.
? Model: class Game and probably any other class that does not fall under View or Controller.
? View: class View and its subclasses.
? Controller: class Controller and its subclasses.
6 Your Task: Game
I will demonstrate the game during the 11/30 lecture. I will take questions about the assignment during the 11/30 and
12/02 lectures.
The first thing you should do (besides becoming comfortable with the prerequisite concepts mentioned above) is look
through the C++ files provided on Canvas. I include helpful comments in some parts.
You can change any of the files that you must submit to Gradescope. The only things that you absolutely cannot change
are the prototypes/signatures of the constructor of class Game and its run() method, since the autograder will call those.
Below is a brief description of what each class is supposed to do.
? class Game:
– Loads game data and level data.
1This might sound strange, considering that C++17 corresponds to 2017, which was three years ago, but there is usually a significant delay
between the release of a C++ standard and the widespread adoption of the standard by major C++ compilers, as compiler developers have to
make many adjustments.
4
– Sets up controller object and view object and uses them when appropriate.
– Handles reaction of player’s icon/character to input, including movement, rotation, and collision detection (with
buildings and portals).
– In what might violate the MVC pattern, this class should create the std::vector of std::string objects that is sent
to the draw() method of the relevant View subclass instance. That also means this class is responsible for making
sure that only what can be seen in the “screen” gets drawn. For example, if the “screen” is 20-by-30 (as dictated
by the game input file’s first line), then all that the user should be able to see are the 20 rows (i.e. 9 rows up and
10 rows down) and 30 columns (i.e. 14 rows to the left and 15 rows to the right) that surround their player icon.
This usually means the map segment is only partially shown and means that sometimes, only part of a building
is shown. Note that the current level and number of remaining moves are displayed too.
– Keeps track of whether the user has collected all items in the current level or not. Determines when to move on
to the next level. If the player collects the last item on their last move, then that counts as completing that level.
– Determines if the game is over (and reacts appropriately) based on any of the following conditions:
? User quits.
? User runs out of moves (“dies”).
? User wins, i.e. completes all levels.
? class MapSegment / class Item / class Building: Management of model data and, perhaps, how to draw themselves.
? class CursesController: Handles input for the curses mode. “q” to quit. For movement, supports the WASD keys. (The
S key does nothing. A rotates the player left; D, right. The W key advances the player forward.) Also supports arrow
keys for movement. When an arrow key is pressed, an “escape sequence” is generated; this escape sequence starts with
ESC (ASCII value: 27), followed by a [ character and concluded by “A”, “C”, or “D” (depending on whether the Up
arrow key, the Right arrow key, or the Left arrow key was entered).
? class CursesView: Handles drawing for the curses mode. Sets up and cleans up curses.
? class PrintController: Handles input for the print mode. Only supports the WASD keys and “q” to quit.
? class PrintView: Handles drawing (i.e. printing to standard output) for the print mode.
Below, I describe the format of the input text files. You do not have to validate their contents and can assume
they are formatted properly.
Format of game input file: The file whose name is passed to the class Game constructor contains:
? Height and width of the “screen” (through which we will see what’s going on).
– Note that these dimensions do not count the border of the screen (i.e. the asterisks).
? Number of levels.
? After the first two lines, each line contains the relative path to a file corresponding to a level. The third line should
contain the name of the file corresponding to the first level. The fourth line contains one for the second level. The fifth
line contains one for the third level. And so on.
Format of file for each level:
? Index of map segment in which the player starts.
? Position (height and width) at which the player starts in the map segment.
? Direction the player starts facing.
? One line per map segment, where each line starts with an “M” and then has the height and width of the segment. Each
map segment has an implicit unique nonnegative ID, i.e. the first map segment has ID 0, the second has ID 1, etc. You
may assume that there is at least one map segment.
? One line per building, where each line starts with a “B”, contains the ID of the segment that the buliding is in, and
then has the y-coordinate and x-coordinate of the top-left of the building. There could be zero buildings.
? One line per item, where each line starts with an “I” and then follows basically the same format as the building lines.
You may assume that there is at least one item.
? One line per portal, where each line starts with a “P”. This is then followed by the segment index and wall of the source
portal and then those two aspects of the destination portal. (Portals are bidirectional; it doesn’t matter which you call
the “source” vs. the “destination”.) For example, “P 0 down 3 up” means that the map segment with ID #0 has a
portal on its bottom wall that is connected to a portal on the top wall of the map segment with ID #3. The portals
don’t have to make directional sense, e.g. there could be a portal from the right of a segment to the top of another
one. There could be zero portals, in which case there should be one map segment, but you need not validate that.
? One line beginning with an “N” followed by the maximum number of movements that the user can do during this level.
5
Whenever I had member variables in the provided class definitions, I followed a convention2 by which I preceded each
member variable’s name with an “m”. If you don’t like this, feel free to change the names of the member variables, but I
think it’s a cute convention.
For compilation, you could use the below command to compile all of the files together. The -g flag is only necessary if
you are using a debugger. If you choose to use a makefile, be aware that the dependencies may be trickier due to the increased
number of files and the web of ways in which they may depend on each other. main.cpp is a file that has an implementation
of main(); you will not submit such a file to the autograder.
1 g ++ - Wall - Werror -g - std =c ++11 main . cpp item . cpp map_segment . cpp curses_controller . cpp print_controller .
cpp curses_view . cpp print_view . cpp game . cpp view . cpp building . cpp -o main - lcurses
Manual review: There will be a brief manual review (done by me) to check certain things, such as:
? Anything involving the curses library, since the autograder can’t do that. I will personally run each student’s program
with the curses setting for the class Game. The autograder will use the print (non-curses) setting.
? That you respected the separation of the classes and files.
– An example of not doing this would be if you had a method in class Game that did everything that the getInput()
methods of PrintController and CursesController were supposed to do.
– Note that I’m not looking for perfection here, because too much is subjective. There are grey areas regarding
what code should go in which class, even in my own solution. For example, you could add a method to class Item
to check for collision between an item and the player. I didn’t do this in my own code and don’t recommend it;
feel free to disagree, as it’s a grey area. As long as you don’t go out of your way to disregard what each class is
supposed to be responsible for, you should be fine here.
– Do not copy/paste the definitions of all of the classes into a single file. You could be severely penalized for this.
? That you do not have any public member variables. That is, all of your member variables should be private or
protected. This is to force you to use getter/mutator and setter/accessor methods.
Below are examples of how your code should behave. In some portions, I include an annotation that stretches far to the
right; that annotation should not be part of your output. Below, I use the print mode. As stated above, the autograder will
not evaluate curses mode; I will do that manually, after the deadline.
1 $ cat main . cpp # You can find this file on Canvas .
2 # include " game . hpp "
3 # include " interface_type . hpp "
4
5 int main ( int argc , char * argv [])
6 {
7 InterfaceType it = InterfaceType :: Print ;
8 if ( argc >= 2) it = InterfaceType :: Curses ;
9 Game g {" game_files / demo_game1 . txt " , it };
10 g. run () ;
11 }
12 $ cat game_files / demo_game1 . txt
13 20 25
14 2
15 demo_level1 . txt
16 demo_level2 . txt
17 $ cat game_files / demo_level1 . txt
18 0
19 6 2
20 down
21 M 12 15
22 B 0 4 4
23 I 0 8 1
24 N 20
25 $ cat game_files / demo_level2 . txt
26 3
27 10 15
28 left
29 M 20 20
30 M 20 20
31 M 15 15
32 M 20 20
33 B 0 1 1
34 B 0 10 10
35 B 3 12 4
2
I don’t want to say it’s common, but it is used.
6
36 I 1 9 3
37 I 3 10 14
38 I 3 10 17
39 P 0 right 1 right
40 P 1 left 3 right
41 P 2 down 3 up
42 N 15
43 $ g ++ - Wall - Werror -g - std = c ++11 main . cpp item . cpp map_segment . cpp curses_controller . cpp print_controller
. cpp curses_view . cpp print_view . cpp game . cpp view . cpp building . cpp -o main - lcurses
44 $ ./ main
45 Level : 1
46 Items remaining : 1
47 Moves remaining : 20
27 Enter input : q
28 You quit the game .
29 $
In this last attempt, we waste all 20 of our permitted movements wandering around level #1.

    推荐阅读