CSCI 1320 - Assignment #4



Before this is due, we will have expanded your abilities so that you can make extensive use of loops in your code to go along with functions and conditionals. Pick one of the options below to complete. We are now getting to the point where you don't want to just start coding. You want to start by sitting down and thinking about what your code needs to do and how you are going to make it do it, paper and pen might even be helpful for this. I can almost promise that every minute spent really thinking about what you are going to be doing will save you 2 minutes of coding/recoding/debugging.

After each problem description I've given you sample input and output files. If you run the program with the input I give you should get something pretty much identical 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.

Standard Problem:

If you choose this option, you will write a little program that does encryption and decryption of a message that you type in. You will also write the code to decrypt that same message. By using redirection of I/O you will be able to easily test to see if it works. Your program will not only have a main, but at least three other functions called encrypt, decrypt, and readTo10.

The encryption your program does will be a 2 part encryption. First, it will offset the characters in the ascii set by a given amount. Then to make things harder, it will throw in a random character after every nth character in the message. So the input of your program will be an e or d followed by two numbers, offset and spacing. Offset is what you will add to all the character values and should be between 1 one 10. Spacing is how far it is between the randomly inserted characters. After that, on a new line, will be the message itself. If the first letter was an e you should do encryption, otherwise do decryption.

Both the encrypt and decrypt functions will have a return type of char. You probably need to pass in the offset and spacing values. Depending on how you design your code, other values might need to be passed in as well.

The encrypt function will first check to see if it is time to insert a random character. If it is it will return a random character generated using the rand function. You can just put return rand()%26+'a'; into the code at that point. The rand function is part of stdlib.h and you can use "man 3 rand" to get more information on it. If it isn't time to insert a new character, you should read one character from standard input, scanf("%c",&oneChar), then return the character that is "offset" positions above it in the ascii table, oneChar+offset.

The decrypt function does something very similar to the encrypt function. If it is at a position where a random character would have been inserted, it reads in one character and ignores it. Whether or not is has reached "spacing" yet, it will read in a character and then return the character that is "offset" below that character in the ascii table.

The readTo10 function is just reads in characters until it gets to one with an integer value of 10 which is a newline. You need this to make sure that you read all the way to the end of the first line before the messages.

Back in main, after you read in the 'e' or 'd', the two integers, print them out, and call readTo10, you will want to go through a loop as long as there is more to be read. If you are using file redirection you can do this by looking at the return value from scanf. We haven't looked at this previously, but if you do a "man scanf", you will find that its return type is not void. Instead, it returns how many things it read in. If you try to read a character and this value is less than one then there was nothing left to read. I will leave it to you to decide how to turn this return value into something that will tell the loop in your main to stop. If you just type in your output instead of using I/O redirection, you will have to use ctrl-C to stop when you have put in everything you want.

To see what the program wants to read in and will print out look at the files below at examples that I did. Your encrypted version doesn't have to match mine perfectly, there is randomness after all, but when you decrypt your encrypted one it needs to be identical to the input you use.

orginal file : encrypted file : decrypted file

Graphics Problem:

By breaking a problem up into pieces things that might seem a bit intractable can become tractable. For this assignment you will start writing some routines that you could use to build a graphics library for doing 3D graphics or ray tracing. In particular, you will begin writing routines that could be used to find how brightly a particular surface should be lit given some information about the surface and the location of a light source.

The idea here is that we have a simple flat surface that is being lit by a single light source. You will be given the location of the light source as well as the location of three points on the surface (if it were a triangle, they would be the corners). For now we will do a simple form of lighting where you assume that the entire surface is lit uniformly. This is sufficient for basic 3D graphics but can easily be improved upon in many ways and will be if you do ray tracing. We will also assume that we are dealing with a matte surface so all light is reflected in a diffuse manner.

How bright a surface will appear depends on two things: distance from the light source, and the angle of the surface relative to the light source. You will write four distinct functions to help you compete these values. The easy one is distance. I will want you to use the distance from the first of the three points that you read in and create a function that returns a double that is the distance between the two points passed in. They will be passed in as six doubles for two sets of x, y, and z. The intensity goes as 1/(r*r), where r is the distance from the light to the point on the surface you are using.

To get the angle you need to know a vector from the light to the surface, as well as a vector for the direction normal to the surface (normal vectors are perpendicular to all lines in the plane of the surface). Then you want to know the cosine of the angle between the vectors. That sounds like a very difficult thing to find, but there are some simple math functions that can help us to get what we want. Getting the vector from the light to the surface is quite easy, just subtract the components of one from the other so that is easy. Getting the vector normal to the surface is a bit harder, but not that much. As it turns out, there is something in math called a cross product that operates on vectors. The cross product of two vectors is a vector that is perpendicular to both. So how do we get those two vectors? Well, they can be any combination of vectors between the three points you read in so maybe <x1-x2,y1-y2,z1-z2> and <x1-x3,y1-y3,z1-z3>. Then the question becomes, what is the cross product (also called the vector product). It is defined as the determinant of a matrix with the unit vectors in the top row, the first vector of the product in the second and the second vector in the third. So for the product a x b=<ay*bz-by*az, az*bx-bz*ax, ax*by-bx*ay>.

So now you have two vectors you need to find the cosine of the angle between them. As it turns out, there is another type of product between vectors called the dot product that does this. Actually, a.b=|a||b|cos(t)=ax*bx+ay*by+az*bz, where the |a| and |b| are the lengths of the two vectors. We just need the cosine, so we need to make the vector lengths equal to one and then that nice expression at the end gives us what we want. First you will write a function called normalize that takes the three components of a vector and divides them all by the length of the vector so you get a vector of length unity. Then you need a function that will take the dot product of two vectors.

