CSE 201 - Tutorial 1 - First C++ program (compiling and running) and Control Flow
Programming a simple shooting game
You will program a simple shooting game in C++
where the
player has to hit a target with a projectile.
The game is played in the 2 dimensions (on the horizontal axes \(x\) and the vertical axes \(y\)), the projectile is always shoot from the origin \((x=0, y=0)\) specifying the projectile shooting angle and velocity and the target is always to the right and above the origin (\(x\ge0\) and \(y\ge0\)). The player wins the game if one of the projectiles hits the target.
In the figure above you see a graphical representation of a trajectory: the projectile starts from position \((0,0)\) and then follows a parabolic motion until it eventually hits the ground.
From the figure above, note that:
- there is still no target to hit and the trajectory ends when hitting the ground (\(y = 0\));
- the game you will program will be completely textual. The player will play inserting the coordinates for the target and the initial projectile angle and velocity and the program will compute if the projectile hits the target; and
- you will compute the position of the projectile sampling its position at different intervals of time. In fact, notice that in the figure above there is a sequence of points and not a continuous line for the trajectory. Consider the following image: the image shows two trajectories (the orange one and the blue one) for a projectile shot with the same initial angle and velocity but with different sampling time (0.5 seconds for the orange one, 0.005 for the blue one). You can see that the orange trajectory has less points because it’s sampling time is larger.
Note that you will not be able to check when a trajectory exactly reach the groud (i.e., exactly when \(y=0\)).
You will program the game gradually through a series of exercises.
Setting up the tutorial.
- Download the handin of the tutorial
CSE201-td1-1-handin.zip
. - Extract the handin of the tutorial. This will create the folder
CSE201-td1-1-handin
. - Open QT Creator, then go on the menu “File”, then select “Open File
or Project…”. Navigate to the
CSE201-td1-1-handin
folder and select the filetd1.pro
.
At this point you should be able to:
- compile the project (click on the menu “Build”, then “Build Project td1”, or alternatively click on the hammer icon in the bottom left).
- run the automatic grading (click on the menu “Build, then”Run”, or click on the green triangle in the bottom left).
You will only edit the file td1.cpp
: the file already
contains the declarations of the functions you will have to implement
during the tutorial.
Evaluation.
You will be evaluated on all the exercises, for a total of 100 points. The different exercises gives at most the following amount of points:
- Exercise 1 (max): 5
- Exercise 2 (max_io): 5
- Exercise 3 (read_doubles): 10
- Exercise 4 (simulate_projectiles): 30
- Exercise 5 (compute_min_distance): 20
- Exercise 6 (multiple_projectiles): 20
- Exercise 7 (play_game): 10
Note that each exercise usually extends the previous ones. So, work on the exercises in order.
Rules for the evaluation:
- A program that does not compile will receive a
total of 0 points: this means that your program cannot contain syntax
errors (e.g., forgetting the
;
sign after a statement) and typing errors (e.g., assigning an array variable to an integer variable). - Each program will be evaluated running on a set of different inputs. You will receive the points for an exercise if your implementation behaves correctly an all the test cases.
- We will look at the latest solution you will submit online.
Running the automatic grader.
You can execute your evaluation directly from QT Creator running the main grading program, you should get an output like:
--------------------------------------------------------------------------------
START TEST - max
[FAILURE] max(0, 1): got -1 expected 1
[FAILURE] max(20, 1): got -1 expected 20
[FAILURE] max(-2, 1): got -1 expected 1
[FAILURE] max(-3, -4): got -1 expected -3
[FAILURE] max(0, 0): got -1 expected 0
[FAILURE] max(1, 1): got -1 expected 1
END TEST - max: [FAILURE] (0 correct test cases out of 6)
--------------------------------------------------------------------------------
... you will see more output here ...
--------------------------------------------------------------------------------
Scores summary:
--------------------------------------------------------------------------------
1 max: 0
2 max_io: 0
3 read_doubles: 0
4 simulate_projectiles: 0
5 compute_min_distance: 0
6 multiple_projectile: 0
7 play_game: 0
Total: 0
--------------------------------------------------------------------------------
The first section shows the results of grading a particular function
you have to implement (in the example the function is max
).
You see that several tests failed, for example:
[FAILURE] max(0, 1): got -1 expected 1
Is telling you that your implementation of the
function max
called with the paremters 0
and
1
returned -1
as result, while the correct
result is 1
.
The line:
END TEST - max: [FAILURE] (0 correct test cases out of 6)
tells that your implementation is not correct and it did not pass any test case. To get the points, you need to pass all the test cases.
The last section shows a summary of the scores for all the exercises and all the tutorial.
Here’s some tips:
- Some functions test the input to the program and the output that you print from the program. Please, respect the instruction about reading the inputs (e.g., read enough numbers as input) and printing the output (e.g., print exactly the string we require to see). Otherwise, the grading procedure will consider a test failed (and hence you will get a lower score). The automatic grader is also case sensitive, so it will consider upper case and lower case letters different (e.g., “Hello world” is different from “hello world”, because “H” is different from “h”).
- You will get a detailed output from the automatic grader about the tests that succeed and the ones that fail. Try to understand the input/output of the tests that fails and why your program is wrong.
Submitting your Work
You will submit your work, the file td1.cpp
here:
You will only have to send the td1.cpp
file. The server
will automatically run the automatic grader and give you feedback on
your submission:
IMPORTANT: submit your partial solutions (i.e., submit your solution every time you solve an exercise) during the tutorial! In this way you will avoid surprises in the evaluation (e.g., things that work on your laptop but on on the automatic grader system) and you allow us to understand how the class is doing. You can submit and test your code as many times as possible and we will evaluate only your last submission.
The deadline for submitting the exercise is next Sunday, September 25th, at 23:59 Paris time. The submission site will not accept new solutions after that date.
IMPORTANT: your final grade is the one that the server computes (and not what you see on your machine!). Both results should be the same, but different machines may give different results (e.g., different operating systems, compilers…). If you get different results please get in contact with us.
The server will show if you solved correctly each exercise. The server will also highlight the first test case that failed and a complete output of your program. In the complete output of the program you will be able to see the complete compilation process and the full output of the automatic grader.
You can submit your solutions as many times as you want. However, the server that runs the automatic grader will take some time to process your program (compiling your program and running it on all the test cases). So, first solve an exercise on your local computer and, once your solution is correct, submit it and check if the results you get on the server is the same.
Useful Resources.
There are different resources you can use to get started on your exercises:
- Use the slides presented in class to refresh your mind;
- Since you are used to the
Python
programming language, you can use these notes (courtesy of Kaustuv Chaudhuri) that provides a quick comparison between Python and C++: use those notes to map the concepts you know fromPython
toC++
when possible (some concepts cannot be mapped, and in that case you’ll have to understand the differences between the languages). - Also, you can (and should!) consult the C++ reference documentation when in doubt on the syntax and semantics of statements.
Use the above resource for the rest of the course and for your project.
1. Find the maximum of two numbers
Write a function that computes the maximum among two floating point
numbers. You will write the implementation of the max
function in the td1.cpp
file:
double max(double first, double second) {
// IMPLEMENT YOUR CODE HERE
return -1.0;
}
While we will learn more about functions in C++ next week, in this
tutorial you will just need to know that a function takes some
parameters as input (in the example above, first
and
second
of type double
), and returns a value
(in the example a value of type double
). You can use the
input parameters in the body of the function (as in Python). Note an
important difference between C++ and Python: in C++ you have to
explicitly declare the type of all the
variables (and parameters) you use.
In this function you will use the double
primitive type
to store your floating point number (another primitive type is
float
, which is less precise but also uses less space than
a double
number, see the IEE754 standard if
you’re curious).
Finally, you’ll need to use an if
statement to compare
the two numbers:
if (<boolean condition>) {
... code for the if branch ...
} else {
... code for the else branch ...
}
The function asks you to return the maximum value
between first
and second
. As in Python, the
keyword return
stops the execution of a function and
returns the value of the expression written after return
(e.g., return 1.0
returns the value 1.0
,
return first
returns the value contained in the variables
first
).
2. Read two numbers and print the maximum
Implement the function:
void max_io(std::ostream &out, std::istream &in) {
// IMPLEMENT YOUR CODE HERE
}
that reads two floating point numbers (of type double
)
from the user and print the maximum of the two.
To read an input from the user you will need to use the input stream
in
and the extraction operator >>
as
follows:
double number;
>> number; in
Note how in C++
you have to declare the variable
number
with its type double
before being able
to use it. The code above reads a number from the input in
and stores it in the variable number
. Don’t worry about
understanding what is in
in detail: while ususally is the
input from the user (e.g., the user typing on a keyword), it can also be
provided programmaticaly (e.g., when reading a file). The automatic
tester will produce the two numbers to be read as input for you. Also,
in the slides you saw std::cin
and std::cout
are the standard instances of input and output streams (the keyboard
input and the output on the screen). Here, just use the variables
in
and out
declared in the function.
To output the number you will use the output stream out
.
Recall that you can print using the <<
operator (this
syntax will become clearer later in the following lectures). The
operator <<
is the insertion operator and it inserts
a number into an output stream. For example:
<< number; out
outputs number
on the output stream out
.
You will see this output on the screen, but in general the output stream
could be a file or a network socket. You can append multiple outputs in
a single statement as
cout << "My number is: " << number;
.
IMPORTANT: We expect you to output the string ‘The maximum number is:’ followed the maximum number (please pay attention to use exactly that string, strings like “the maximum number is:” will be considered differently because the automatic grader is case sensitive). The automatic grader will report an error if you do not output the string ‘The maximum number is:’.
You will see the following output running the automatic grader for
max_io
(this is the output with an empty
implementation):
--------------------------------------------------------------------------------
START TEST - max_io
[FAILURE] max_io called with inputs: 0.0 1.0
We did not find this string in the output: "The maximum number is:1"
Your implementation returned the following (wrong) output:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
...
You can interpret the above output as follows:
the
max_io
has been executed providing as input two numbers,0.0
and1.0
(i.e., note that you always have to read two numbers in your implementation!).The automatic grader expects your implementation to output “The maximum number is: 1.0:”. However, your program provided no output (the content shown between the two horizontal lines).
A correct implementation would look like this:
[SUCCESS] max_io called with inputs: 0.0 1.0
Correctly found this string in the output: "The maximum number is:1"
Note that the return value of the function is void
. In
this context, void
tells that the function does not return
a value (so you don’t need to write return value;
).
Also, ignore the &
symbol used in the parameter
declaration of the function (e.g., std::ostream &out
).
You’ll learn what that symbol later in the course.
3. Read and print 5 numbers
Implement the function:
void read_doubles(std::ostream &out, std::istream &in) {
// IMPLEMENT YOUR CODE HERE
}
that reads a 5 numbers, stores them, and prints them back. To store
the numbers you need to declare an array variable of
type double
and of size 5:
double numbers[5];
Recall that you can access the element of the array by index (e.g.,
numbers[0]
accesses the first element of the array,
numbers[4]
accesses the last element of the array).
Here you will also need a loop to read all the numbers. For example, the following loop iterates for 5 times (look back at the slides to see how the different loop statements work):
for (int i = 0; i < 5; i++) {
std::cout << "Loop iteration " << i << std::endl;
}
IMPORTANT: We expect you to output the list of numbers you read as input.
For example, if you input the numbers
0.0 1.0 2.0 3.0 4.0
, the output will be
0 1 2 3 4
. The automatic grader would report something like
this:
[SUCCESS] read_doubles called with inputs: 0.0 1.0 2.0 3.0 4.0
Correctly found this string in the output: "0 1 2 3 4"
4. Simulates the projectile trajectory
Implement the function:
double simulate_projectile(const double magnitude,
const double angle,
const double simulation_interval) {
double PI = 3.14159265; // use these variables for PI and g
double g = 9.8;
// IMPLEMENT YOUR CODE HERE
return -1.0;
}
that simulates the motion of a projectile in 2 dimensions. Your projectile is always shot from the origin position (the point with coordinates \(x=0\) and \(y=0\)) with an initial velocity took as input. The input to the function are the components of the velocity vector, that is:
- a
magnitude
\(v\) (the velocity in m/s), - an
angle
\(\theta\) (in degrees, it must be greater or equal to 0 degrees and less or equal to 90 degrees),
and the sampling time of the simulation ‘simulation_interval’ (in seconds).
The function simulates the trajectory of the projectile every
simulation_interval
seconds until it hits the ground
(coordinate \(y = 0\)) and returns the
last computed value for the coordinate x
before hitting the ground (\(y =
0\)).
To solve your problem, you’ll need to compute the coordinates of the projectiles \(x\) and \(y\) given a time \(t\) (i.e., the coordinate of the projectile \(t\) seconds after the shooting). The equations you will need to use are:
\(x(t) = v_x t\)
\(y(t) = v_y t - 0.5 g t^2\)
where \(g = 9.81\) is the
gravitational constant, \(v_x\) is the
component of the velocity vector on the \(x\) axes, and \(v_y\) is the component of the velocity
vector on the \(y\) axes (use
the variable g
that we already defined in the function to
get our same numerical results).
To compute the components \(v_x\)
and \(v_y\) you will need to compute
the cosine and sine of \(\theta\). The
library math.h
declares the functions sin
and cos
,
which compute the sine and cosine of an angle expressed in
radians. For example:
cos(30 * (3.14159265 / 180))
computes the cosine of the 30
degrees angle (you can
convert from degrees to radians multiplying the angle by
(3.14159265 / 180)
. Use the variable PI
already declared in the function). We already added the include
directive #include 'math.h'
at the top of the
td1.cpp
file: this directive tells the compiler (or better,
the preprocessor) to include the functions defined in
math.h
(try to remove the directive and see what
happens).
WARNING: since you simulate the trajectory in time-steps, you will rarely compute a point where \(y = 0\) (also because of numerical inaccuracies). So, in your function:
Keep computing new points in the trajectory if \(y \ge 0\)
Returns the last value of \(x\) when the projectile was above ground (depending on the loop that you write, that value may have been the previous value of \(x\) you computed).
5. Minimum distance from a target:
Implement the function:
double compute_min_distance(const double magnitude,
const double angle,
const double simulation_interval,
const double x_target,
const double y_target) {
// IMPLEMENT YOUR CODE HERE
return -1.0;
}
that simulates the projectile trajectory, as you did in the previous exercise, and that computes the minimum distance of the projectile from the target, during the whole projectile’s trajectory.
The function takes as input the initial velocity of the projectile
(magnitude and angle) and the simulation interval (as before).
Additionally, the function takes as input the coordinate of the target
(x_target
, y_target
). The function must return
the minimum distance.
Computing the distance of the projectile from the target. Suppose that \(x\) and \(y\) are the current position of the projectile, and \(x_t\) and \(y_t\) are the position of the target. The distance between the projectile and the target is:
\[ \sqrt{ (x - x_t)^2 + (y-y_t)^2 } \]
6. Multiple projectiles
Implement the function
double simulate_multiple_projectiles(const double proj_magnitude[],
const double proj_angle[],
const int total_projectile,
const double simulation_interval,
const double x_target,
const double y_target) {
// IMPLEMENT YOUR CODE HERE
return -1.0;
}
that computes the minimum distance between multiple projectiles and a target.
The function takes as input an array of velocities
(proj_magnitude
), an array of angles
(proj_angle
), the number of elements in each array
(total_projectile
), a simulation interval and the
coordinates of the target. You can also assume that
total_projectile
is greater than 0
.
You can interpret an element of the arrays as the initial velocity
(e.g., proj_magnitude[0]
and proj_angle[0]
are
the initial velocity and angle of of a projectile).
The function computes the trajectory of each projectile and computes the minimum distance between all the projectiles and the target, returning it as value from the function.
HINT: can call the function
compute_min_distance
you implemented in the previous
exercise on each projectile (for now, you can use your function “as in
Python” — there will be more to it next week).
7. Shooting game
Now we should have all the ingredients to program the shooting game.
Implement your game in the:
void play_game(std::ostream &out, std::istream &in) {
double simulation_interval = 0.05;
// IMPLEMENT YOUR CODE HERE
// WARNING -- remember to output
// "You hit the target" if a projectile hit target
// "You did not hit the target" if it didn't
}
function.
The game will read from the user (in this order!):
- the coordinate \(x\) for the target;
- the coordinate \(y\) for the target; and
- the magnitude and the angle for each one of the 5 projectile (i.e., the magnitude for the first projectile, the angle for the first projectile, the magnitude for the second projectile, …).
You will use a simulation interval of 0.05 (please use the variable
simulation_interval
already defined in the function) to
compute the trajectories of each projectile.
The function will compute the minimum distance between a projectile and the target (sounds familiar?). A projectile hits the target if the minimum distance is less than or equal to 1.
The game will output the string
“You hit the target”: if at least a projectile hit the target.
“You did not hit the target”: otherwise.
PLAYING THE GAME:
You can play the game yourself instead of running the automatic
grader. The execution of all C++
programs starts from the
int main
function. The main
function in the
main.cpp
file executes bt default the automatic grader. You
can change this file to execute the play_game
function
instead:
Open the file
main.cpp
.Change the preprocessor declaration
#define GRADING 1
to#define GRADING 0
and saves the file.
If you run the program now you will run the game, instead of the automatic grader.
The preprocessor
runs before the compilation of your program and process all the
“directives” in the file, which start with a hashtag symbol
#
(e.g., #include
, #define
). You
can read more information about the preprocessor if you want to, e.g.,
here.
Using the preprocessor could be helpful for the class project.