CS 70

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.

  • Duck speaking

    In the private section, there's some strange conditional code that uses #ifdef DISPLAY_OUTPUT_FILE. What's that all about?

  • LHS Cow speaking

    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 the ncurses 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 using ncurses wouldn't be ideal, such as an automated testing system.

  • Rabbit speaking

    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.

  • Rabbit speaking

    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 called Command Prompt or PowerShell. If you're using Linux, you probably already know how to open a terminal window. Open a terminal and ssh 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

  • LHS Cow speaking

    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.

  • RHS Cow speaking

    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

  • LHS Cow speaking

    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.

  • Goat speaking

    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.

To Complete This Part of the Assignment

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)