Lab 3: Multiball Madness
Early Tuesday 5-Feb-2019 at 11:58 PM or before Due Thursday 7-Feb-2019 at 11:58 PM or before Cutoff is Friday 8-Feb-2019 at 11:58 PM
Read this carefully. Before you turn in your code, read each line of this document to make sure that you have accounted for everything called for.
As always, it must compile without errors or warnings on stdlinux using gcc –ansi -pedantic Use the lab 2 core simulation equations of motion.
This lab teaches:
1. Structs
2. Functions and short blocks of code 3. Pointers
4. Dynamic allocation and free
Differences
Lab 3 runs the basic simulation one time for multiple balls simultaneously in motion. Balls do not collide or interfere with each other. They bounce around as if alone until gravity takes them off the table. The simulation will read as many balls as it can and then run the sim until no more balls are left on the table.
Structures
Create two structures for the lab. One holds a single ball. The other holds many of those single ball structures. Create a new file named ballStructs.h in the same directory as your C code. Put your structure definitions in that file. Use #include “ballStructs.h” in your C code.
The structure for one ball has a single character designator so that we can name them and tell them apart from each other. The first ball you create will be designated as ball ‘A’ and the second one as ‘B’ and so on. A ball never changes its name. The structure also holds 4 doubles for X, Y, VX, and VY data we are familiar with from lab 2.
The structure to hold all of the balls will need a count of balls in play and a pointer to a single ball (the struct described in the paragraph above). Recall that a pointer can be used as the start of a dynamically allocated array. All of the balls in play must be kept in alphabetical order.
File scope variables are not allowed. That is no “global” variables. Make sure that your header files do not allocate any space. Make sure that your code has no global variables.
Dynamic Memory
Use dynamic memory to hold the array of balls. Be sure to free the allocated space when you are done. When a ball falls off the bottom of the table, it is no longer in play. So if 4 balls are in play, they will be named A, B, C, and D. If ball B falls off the bottom of the table and goes out of play, move ball C and D up one slot so that they stay in order. You will decrement the number of balls in play, but you won’t change how much space you have allocated. For this lab, it is OK to make fine-grained memory requests if you want. For example, every time you read another ball you could call realloc. Be very careful not to lose the pointer to your dynamic memory. Always check to see if allocation succeeded. If you can’t allocate memory, do not exit but print an error message and return a structure that has 0 balls in play.
Pointers
Structures are passed by value the same way ints are passed by value. You will need many functions in this lab (see “Refactoring” below) and so call by value and the need to change things will play a major part in how you design the function signatures. Thankfully, the -> operator makes structures and pointers get along well with each other.
You will be using an array of function pointers as well.
Refactoring
Lab 3 takes the core simulation of lab2 but refactors the code base to use short functions that are easy to understand. It pulls out constants and structures into their own files.
Be mindful of return values; many of your functions will have them. Functions that want to return what is effectively a Boolean will return int. Any function that returns a value should be capable of returning more than one value when running. Otherwise, make that function return void. Any function that returns a value should have that value used by the calling function.
Use const to protect data from being changed in functions that do not need to make changes. Your print routine, for example, doesn’t need to change anything so any pointer passed in should be marked const.
Refactor magic numbers to a separate file as follows:
Create a new file named constants.h in the same directory as your C code. Use #include “constants.h” in your C code file. Use #define to create symbolic constants for your magic numbers. The names must be in ALL CAPS and the values must default to the appropriate type.
Refactor your code into small functions that roughly follow the comments below. Your code doesn’t have to be in the same order. Your code doesn’t have to have the exact breakdown I used or even the
same names. Try to limit each function to 1 idea. Most, if not all, of your functions will be 10 functional lines or less. Do this to control the amount of detail exposed at any given point in your code. If you need more than 10 lines of non-declaration code, bring your design to the instructor for approval – don’t expect to get it. All future C labs must be written this way.
The comments below give very little detail about function signatures. Designing the signatures of each function is a major part of this lab.
/* your name, statement that you worked alone, and a brief description of the lab go here. */ /* # includes go near the top */
/* forward declarations if any go here */
/* main: */
/* have readAll fill out an AllBalls */
/* as long as one or more balls are in play, run oneSimStep and printAll */ /* deallocate any space */
/* readAll fills out an AllBalls struct */ /* loop scanf until it fails */
/* uses realloc to make space each time scanf succeeds and store values in the new space*/ /* if realloc fails, set in play to 0 and return */
/* printAll prints all of the balls in play */
/* oneSimStep takes the AllBalls */
/* each ball gets an updateOneBall call */
/* if update said it’s off the bottom of the table, adjustList */
/* updateOneBall takes a OneBall */
/* physics gives proposed new data for the ball */
/* 3 separate constraints called to adjust that data */ /* let the caller know if the ball is still on the table */
/* physics takes a ball and does the equations of motion to it */ /* 3 independent wall constraint functions go here */
/* adjustList takes the AllBalls and slot number */
/* every ball below the one to be removed gets moved up */ /* adjust the number of balls in play */
The 3 Wall Constraints
Each of the wall constraints will be a separate function that gets a ball and the time and if need be fixes the ball. All 3 functions will use the same signature. If a constraint function does nothing, it will return 0, otherwise 1. The wall constraints use a different error message than lab 2.
You may not invoke them by their names. Use a static array to store function pointers to the three wall constraint routines. Iterate that array. You may not use subscripts to iterate the array. Use a pointer and if need be some pointer math to call each function in turn. As long as at least one constraint fixed the ball, you need to run the three wall constraints again. In other words, run the list of constraints until no wall constraint needs to fix the ball.
Input
Input is the same as lab 2, except that you read everything possible before launching the simulation. Your code will be graded using the following data set, as well as others:
4.4 0.0 4.4 0.0 11.0 0.0 11.0 0.0 18.0 0.0
-8.0 100.0 6.0 48.0 -880.0 2.0 25.0 66.0 -2.0 970.0
The third ball above won’t last very long with such a low velocity in Y, but it will bounce off the left and right walls many times.
Output
When a wall constraint fires, it issues a 1-line error message formatted as follows: Ball A hits left wall at 5.50 seconds pos (-1.40, 19.29) vel (-20.00, 24.47)
The numbers in the error message should not have a min field width specified and they shall have 2 decimal places. Use fprintf to stderr instead of printf. Below is an example call to fprintf.
fprintf(stderr, “This is an error message #%d\n”, 6);
Regular output will need an additional column (and heading to go with it) for the ball designator. The output will again be tab separated. That data shown below is tab separated, but the spacing in Word is different than what you might see on stdlinux.
Ball X____ Y______ VX___ VY_____ ET__ –assume a few iterations printed here —
A 6.2000 12.9884
B 4.2000 1.98844
C 6.2000 12.9884
6.0000 33.8842 0.30 6.0000 -33.8842 0.30 6.0000 33.8842 0.30
Ball B leaves the table at 0.40 seconds.
A 6.8000 16.9884 6.0000 29.8842 0.40 C 6.8000 16.9884 6.0000 29.8842 0.40
After you print all of the balls still in play, print an extra newline to create a blank line after the last ball. This will group all the balls with a common time in blocks with the error messages at the top of the block. The data shown above is made up. It is correctly formatted, but the numbers are random.
Redirection
Your code should work when run on the command line with no redirection. This may be the easiest way to do initial testing. Your code should also work when you redirect stdin, say from a file. This may be the easiest way to load 3 or more balls on every run. Be sure to test your lab on the command line with everything redirected. Run your lab with the following command:
$lab3 < testdata > output 2>errors
Pay attention to what displays on the console. Run the cat command on errors and then run it on output. Describe the results in your readme file and how it differs from everything on the command line.
Comments
Comment your code. Comments should say things that are not obvious from the code. In lab 2 the printf error messages explained what each constraint was pretty well so we didn’t comment those blocks. Good names and detail control also mitigates the need for comments.
Comments can show intent – what you meant, which may vary from what you wrote as code.
Comments can make clear things that are easily confused in the code. If you have two operations that are similar but slightly different, explain the difference.
Comments can show why you did something when all the code says is what you did. If you can’t do something in the most obvious way for a reason, comment with that reason.
At a minimum, put your name and the assignment number in your initial comments. Also add the statement that says that you wrote all of the code in the file (see below).
This requirement is mandatory for all future labs
Formatting
Please use indentation. If you don’t have an established style, use the 0-8-4 style shown below. It sets off functions well. After the first indent, it uses 4 spaces for the rest since many displays in the Unix world are only 80 characters wide. Code that wraps is harder to read, so try to fit it nicely on an 80 character line. If you break a single statement onto multiple lines, break on a comma and indent the lines after the first line.
Using indentation is mandatory for all labs (assembler has a different style). If your style is different and makes your code harder to read, you might lose a point.
0-8-4 Example below:
main() {
/* file scope items have no indent */
int i, j=0; /* initial indent is 8 spaces */ for(i=0; i<5; i++)
{
j=j+i; /* all successive indents are 4 spaces */ j= doSomethingComplex( complexParam1, complexparam2,
anotherParam, embeddedCall() ); /*indent the overflow */ /* return to regular indent level */
} }
Readme
As always, create a text file, in this case named “lab4readme” and submit it with your code. All labs require a readme file. Include:
• Your name
• Hours worked on the lab
• Short description of any concerns, interesting problems, or discoveries encountered. General
comments about the lab are welcome.
• This item pertains to redirection. Describe the contents of the output file and the errors file.
What did you see on the command line when you ran lab3 this way?
Method of Attack
Start simple. Take small steps. Save intermediate results. Control complexity. Build a little, test a little.
For example:
If you haven’t ever done anything with a function pointer, write a short program that has a simple function of say two parameters, a short and a long. Create a function pointer variable and see if that compiles. Set the pointer equal to the function and see if that compiles. Use the pointer to call the function (the function should print a handy message) and see if that runs as expected.
Now copy that working code to a new file and see if you can create an array of function pointers and load them with values. Once that compiles, add a simple loop with subscripts to iterate those pointers and call their functions. Do something useful with the return values. Run it and see that it works.
Now copy that code to a new file and change your iteration from subscripts to either pointer math or create a pointer to a function pointer and set it to point to the first pointer in the array and then increment your added pointer.
Now take your iteration code and copy it to yet another file and wrap that with another loop that keeps running until all the return values are to your liking. You may have to be careful about what your functions do so that they cause the loop to iterate but doesn’t infinite loop.
Now you have working code examples to draw on to write the code for the wall constraints, which will have different signatures.
Now apply this way of doing things to the next new thing and iterate.
Submission
Submit a zip file containing ALL of your source code files. If you don’t include your header files (*.h) in your zip archive, the .c file(s) in your archive won’t compile and you will get zero credit! Do not include executable files, just the .c and .h files. The zip file gets uploaded to Carmen the same way as earlier labs. Test your zip file in an empty directory to make sure it has everything needed.
Do your own work – write your own code.
Every line of code should be code that you wrote. Help with writing code should only come from the instructor or a grader. Helping someone else write their code is a violation of the standards of this class. All such violations immediately go to the Committee on Academic Misconduct.
The following comment is mandatory in your C code file or you will receive 0 credit.
/* BY SUBMITTING THIS FILE AS PART OF MY LAB ASSIGNMENT, I CERTIFY THAT ** ALL OF THE CODE FOUND WITHIN THIS FILE WAS CREATED BY ME WITH NO
** ASSISTANCE FROM ANY PERSON OTHER THAN THE INSTRUCTOR OF THIS COURSE
** OR ONE OF OUR UNDERGRADUATE GRADERS. */
If you are looking at someone else’s code, you both are at grave risk; ask them to take their problem to the instructor or a grader.
If you are showing them your code at the same time they are showing you their code, it is a violation.
If you can’t write your own code when you have a week to do it, you won’t be able to write code for the midterm.