Homework 3: Exploring the Display
Class
In this Step, we will explore the Display
class, which is responsible for managing the terminal display using the ncurses
library. The Display
class encapsulates all ncurses
functionality to provide a simple interface for displaying characters on the terminal. It handles initialization, cleanup, and drawing operations.
In this case, you don't need to (and in fact must not) modify any code in the Display
class. Instead, you will be using its public interface to implement the display functionality in the Asciimation
class in the next Step, so it's a good idea to understand the functionality it provides.
Your Task
Explore the Display
Class's Public Interface
Read through display.hpp
to determine what functionality the Display
class provides. Pay special attention to the public member functions, as these are the functions you will be using in the next step of the assignment. (Where you use this functionality to implement the Asciimation
class.)
C++ also includes private:
sections in classes that are not part of the public interface. You can ignore these sections for now, as they are used internally by the Display
class and you won't need to use them in your code.
In the private section, there's some strange conditional code that uses
#ifdef DISPLAY_OUTPUT_FILE
. What's that all about?One of the really cool things about object-based programming is that you can change the implementation of a class without changing its public interface. The
Display
class has two different implementations: one that uses thencurses
library to display things on the terminal which you use, and another, totally different, implementation that writes the display output to a file, but both versions provide the same public interface. The second variant is useful because it allows us to run the program in an environment where usingncurses
wouldn't be ideal, such as an automated testing system.Although you absolutely don't need to know about this feature, there's a deeper-dive section below that talks a bit more about what the alternative version can do and how to turn it on, if you're curious.
Run the display-test
Executable
Once you have explored the Display
class's interface, you should run the display-test
executable to see a demo of some of the things the Display
class can do. You can run it by executing the following command in your terminal:
./display-test
The command will complain if your terminal is not large enough. In some terminals, it will automatically resize the terminal window for you, but VS Code's terminal does not support this feature; when display-test
can't resize the terminal to be big enough, it will complain but still work, just some of the content that should be seen won't be visible.
One option to avoid this problem is to run the program in a separate terminal window outside of VS Code, where you can manually resize the window to be large enough. The Mac has a program called
Terminal
, and Windows has a program calledCommand Prompt
orPowerShell
. If you're using Linux, you probably already know how to open a terminal window. Open a terminal andssh
into the course server, then navigate to your homework directory and run./display-test
there.
Explore the display-test.cpp
Code
Having seen the display-test
program in action, you should now read through the display-test.cpp
code to see how it uses the Display
class's public interface to create the what you saw on the screen. This will help you understand how to use the Display
class in your own code.
Helpful Hints
Here are some tips for exploring the
Display
class!
You Don't Need to Look at display.cpp
While you are welcome to look at the implementation of the Display
class in display.cpp
, you do not need to do so for this assignment. The class is already fully implemented, and you should focus on understanding its public interface as defined in display.hpp
.
The code uses some C++ features we haven't covered yet in class, as well as some C++ and Unix features that are outside the scope of this course. For example, it contains special code to handle program crashes so that if your code goes wrong, it won't leave your terminal in a messed-up state. You don't need to understand how this works for this assignment, but if you're curious, you can look up signal handling in C and C++.
A Deeper Dive: The DISPLAY_OUTPUT_FILE
Feature
Reminder: You don't need to do anything with this feature for the assignment. This discussion is just to satisfy your curiosity if you want to know more about how the
Display
class works. Feel free to skip this section if you're not intrigued.You betcha.
The Display
class has a special feature that allows it to write its output to a file instead of displaying it on the terminal. This feature is controlled by the DISPLAY_OUTPUT_FILE
preprocessor directive and the use of #ifdef
and #ifndef
in the code.
When DISPLAY_OUTPUT_FILE
is defined, the Display
class will not use the ncurses
library. Instead it will write an ASCII movie file to the file named in the DISPLAY_OUTPUT_FILE
macro. The file will contain a series of frames, each representing the state of the display at a given time. Each frame is separated by a blank line. The file looks a bit like a film strip, with each frame separated by a line of =
characters and information about the time elapsed since the start of the display.
Although we could edit display.hpp
and add the line
#define DISPLAY_OUTPUT_FILE "the-movie.txtmov"
to switch to building this version of the Display
class, a better way to do so is to pass a special flag to the compiler when building your program, which we can do by giving the compiler an extra argument, -DDISPLAY_OUTPUT_FILE=\"the-movie.txtmov\"
, which tells the compiler to define the DISPLAY_OUTPUT_FILE
macro to be the string "the-movie.txtmov"
.
If you built your Makefile
using variables and have a CPPFLAGS
variable that gets included in CXXFLAGS
, you can just pass this flag to make
like this:
make clean
make 'CPPFLAGS=-DDISPLAY_OUTPUT_FILE=\"the-movie.txtmov\"'
(Running make clean
is necessary whenever you switch between building with and without this flag, because otherwise make
won't realize that it needs to rebuild everything that includes display.hpp
because the file itself hasn't changed.)
As usual, you can run the program with
./display-test
but now, rather than seeing the output on the terminal, it will create a file called the-movie.txtmov
in the current directory. You can look at the file in VS Code or any other text editor. It should be fairly readable.
Because the normal programs usually run until the user quits, the file output version might never end or produce a very large file. To avoid this issue, the file output version of the Display
class has two limits: a maximum runtime (default 5 seconds) and a maximum number of frames (default 500). You can change these limits by setting the environment variables ASCIIMATION_MAX_RUNTIME
and ASCIIMATION_MAX_FRAMES
to different values before running your program. For example, to limit the output to 10 seconds and 1000 frames, you could run:
ASCIIMATION_MAX_RUNTIME=10 ASCIIMATION_MAX_FRAMES=1000 ./display-test
Using the Movie File
There is a Python program called player.py
in the assignment directory that can read and play back these ASCII movie files. You can run it with the following command:
python3 player.py the-movie.txtmov
You can use the --help
option to see what other options it supports.
One thing you may find with the regular ncurses
version of the code is that because you're connected to the server over the network, there may be some jitter in the display. If you copy the movie file and Python player program to your local machine, you can get a smoother playback experience or share your movie with friends.
(When logged in, completion status appears here.)