CS140 -- Lab 3

This lab comes in three parts and is designed to give you practice using the fields library, lists and command line arguments.

Part 1: 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. A row will 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:

9
0-28
0 28
0 4-8 12-16 28-33
0 4-8 13-14 33
0 5-7 13-14 20-26 33
0 6-7 12-16 20-26 33
0 7 33
0 33
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 last field in the input line will include the last wall for that row, and therefore allow you to compute the length of the string for that row (remember to include an extra byte for the null character).
  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 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.


Part 2: Sorting a Score File

You may have played games in which a high score list is printed at the end of the game. More sophisticated games may allow you to select a difficulty level and then keep a high score list associated with each difficulty level. You will write a program named score.c that creates a high score list for a game with 15 difficulty levels, ranging from 1-15. Your program will take two command line inputs, a score file and an integer representing the number of high scores to print for each level. It will produce as output a sorted high score list for each level. The scores will be printed from highest to lowest. Each line of input will have the format:

player_id level score
player_id is a 6 character or less id, level is an integer between 1 and 15, and score is a positive integer that is less than 100000.

The output should have the following format:

Level x:
    player_id score
    ...
Level y:
    player_id score
The level number should be in a field two digits wide, player_id should be in a field six characters wide, and score should be in a field 5 digits wide. level and score should be right-justified and player_id should be left-justified.

As an example, given the input file:

bvz 4 8585
bvz1 11 53
mary 4 58685
jack 4 838
marvin 8 6869
smiley 4 15868
ardvar 8 68
and the command:
score score_file 3
your output should be:
Level:  4
    mary   58685
    smiley 15868
    bvz     8585
Level:  8
    marvin  6869
    ardvar    68
Level: 11
    bvz1      53
Note that levels without scores are suppressed and all scores for a level are printed if the level does not have the requested number of high scores.

The only error check you need to make is whether or not the line has exactly three fields. Print an error message if the line does not have three fields and discard it.

Required Design:

  1. Each score should be stored in a struct that has a player id and a score.
  2. Use a 16 element array to store the levels (there is no level 0 so this entry will be null).
  3. Each entry in the array should be 1) null, if there are no scores for that level, or 2) a pointer to a linked list of score structs for that level.
  4. As you read scores you should insert them into the appropriate place in the list in descending order. If you insert them in descending order then it is easy to print the high scores since they are printed in descending order.
You can make no assumptions about the maximum number of scores that will be given to your program.

Part 3: listfile (Courtesy of the extraordinary Dr. Plank)

Implement listfile using the fields library so that it works exactly as described in the following blurb:
NAME
     listfile - display a fractional portion of the specified file

SYNOPSIS
     listfile start_fraction end_fraction filename

DESCRIPTION
     listfile copies the lines of filename between start_line and
     end_line to the standard output where start_line and end_line are 
     computed as follows:
	start_line = start_fraction * (number of lines in file)  
	end_line = end_fraction * (number of lines in file)  
     start_line should be rounded down to the next lower integer and
     end_line should be rounded up to the next higher integer. For example, 5.03
     will become 5 for start_line and 6 for end_line.  Similarly, 5.67 will
     become 5 for start_line and 6 for end_line.

     Precede each line of output with its line number and a colon (:). 
     Allocate 6 spaces for the number and right justify the number.

ERROR CHECKING
     listfile prints an error message if:
        1. either start_fraction or end_fraction is not a valid number,
	2. either start_fraction or end_fraction is not between 0 and 1,
	3. end_fraction is less than start_fraction, or 
	4. the file named filename does not exist.

Here are some helpful hints:

  1. You will need to make two passes through the lines in the file. The first pass will count the number of lines and the second pass will print the lines.

  2. Use a linked list to store the lines in the file so that you do not have to read the file twice.

  3. Use the math library's ceil function to round a number up to the next highest integer. The declaration for the ceil function is:
    	double ceil(double number)
    	
    You will need to cast the return result of ceil to an integer. You will also have to include the <math.h> file in order to use the ceil function and you will have to put a '-lm' flag at the end of your gcc line. For example:
    	gcc -o listfile ...-lm
            

  4. You can round a number down to the next lowest integer by simply casting it to an integer. For example:
    	double number;
    	int rounded_number:
    
    	rounded_number = (int)number;  // rounds a number down