These assignments will have you playing more with pointers and arrays since that is what we have been talking about. All of these assignments will also take command-line arguments instead of reading input from the user with scanf.
After each problem description I've given you a sample output file. You should produce something similar to my output.
As a side note, be sure to save the code from all the programs you do. It is quite possible that later in the semester other assignments will include things that overlap with them and your code will be reusable.
File Stats:
There is a utility in Linux called wc which stands for word count. You can run it on one or more files and it will tell you how many lines, words, and characters there are in the files. For this assignment option you will do the same thing, only I also want you to count how many time each letter occurs in each file (regardless of case). The files you should work on will be specified on the command line. Your program should read through each file and count up how many characters, words, and lines there are as well has how many times each letter occurs. You will print this information for each file followed by a grand total for all the files. Your program might be invoked as "a.out *.c", which would go through all the C program files in the current directory.
You will consider any string that is between whitespaces to be a word. All white spaces in ASCII are at or before the space character (' '), so use <=' ' for doing this counting. Check the provided output for details on what that should look like.
Symbolic Algebra:
We wrote simple little calculators in class and even a parser for Scheme expressions. Now we want to go a bit further to have you write something that could actually be useful. For this option, you will write a program that recursively parses a string for an arithmetic expression and returns the value of it. Examples would be 5+7 or 9*(5+7.5)/2. Your parser should do proper order of operations binding (things in parentheses bind highest, * and / before + and -, and go from left to right for the same level of priority).
The approach I want you to take for solving this problem is with a recursive algorithm that breaks the problem into pieces starting with the lowest priority operation. You will write a function double parse(char *exp,int start,int end);. This function will return the value of the expression in the string exp in the characters between indexes start and end. First it should find the lowest priority operator (it can't be in parentheses). If it finds one it recurses twice with the values of start and end that give the strings on either side of that operator. If there isn't an operator that isn't in paretheses you can check if the string starts with '(' and pull the bounding parentheses off and recurse on what is left. If it doesn't start with '(' you know that part of the expression is just a number it returns the value of the number.To get the value of a number you can use the atof function in stdlib.h.
The user will give you a formula, that doesn't include any spaces, at the command line and you should simply print the value it evaluates to. So a potential invocation of your program might be as follows: "a.out 5+3*(70/5)". I'm not providing a sample output file because this would simply output 47.
This assignment will lead into future assignments. It will be merged with the BASIC editor if you did that for assignment #5, but can be used for other things in other cases.
Mandelbrot Set:
This program will generate text files that can be displayed using the raster viewer I have given you previously to render sections of the Mandelbrot set. This is a rather famous fractal produced by a simple equation. This equation is z_n+1=(z_n)^2+c. The trick is that z and c are complex numbers (they have both real and imaginary parts. Also, z_0=c. For every point c in the complex plane, you can run through this series and it will either run off toward infinity or it won't. If it does run off it is not part of the Mandelbrot set. If it stays bound, it is part of the Mandelbrot set. Obviously, you can't run the equation forever so the user will tell you the maximum number of times to try. If the magnitude of z (distance from the origin in the complex plan) ever gets bigger than 2, you should stop the calculation and go to the next point because that one will just get larger and larger.
When the user runs your program he/she will provide seven command line arguments: number of pixels, maximum iterations, file name, real minimum, real maximum, imaginary minimum, and imaginary maximum. You will open the filename and print the number of pixels on the first line. Let's call the N. Then you will do N points across the row in the complex plane where the imaginary component is imaginary maximum and the real component goes from real minimum to real maximum. You will do this over again N times, making the imaginary value slightly smaller each time so you get to imaginary minimum at the Nth iteration. For each value you calculate you will output one integer, the number of iteration the magnitude stayed less than 2 (or maximum iterations if it stayed less than two that whole time). This file can be read in by RasterViewer to produce a black and white image of the set.
For extra credit, don't output the number of iterations. Instead, output an RGB encoded hex string (like in the raster option for assignment 4). You can decide how to vary the color, but pick something to make the points in the set stand out from the rest and try to make it colorful.
The first two output files were made with the following command:
a.out 400 150 fullMandel.txt -1.5 0.5 -1 1
int output : This file can be viewed using the RasterViewer with "java -jar RasterViewer -d 150 fullMandel.txt".
rgb output : This file can be viewed using the RasterViewer with "java -jar RasterViewer RGB fullMandelRGB.txt".
big rgb : This one shows a blowup in color.
Map Traversal :
This is the first installment for you building your own text adventure. Your program will read in from a map file that you will write by hand and let the user run around in that map by using commands like "north" to move from one room to another. The map file will have a fairly simple format right now and you will create your own map file using vi. Make sure when you submit this program you turn in both the .c file and the map file so I can walk through your map.
The format of the map file should be something like the following:
room_number room_name
long line of room description
number_of_links
direction1 destination1
direction2 destination2
...
This is repeated over an over. Each room should have a unique room number and it should start at 0. The reason is that you will be putting all the room information into arrays. I'm providing a sample map file below, but you don't have to stick perfectly to that format if you don't want to. You might deviate if you are thinking about other options you will add in later. Odds are good you will be refactoring your code later anyway to add support for things like structures once we cover them.
The interface for your program is quite simple. When you run the program it should read in the map file and keep all the map information stored in various arrays (they might be dynamic). You will start the user in room 0 and print the description of that room and the different directions they can go as well as where they lead to, then follow that with a prompt. You could just use ">" as the prompt to start with. It might get more complex later on when you have real game functionality. So when the user starts the game it might look something like this if you read in the sample map file.
Halsell 228
You are standing in a room full of computers and comfy chairs with a giant air conditioning unit hanging from the ceiling. While the surroundings are serine enough, you can't help feeling a certain amount of dread. This isn't just a fear that the air conditioning unit is going to fall either. Something in you tells you that this room is regularly used for strange rituals involving torture. You can only wonder what happens here and why there isn't blood all over the place. Your uneasyness makes you want to leave quickly.
The hallway is east.
>
The user must type in either a direction to move or "quit". If anything else is entered you should print an appropriate error message.
Graphics Problem:
For this problem you will be bringing together components of the last two graphics assignments to make something a bit different. You are going to use parts of your raster drawing program to help "render" a scene in 3-D. You are going to use a very simple rendering model to do it so that things aren't too complex. A real rendering model would have things look smaller as they move away, that is a perspective view. You aren't going to do that. You'll assume that your lines of sight are parallel which makes things a lot easier.
What you will build is something a lot like assignment #4, but now the image will be in 3-D instead of 2-D and you will have some lighting from assignment #5. In this assignment there are two things that you can add to what you are drawing, triangles and light sources. You should be able to handle at least 3 lights and 20 triangles, but you can write your code to handle more than that if you want. When you start the program, you won't have any of either. You will have functions that read lights and triangles from a file as well as a function to write such a file. Your code will also have the simplePrint and printRaster functions you wrote before. The first one will still print to screen just so you can see roughly what it looks like. The second though should write out to file. The user should be prompted for a file name. Make sure your print raster prints a first line with the width and height that you use on it. I left that out of my earlier sample output. I'll be providing you a way that you can view those images in color if you want to. So the functions in your program are the following
The lights and triangles will have x, y, and z coorodinates. x and y will be just like they were in the earlier program. z will be distance from the viewer. When you draw a triangle (you get to figure out how to do this), you will ignore the z component for where it is on screen. That will only matter for determining the lighting on it. When the user adds a triangle, that should be drawn on the raster with the current lights. When a light is added all the triangles will need to be redrawn so that they use all the lights. Each triangle and light should also have a color specified for it. To determine the color to draw each triangle, you will add up the colors it would be for each light. To determine that, you will use what you did for assignment #4 to get the intensity of the light. One alteration you should make here is that using the pixels distances for the 1/r^2 decrease in intensity causes things to be very dark so instead, take the distance you find and divide it by WIDTH to get a more appropriately scaled value. If we say that value is frac, then the color from that light will be a rgb where each component is determined as follows. r_drawn=frac*r_tri*r_light/255. The reason you divide at the end is because the components aren't between 0 and 1, but between 0 and 255 so to get a value in that same range you multiple the two and divide by 255.
The only geometric shape you are drawing for this is a triangle. Of course, any polygon can be built out of triangles. Drawing triangles isn't a simple task though. My hint to you is that you should figure out where you would draw lines between the points, then for each row in the raster, fill all the pixels between those. Then you only have to worry about the math for drawing a straight line.
The option to read in a geometry file should ask for a file name, clear your current geometry, then read in a file that has new lights and triangles. The format of the file has lines that start with an 'L' for a light or a 'T' for a triangle. You can read a string for that and just examine the first character. Following that will be either 3 numbers for a light or 9 numbers for a triangle. After this is called, the raster needs to be cleared and all the new triangles should be drawn. Note that the reading function will have to check for feof to know when it is done. Writing a geometry file should ask for a file name then write the above format to it.
If you want to do this option and you didn't do the graphics options on earlier assignments, let me know and I can e-mail you code for those.
To view your rasters graphically download this file to the directory you are doing your assignment in. To use it you will need to have a recent version of java installed. The ones on the mab machines should work well. At the command prompt, type "java -cp RasterViewer.jar RasterViewer RGB raster.txt". The raster .txt can be replaced with whatever file name you are using for your output file.
input : output : orginal format geometry file : geometry file : raster file
Biology/Chemistry Problem:
In this problem you will model diffusion of particles and how that can lead to crystal growth. For this assignment you will implement a "raster" like what was done in the graphics option for assignment #4. However, for this one you can use just a simple raster of characters if you just want to print out text images of the crystals. If you want to use my raster viewer (which is described in the graphics option of this assignment) then using the raster style from assignment #4 can help, but you don't need the full color functionality unless you want to make your pictures prettier. You will also be using the random number generator in C to help with modeling diffusion which appears to be a random process on a macroscopic scale. The random number generator in C is rand() which you can get more info on with the man pages.
The menu for this application should look like this:
The data you will store in this program has two basic parts, a raster which is a 2-D array of ints and configuration data that keeps the number and locations of your sources. A source is just an x,y position in the raster and you should be able to support up to 10 of them. For this "simulation", you will start a "particle" at one of the sources and let it drift around until it comes in contact with another particle. This might sound complex, but it isn't. Say you have one source at 5,5. You start your "particle" there just by keeping track of 5,5 in two varialbes. Then you pick a random number between 0 and 3 (rand()%4) and depending on what that number is you try to offset your particle either up, down, left, or right. If we got a move to the right our particle would now be at 5,6. The procedure is repeated until the move would put the particle in the location of another particle. At the beginning the only particles out there are seeds which you have placed. If a particle tries to move onto something, it attaches there and is put on the raster. If a particle ever tries to move out of the raster bounds, simply don't move it and pick another random number.
The clear raster option sets all the values in the raster (your 2-D array of ints) to zero.
The clear sources option sets the number of sources to 0.
When the user selects "Add Source" you should ask them for an x,y location and put that in your source array(s) then increment the number of sources by one.
When they select "Add Seed" you should ask them for an x,y and put a non-zero value in your array at that location. This is effectively a particle that things can stick to.
When they do "Free Particles", you will ask them how many particles to free. Then you will repeat the following procedure that many times. First pick a source at random from the sources you have. If they haven't made a source yet, give them an error message and go back to the menu. Then start a particle at the source location and let it do a random walk as described above until it attaches to a non-zero value in the raster/array.
If the user selects option 6 you should print out the sources to screen, then print out a simple representation of your raster to screen. Print a blank (' ') for each zero entry and an 'X' for each non-zero entry. Separate the lines of the raster with newlines. See the sample output for more information on this.
When they select item 7 you should ask them for a file name to save to, then "print" the raster in a manner like what is described in assignment #5: graphics option so that it can be viewed with the raster viewer. The difference being that if you don't want to make it pretty you don't have to. Your file should start with two ints on one line. These give the size of you raster. After that is 6 characters per pixel in the raster. To make things simple, you can print 0 if the raster value was 0 and 10 if it was not. This just gives you black and white, but you will be able to see what you get.
If they select 8 you should ask for a file name and write to that file the information on your sources. The easiest format is probably the number of sources followed by x and y for each one.
If they select 9 you should ask for a file name and read in whatever format you wrote from that file.
For extra credit you can have your new particles color coded by the point from which they were released. This will allow you to visualize where the particles end up. You could also color code them by "when" they were released so the color coding changes as you move away from the seed. This means printing something a bit more complex for the pixel values, but you still don't have to pack and unpack colors like in assignment #4 unless you want to.
input : output : raster file 1 : raster file 2 : source file