Programming Assignment 2 - ASCII Animation

Advanced Programming II, Fall 2002


Due Date

This assignment is due by 2:00 p.m. on Thursday, 3 October.

See the assignment turn-in page (last modified on 4 March 2002) for instructions on turning in your assignment.

Background

Back in the days before high-resolution, full-color bit-mapped displays, we used to entertain ourselves by creating ASCII animations ("ASCII" stands for "American Standard Code for Information Interchange"). An ASCII animation is a text file containing regular characters and ANSI escape sequences ("ANSI" stands for "American National Standards Institute"). An ANSI escape sequence is a short string that directs the terminal to move the cursor to various locations on the screen and perform various actions.

By artfully intermixing regular text and ANSI escape sequences, it's possible to make it look as if the characters were moving around the terminal screen. For example, by repeatedly performing the following

  1. Display an asterisk *.

  2. Move the cursor left by one character so it's back over the asterisk.

  3. Display a space.

  4. Move the cursor left by two characters.

the asterisk can be made to look as if it is moving from right to left on the terminal screen. The contents of an ASCII-animation file, when displayed on a terminal, results in a simple animation made up of moving characters.

The following is a list of some ANSI escape sequences that may be useful when implementing this assignment:

<ESC>[r;cHMove the cursor to row r column c.
<ESC>[rAMove the cursor up r rows.
<ESC>[rBMove the cursor down r rows.
<ESC>[cCMove the cursor right c columns.
<ESC>[cDMove the cursor left c columns.
<ESC>[sSave the cursor position.
<ESC>[uMove the cursor to the previously saved position.
<ESC>[2JClear the screen and move the cursor to row 1 column 1.
<ESC>[KErase everything from the cursor to the end of the row containing the cursor.
<ESC>[fmSet the output mode to the display format f.

<ESC> represents the ASCII escape character, decimal value 27. The topmost terminal-screen row is row 1; increasing row numbers move down along the terminal screen. The leftmost terminal-screen column is column 1; increasing column numbers move right along the terminal screen. You may assume a terminal screen has 30 rows and 80 columns.

The display formats recognized for f are

attributes foreground color background color
0normal
30black
40black
1bold
31red
41red
4underline
32green
42green
5blink
33yellow
43yellow
7reverse video
34blue
44blue
8invisible
35magenta
45magenta
36cyan
46cyan
37white
47white

To continue the example given above, the following string implements the four-step sequence that moves an asterisk left by one column:

,
"*" "<ESC>[1D" " " "<ESC>[2D"
1 2 3 4

The number under each string corresponds to the step given above; in an ASCII animation file the sequence would appear as a single string made up of the four pieces catenated together in the order shown:

"*<ESC>[1D <ESC>[2D"

The Problem

Write a program that reads an animation script from std-in and writes to std-out a file that, when displayed on a terminal, produces the animation described by the input script.

Input

The input consists of a sequence of zero or more animation instructions. Each input line read from std-in does not contain more than one animation instruction and a single animation instruction cannot be split into several input lines; that is, Each line of input read contains at most one animation instruction, and each animation instruction occupies exactly one input line. Empty input lines or input lines containing only white-space characters should be ignored.

An animation instruction is either a box instruction or a move instruction. A box instruction defines a box that may appear in an animation. Every box that appears in an animation must have been defined by a box instruction. A box instruction has the form

box box-name hight width [ level ] [ color ]

where

Note that while either height or width can be zero, one of them must be non-zero for each box (that is, for any box it must be the case that height + width > 0).

A move instruction moves a previously defined box from one location to another along a straight line. A box instruction has the form

move box-name start-r start-c end-r end-c time

where

There are two move-instruction idioms of which you should be aware:

  1. move box-name start-r start-c end-r end-c 0

    This instruction moves the named box from (start-r, start-c) to (end-r, end-c) in zero time; that is, the named box suddenly appears at (end-r, end-c).

  2. move box-name r c r c time

    This instruction moves the named box from (r, c) to (r, c) in time milliseconds; that is, the named box appears at (r, c) and remains there for at least time milliseconds.

Output

The output should be a sequence of characters that, when displayed on a terminal, produces the animation described by the input script.

If an animation script contains several move instructions for the same box, the moves should be applied in the order given, one after the other. For example, assuming the box 1 is defined, the sequence

move 1 10 10 10  1 100
move 1 10  1 10  1  50
move 1 10  1 10 10 100 

would result in box 1 moving left, pausing for 50 msec., and then moving right.

The first time a box is moved, it should just appear at its starting location. Once a box has reached its ending location, it should remain there until moved again.

If a box isn't at the starting location given by a move statement, it should instantaniously jump to its starting location. For example, assuming box 1 is defined, the sequence

move 1 10 10 10  1 100
move 1 10 10 10  1 100

moves box 1 left, instaniously jumps it to its previous starting location, and moves it again.

You may use whatever characters you want to to draw the rectangles, but make sure it's clear what's a rectangle and what isn't.

It is not necessary that a rectangle remain in the frame defined by 30-by-80 terminal screen; however, only those parts of the rectangle appearing in the frame should be displayed; parts of a rectangle falling outside of the frame should not be displayed.

If two rectangles overlap during the animation, they should be output in the order determined by their level: higher level rectangles should appear above, and obscure, lower level rectangles. For example, suppose the vertical rectangle has level 1 and the horizontal rectangle has level 0 (the lowest possible level). If they overlap during an animation, then they should appear as, for example,

   +--+
   |  |
+--|  |----+
|  |  |    |
+--|  |----+
   |  |
   +--+

If, on the other hand, the vertical rectangle has level 0 and the horizontal rectangle has level 1, then they would appear as, for example,

   +--+
   |  |
+----------+
|          |
+----------+
   |  |
   +--+

The overlapping rectangles have the same level, then they should be merged. For example with both rectangles at the same level, they would appear as

   +--+
   |  |
+---  -----+
|          |
+---  -----+
   |  |
   +--+

The output of your program does not need to preserve correct animation timings; you may rely on delayed output to produce the required motion timings (this means if you save the output of your program to a file and then display the file everything will streak past at the same, probably too fast, rate).

Implementation Tips

Terminal characters are not square; they're taller than they are wide. If you draw a square with characters, it be output as a rectangle taller than it is wide. Don't worry about it, as long as the height and width are as specified in the associated box instruction.

You might want to investigate the usleep() system call for motion timings. See the usleep() man page for details.

Your code may not use any of the cursor manipulation packages such as termcap, curses, ncurses, and so on.

Some terminals don't reproduce color. If that's the case, don't worry about color, but still handle it correctly.

Testing

I'll make my implementation of the problem and a test driver available as soon as I get them working. I don't recommend sitting around waiting for me to make these available; I recommend getting right to work.


This page last modified on 25 September 2002.