2. Run-Time Bugs The following program is an upgrade to the Week 3 snowball figh
ID: 3809142 • Letter: 2
Question
2. Run-Time Bugs
The following program is an upgrade to the Week 3 snowball fight code. We’ve changed the movement algorithm and made the code easier to modify by using two functions. We’ve also changed what it reports. It has four lines of code that need to be changed but only two real bugs. You’ll understand when you find the bugs. The assignment is to find and fix the two bugs.
One bug is subtle but does exhibit improper behavior; you just need to be looking closely. Here’s a big hint. When a target is hit, it should no longer move or report hits or misses. The other bug is insidious. This is the kind of bug that gets shipped when you don’t thoroughly test your code. It has no outward signs of failure but affects the game significantly. We’re going to provide some guidance for this bug to help improve your code testing skills. Build the code and then follow these steps.
Set a breakpoint at line158, switch (ranNum). The quickest way is to left click to the left of the line number. If a red dot doesn’t appear, move the mouse a little farther left.
Now start debugging (either hit F5 or use the DEBUG -> Start Debugging menu).
Enter in the hit column and row data. You will get one or more target hit or miss reports, and then the program will stop at the breakpoint. (It is possible that the random number will be 4 and the breakpoint won’t be triggered for any of the targets in this turn. If that happens, just keep entering column and row data until the breakpoint is triggered.) You’ll see a yellow arrow in the red dot. The yellow arrow tells you where the program has stopped. Now look in the Locals window below your source code. (Note: The Locals window is configurable and can be placed anywhere or hidden. The default location is below the source code.) If the Locals window is hidden, try the Alt+4 key combination. The Locals window can also be accessed through the DEBUG->Windows->Locals menu. Left click the + to the left of Target. This should expand the target so you can see all the values, although you can also see the values in the Value column without clicking on the +. Note the value of Target.position (.x and .y).
Hit F10. This will cause the program to advance one line of code (single step). The yellow arrow will move and will be pointing at the next line of code to be executed. This should be the first line of one of the case statements.
Hit F10 again. If you’re lucky, you will be on a line of code that looks like Target.position. . .;. If not, hit F5, which will take you back to Step 3. Cycle through Steps 3, 4, and 5 until you are on a line of code like that shown above.
Hit F10 again and note the values of Target.positon. The text in the value line after Target should have turned red, and either the .x or .y value should have changed.
Hit F10 three more times and you should be back in the main code at the if (!T.hit) moveTarget(T); line of code. Look at the Locals window. Notice the variables being shown have changed. The local variables in the function are no longer available (they are out of scope), and we are looking at the local variables in Main. Look at the T.position values. Are they the same as the Target.position values? If not, then we haven’t really moved the Target. Can you figure out why? Remember our discussion of pass by value and pass by reference, especially for structs and std::arrays.
You might want to do a little research on the other windows, such as the Autos window and especially the Watch window, which can be very useful.
Here is the code.
// Week 5 Assignment-2
// Description: Snowball fight – version 2
//----------------------------------
//**begin #include files************
#include <iostream> // provides access to cin and cout
#include <array> // provides access to std::array
#include <time.h> // provides access to time() for srand()
//--end of #include files-----------
//----------------------------------
using namespace std;
//----------------------------------
//**begin global constants**********
// define coordinate structure
struct Coords
{
int x;
int y;
};
// define a struct of the target
struct MyStruct
{
int ID; // -- Identification number of the target
Coords position; // -- position of target
int dist; // -- distance between target and snowball hit
bool hit; // -- flag indicating target has been hit
};
const int gridSize = 5; // const grid size (i.e. 5x5 grid constant is 5)
const int turns = 20; // const number of turns
const int targetCount = 3; // number of targets
//--end of global constants---------
//----------------------------------
//**begin function prototypes*******
int throwSnowball(Coords p, MyStruct Target);
void moveTarget( MyStruct Target);
//--end of function prototypes------
//----------------------------------
//**begin main program**************
int main()
{
// initialization
srand(time(NULL));
bool allHit = false;
int hitCount = 0; // number of hits.
int dist = 0; // distance of miss
Coords snowballPos; // position of snowball hit
array <MyStruct, targetCount> Targets;
// Initialize targets
int idNum = 0;
for (auto &T: Targets)
{
T.ID = idNum++; // set identification number
// set target at random location
T.position.x = rand()%gridSize;
T.position.y = rand()%gridSize;
T.hit = false; // set target hit flag to default: false
}
// loop for the specified number of turns
for (int i = 0; i < turns; i++)
{
// get x and y position for the snowball from player
cout << "column? ";
cin >> snowballPos.x;
cout << "row? ";
cin >> snowballPos.y;
// throw snow ball (see instructions for details)
for(auto &T: Targets)
{
if (!T.hit)
{
// check for hit or miss
dist = throwSnowball(snowballPos, T);
// report results
switch (dist)
{
case 0:
cout << "***SPLAT*** You hit target " << T.ID << "!" << endl;
hitCount++;
break;
case 1:
cout << "target " << T.ID << ": Way too close!" << endl;
break;
case 2:
cout << "target " << T.ID << ": I heard it hit." << endl;
break;
default:
cout << "target " << T.ID << ": Missed by a mile." << endl;
break;
}
// target moves (see instruction for details
if (!T.hit) moveTarget(T);
}
}
if (hitCount == 3)
{
allHit = true;
break;
}
cout << "---Next Turn---" << endl;
}
// end of loop
// report score (number of hits vs turns)
if (allHit) cout << "All targets have been hit! Great job!" << endl;
else cout << "You had " << hitCount << " hits out of " << turns << " throws." << endl;
cin.get();
// Wait for user input to close program when debugging.
cin.get();
return 0;
}
//--end of main program-------------
//----------------------------------
//**begin function definitions******
// Determine hit or distance
int throwSnowball(Coords p, MyStruct Target)
{
int aDistance;
// compare to the target's position
if ( p.x == Target.position.x)
{
if (p.y == Target.position.y)
{
Target.hit = true;
return 0;
}
else
{
return abs(p.y - Target.position.y);
}
}
else
{
aDistance = abs(p.x -Target.position.x);
if (aDistance < abs(p.y - Target.position.y)) aDistance = abs(p.y -Target.position.y);
return aDistance;
}
}
// Move the target
void moveTarget( MyStruct Target)
{
enum MyEnum
{
North, East, South, West, Stay
};
bool moveNotFound = true;
MyEnum ranNum = MyEnum(rand()%5);
if (ranNum == Stay) return;
while (moveNotFound)
{
switch (ranNum)
{
case North:
if (Target.position.y == 0) break; // can't move North
Target.position.y--;
cout << Target.ID << " moving North." << endl;
return;
case East:
if (Target.position.x == gridSize-1) break; // can't move East
Target.position.x++;
cout << Target.ID << " moving East." << endl;
return;
case South:
if (Target.position.y == gridSize -1) break; // can't move South
Target.position.y++;
cout << Target.ID << " moving South." << endl;
return;
case West:
if (Target.position.x == 0) break; // can't move West
Target.position.x--;
cout << Target.ID << " moving West." << endl;
return;
default:
break;
}
ranNum = MyEnum(int(ranNum+1)%4);
}
}
//--end of function definitions------
//-----------------------------------
Explanation / Answer
Hey, your code doesn't work because you are changing the value of local object in the function moveTarget( MyStruct Target) and throwSnowball(Coords p, MyStruct Target). We must change the value of the pointer of the object which it is referece to using operator ->. Below is fully working code. (changes highlighted)
#include <iostream> // provides access to cin and cout
#include <array> // provides access to std::array
#include <time.h> // provides access to time() for srand()
//--end of #include files-----------
//----------------------------------
using namespace std;
//----------------------------------
//**begin global constants**********
// define coordinate structure
struct Coords
{
int x;
int y;
};
// define a struct of the target
struct MyStruct
{
int ID; // -- Identification number of the target
Coords position; // -- position of target
int dist; // -- distance between target and snowball hit
bool hit; // -- flag indicating target has been hit
};
const int gridSize = 5; // const grid size (i.e. 5x5 grid constant is 5)
const int turns = 20; // const number of turns
const int targetCount = 3; // number of targets
//--end of global constants---------
//----------------------------------
//**begin function prototypes*******
int throwSnowball(Coords p);
void moveTarget( MyStruct Target);
//--end of function prototypes------
//----------------------------------
//**begin main program**************
int main()
{
// initialization
srand(time(NULL));
bool allHit = false;
int hitCount = 0; // number of hits.
int dist = 0; // distance of miss
Coords snowballPos; // position of snowball hit
array <MyStruct, targetCount> Targets;
// Initialize targets
int idNum = 0;
for (auto &T: Targets)
{
T.ID = idNum++; // set identification number
// set target at random location
T.position.x = rand()%gridSize;
T.position.y = rand()%gridSize;
T.hit = false; // set target hit flag to default: false
}
// loop for the specified number of turns
for (int i = 0; i < turns; i++)
{
// get x and y position for the snowball from player
cout << "column? ";
cin >> snowballPos.x;
cout << "row? ";
cin >> snowballPos.y;
// throw snow ball (see instructions for details)
for(auto &T: Targets)
{
if (!T.hit)
{
// check for hit or miss
dist = throwSnowball(snowballPos);
// report results
switch (dist)
{
case 0:
cout << "***SPLAT*** You hit target " << T.ID << "!" << endl;
T.hit = true;
hitCount++;
break;
case 1:
cout << "target " << T.ID << ": Way too close!" << endl;
break;
case 2:
cout << "target " << T.ID << ": I heard it hit." << endl;
break;
default:
cout << "target " << T.ID << ": Missed by a mile." << endl;
break;
}
// target moves (see instruction for details
if (!T.hit) moveTarget(T);
}
}
if (hitCount == 3)
{
allHit = true;
break;
}
cout << "---Next Turn---" << endl;
}
// end of loop
// report score (number of hits vs turns)
if (allHit) cout << "All targets have been hit! Great job!" << endl;
else cout << "You had " << hitCount << " hits out of " << turns << " throws." << endl;
cin.get();
// Wait for user input to close program when debugging.
cin.get();
return 0;
}
//--end of main program-------------
//----------------------------------
//**begin function definitions******
// Determine hit or distance
int throwSnowball(Coords p)
{
int aDistance = abs(p.x -Target.position.x);
if (aDistance < abs(p.y - Target.position.y)) aDistance = abs(p.y -Target.position.y);
return aDistance;
}
}
// Move the target
void moveTarget( MyStruct target)
{
MyStruct *Target = ⌖
enum MyEnum
{
North, East, South, West, Stay
};
bool moveNotFound = true;
MyEnum ranNum = MyEnum(rand()%5);
if (ranNum == Stay) return;
while (moveNotFound)
{
switch (ranNum)
{
case North:
if (Target->position.y == 0) break; // can't move North
Target->position.y--;
cout << Target->ID << " moving North." << endl;
return;
case East:
if (Target->position.x == gridSize-1) break; // can't move East
Target->position.x++;
cout << Target->ID << " moving East." << endl;
return;
case South:
if (Target->position.y == gridSize -1) break; // can't move South
Target->position.y++;
cout << Target->ID << " moving South." << endl;
return;
case West:
if (Target->position.x == 0) break; // can't move West
Target->position.x--;
cout << Target->ID << " moving West." << endl;
return;
default:
break;
}
ranNum = MyEnum(int(ranNum+1)%4);
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.