So the functions you need to write are as follows: distance, normalize, dotProduct, and crossProduct. Some of these need to return multiple things so pass by reference might be handy. Your main will basically read in the x, y, and z position for the light followed by x, y, and z for each of the three points. It will then call the functions you have written and output the cosine of the angle divided by the distance squared which is the relative intensity of the lighting. If you ever get a "negative intensity", just flip the sign when you print it out.

input : output

Biology Problem:

An interesting twist that biology has taken over the past few decades is the ability to look at the populations of different species and how they interact with one another. Often, the way in which different populations vary over time can be approximated by simple mathematical expressions. In this assignment you will use your basic knowledge of loops, conditionals, and functions to examine a simple case where you have two different populations that interact in a preditor-prey manner.

The simplest form of this problem is the rabbit and fox scenario. The idea is that each summer you go out and count the population of rabbits and foxes in a certain region. This region is fairly well isolated so you don't have animals coming in or leaving. In addition, the climate is extremely temperate and there is always enough grass so environmental factors don't seem to impact the populations. All that happens is each year the rabbits try to eat and have babies while not getting eaten and the foxes try to catch rabbits. We will make up some formulas for what happens to the population from one year to the next and you will write a program to do this sequence.

Over the course of each year the rabbit population will be impacted in the following ways. Some rabbits will be born, some rabbits will die of natural causes, and some rabbits will be eaten. Similarly some foxes will be born and some will die. The number of rabbits eaten depends upon the population of foxes in the previous year (more foxes eat more rabbits) and the number of foxes who are born and die depends on the number of rabbits because foxes can't live long or have young without finding rabbits to eat. We can combine these things to come up with some equations that predict the numbers of foxes and rabbits in a given year based on the number in the previous year.

Here we assume that the natural tendancy of rabbit populations is to increase without foxes around and the natural dendancy of fox population is to decrease with rabbits around. The 4 constants should have positive values. A represents the normal increase in rabbit population without predation. B is the predation rate and is multiplied by both the rabbit population and the fox population because if either one is small, the predation rate is small. C is the rate at which foxes would normally die out without being able to bear young (if they didn't have enough food). D is the rate at which fox will bear young when they do have rabbits to feed on.

The input for your program is the initial rabbit population, R(0), the initial fox population F(0), and the four constants. To start you off, you might try values of 100, 10, 0.01, 0.001, 0.05, and 0.001. You can play with these values to try to find some that produce interesting results. Print out the first 1000 iterations of your loop. To make it so that you can see your results easily, I want your output to be only numbers. Never prompt for anything. The advantage of this is that you can create a file that is easy to plot with a program like gnuplot. When you run the program you redirect the output to a file then you can run gnuplot and plot it with that to see what it looks like. If you print 3 numbers per line, n R F, and put it in a file called pop.txt then you can plot that in gnuplot with a command like plot 'pop.txt' using ($1):($2), 'pop.txt' using ($1):($3). There are many other options in gnuplot and you can use the help command in gnuplot to see them.

For extra credit, put a comment in your code documenting some interesting behaviors that you saw at different input values.

input : output

Physics Type:

Computers are used extensively for simulating physical systems, especially when the system is hard/impossible to build in a lab. For this assignment I'm interested in having you write a very simple simulation of the gravitational Kepler problem. You will also explore the accuracy of what you are doing a little bit. Imagine you have a body in orbit around a star. We'll assume that the star is much larger than the other body so it stays at the origin, (0,0), of our coordinate system. The other body starts at some position (x,y) with a velocity (vx,vy). A simple "integrator" for a system like this can be constructed by discretizing Newton's laws (a fancy way fo saying that we avoid calculus and do things in a way that is more computer friendly). Newton's second law tells us F1=m1*a1 and fro gravity F=-G*m1*m2/(r*r). We're going to simplify this a fair bit for our toy system and just say that a=-1/(r*r). We can break this into components and get ax=-x/(r*r*r) and ay=-y/(r*r*r). Now, the trick on the computer is to say that instead of moving smoothly, the particle jumps over certain timesteps, dt. So after one timestep the new position is x=x+dt*vx and y=y+dt*vy. Similarly, vx=vx+dt*ax and vy=vy+dt*ay. Doing this in a loop "integrates" the motion of the body. (Use the sqrt function in math.h to calculate r.)

This integrator is very simple, but far from perfect. If you start with your body at (1,0) with a velocity of (0,1) it should be in a nice circular orbit staying that distance forever. By measuring how that distance changes, you can get a measure of how accurate, or inaccurate, the integrator is. You can play with other positions and velocities to see what happens. as well.

If you choose this part, you will write a program that takes the initial x, y, vx, and vy as well a a timestep, dt, as inputs.It should then advance the system for a total time of 10.0 (so if dt=0.1 that requires 100 iterations). At the end of it you should measure the distance from the origin and print a message giving that and the original distance. Then check to see if the change is less than 1%. If it is, say that the integration was accurate enough, otherwise say it isn't. In a comment in your code you should tell me how small you had to make your timestep for this to be reached given the coordinate 1 0 0 1. (I should note that this measure of accuracy is only good for circular orbits. We aren't going to do enough physics to go beyond that, but if you happen to want to, the real objective is to conserve total energy. You can get extra credit by comparing inital and final total energies of the system.)

For fun you can change it so it prints the x and y values during the simulation and see what is happening with gnuplot in a manner similar to what is described in the biology problem. This can also be helpful for debugging. I have included such prinouts in the sample output.

input : output

Logic/Football:

This problem is something of a standard at high school programming contests. You should prompt the user for a football score and then print out the ways that score could have been achieved. For large numbers that is a long list, so I'll ask that you only print 5 ways it could have been reached.

If you aren't familiar with football there are several ways to score and they result in different numbers of points. (I'm going college rules a full description of which can be found here.)

input : output