CS140 -- Lab 3


This lab is designed to give you practice using pointers, malloc, strings, C I/O, and the fields library

Part 1: PGM negatives

A PGM file is a kind of digital picture. You can view pgm files with the display program on the cetus or hydra machines. Simply type
display name.pgm
where name.pgm is the name of your pgm file. You can find the following pgm files in /home/bvz/cs140/labs/lab3: Pgm files are nice because you can actually view them both as pictures with display, and as text -- go ahead and look at one of them with more, vi or whatever editor you use.

A picture is simply a two-dimensional array of pixels. In pgm files, a pixel is a grey value between 0 and 255. Zero is black, and 255 is white. Everything in between is grey.

Pgm files have a specific format. (Actually, I've tweaked them a little to make this easier for you). It is composed of words. The first word is ``P2''. Then the next two words define the number of pixels in the picture -- first is the number of columns in the two-dimensional array, and then the number of rows. The next word is the number 255. So, if you look at the beginning of jsp.pgm, you'll see:

UNIX> head jsp.pgm
P2
252 267
255
 37  44  37  37  44  37  44  44  44  37  44  44  48  48  48  44  37 
 34  33  34  37  33  34  37  48  44  44  44  48  44  44  44  44  53 
 44  44  37  44  53  53  49  44  41  37  41  41  33  33  29  26  26 
 29  29  33  37  37  44  48  53  53  57  53  57  61  64  69  69  81 
 81  77  81  81  73  77  72  48  37  33  33  33  37  37  48  44  33 
 22  22  25  22  22  14  14  14  14  22  22  22  22  22  22  22  22 
 22  22  26  22  22  22  22  18  22  18  22  18  18  18  22  26  22 
This means that jsp.pgm is a 267 * 252 array of pixels. After the 255 come all the pixels. First, the top row, then the next row, etc. Note that the ASCII formatting of the file doesn't mean anything -- there could be one pixel per line and the file would still be a legal pgm file. In jsp.pgm above, the first 252 pixels are those in the top row, then the next 252 are in the second row, and so on. There will be a total of 267*252 = 67284 pixels. After the last pixel, the file ends.

Before you go any further, create a PGM file of your own -- make it 10x10 and give the pixels any value you want. Take a look at it with display. Cool, no?

Now, your first pgm program should take two command line arguments: 1) an input pgm file, and 2) the name of the pgm file that you will create. It should read from the input pgm file and create an output pgm file that is the negative of the input file. Call this program neg.

Note, you don't need to call malloc() with this program. Just read in the first four words, print them out, then print out 255 minus each pixel. You can put a newline after each pixel if you want to make it really easy (this is what I did). Check out the output, and see how it looks:

UNIX> neg jsp.pgm jspneg.pgm
UNIX> display jspneg.pgm

Part 2: Hflip

Hflip reads a pgm file given as the first command line argument, and prints a pgm file to the second command line argument. The output file should be the horizontal reflection of the input file -- in other words, left is right and right is left. Check out the output, and see how it looks:

UNIX> hflip jsp.pgm jspneg.pgm
UNIX> display jspneg.pgm

You'll have to use malloc() for this one. Read in the first four words, and then malloc() a row's worth of pixels. Then, for each row, read in the row and write it out backwards. Test it out!

Part 3: Creating a Diagram of a Maze

Many pictorial files, such as jpegs or gif files, are stored in a compressed format that eliminates redundant information. This compression reduces the size of the files, which you may have noticed can be quite large, even when compressed. In this program you are going to take a compressed file of a maze and re-create the diagram for that maze. The maze will have walls that are drawn with a '#', corridors that are drawn with spaces, and players, monsters, and treasure that are drawn with various symbols. Here is a sample maze:

#############################
#   @                       #
#   #####   #####    $      ######
#   #####    ##                  #
#    ###    !##     #######      #
#     ##    #####   #######      #
#      #                         #
#          O       $     D       #
##################################
Our compressed representation of the maze will be as follows:

  1. Line 1 is the number of rows in the maze
  2. Rows are input next, then players, monsters, and treasure
  3. The first entry in a row denotes the width of the row in characters and the remaining entries use the representation x or x-y to indicate either a single # at x or a line of #'s from x to y.
  4. A player, monster, or piece of treasure will be input on individual lines with a symbol, and an (x,y) location.

For example, the above maze would be represented by the input file (this file is named mazedata.txt in the lab3 directory):

9
29 0-28
29 0 28
34 0 4-8 12-16 28-33
34 0 4-8 13-14 33
34 0 5-7 13-14 20-26 33
34 0 6-7 12-16 20-26 33
34 0 7 33
34 0 33
34 0-33
@ 1 4
$ 2 21
! 4 12
O 7 11
$ 7 19
D 7 25
Your program will take a single argument, the name of the maze file, as input and output the appropriate maze diagram.

Required Design

  1. Read the number of rows and allocate an array to hold that number of strings
  2. As you read each row, create a string that is the maze representation for that row. The first entry in each row indictes the width of the row in characters and hence allows you to compute the length of the string required to hold that row (remember to include an extra byte for the null character). You may make no assumption about how wide a row might be, hence you must compute the width of the row and then a malloc a block of memory big enough to hold that row.
  3. After reading the rows and creating their string representations, modify the strings so that they include the players, monsters, and pieces of treasure at the appropriate places.
  4. Iterate through the array and print the appropriate string for each level

Hints

  1. Use the fields library to open the input file and to read the lines of input. You will need to declare your file variable as an inputstruct (an IS) and then open it using the new_inputstruct command. You can read lines using the get_line command.
  2. Use the fields member of an inputstruct to access the individual fields of a line.
  3. Use strchr to determine whether or not a string is in the form "x-y". If it is, you can replace the '-' with a '\0', thus converting "x-y" to two separate strings, "x" and "y", respectively. You can then convert each string to an integer. You can increment by 1 the pointer returned by strchr to get a pointer to the string for "y".

Name your file maze.c. No error checking is required for this program. A sample invocation would be:

maze mazedata.txt

Misc

When you're done, clean up all your stray pgm files -- they are large and with 60 students, that's a lot of wasted disk space. If you want to keep the images, use display to turn them into gif or jpg images to save space.


What To Submit

Submit the following files: