Problems creating Stack! (arcade game) in C++ - c++

im a beginner amateur in C++ and i recently had the idea to remake the popular arcade game Stack! in the C++ console.
The problem occours when the player has got to place the pad:
the pad places well, but if you make an error it doesn't resize properly (you'll understand better when you'll run the code).
Don't care about the graphic that sometimes bugs, because i can fix that on my own.
Please help me!
Here is the code:
#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <windows.h>
#include <string>
using namespace std;
bool bDirection = true; /* Bool for the direction:
true = dx, false = sx */
string sPad;
int nPadLenght = 6;
int x = 40, y =21; // Referement tile's position
int nSpeed = 200;
bool loop = true; // main loop
int nScore = 0; // score
int nPlaceX = 40;
int nTileX = 35, nTileY = 20; // Player's actual postition
int nEndTileX, nEndTileY;
void RenderLine(int *x, int *y);
int main();
// Void for the coordinates
void gotoxy (int x, int y){
COORD coord;
coord.X = x ;
coord.Y = y ;
SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void Victory(){
x = 10;
y = 4;
Beep(698.5, 300);
Beep(698.5, 100);
Beep(1047, 500);
system("color a");
gotoxy(x,y); cout << "You win!\n\n Score = " << nScore;
system("pause >nul");
}
void PadLenght(int *x){
// Each number is equal to a possible pad lenght
switch (*x){
case 6:
sPad = "[][][]";
nEndTileX = nTileX + 5;
break;
case 5:
sPad = "[][]]";
nEndTileX = nTileX + 4;
break;
case 4:
sPad = "[][]";
nEndTileX = nTileX + 3;
break;
case 3:
sPad = "[][";
nEndTileX = nTileX + 2;
break;
case 2:
sPad = "[]";
nEndTileX = nTileX + 1;
break;
case 1:
sPad = "[";
nEndTileX = nTileX;
break;
}
}
void SwitchDirection(bool *x){
// Switches the bool of the direction
switch (*x){
case true:
*x = false;
break;
case false:
*x = true;
break;
}
}
void Speed(){
// For each line from 500ms to 20ms speed increments of 10ms
if (nSpeed > 20)
nSpeed -= 20;
}
// void for placing the pad
void Place() {
int i = nPlaceX - nTileX;
if (i < 0)
i * -1;
nPadLenght -= i;
}
void collision(){
// Collisions with the border
if (nTileX > 45 || nTileX < 35)
SwitchDirection(&bDirection);
}
void movement(){
int nLastX = nTileX;
// Place the pad if pressing down arrow
if(GetKeyState(VK_DOWN) & 0x8000){
nTileY--;
Place();
Speed();
Beep(698.5, 50);
Beep(880.0, 50);
Beep(1047, 50);
nScore += 10;
Sleep(60);
}
// Movement of the pad
switch (bDirection){
case true:
gotoxy (nLastX, nTileY); cout << " ";
nTileX++;
break;
case false:
gotoxy (nLastX - nPadLenght, nTileY); cout << " ";
nTileX--;
break;
}
}
int main(){
system("color 0");
while (loop = true){
char a = '"';
gotoxy(x,y); cout << a << a << a << a << a << a;
collision();
PadLenght(&nPadLenght);
movement();
gotoxy (nTileX, nTileY); cout << sPad;
Sleep (nSpeed);
if (nScore > 160) {
Victory();
break;
}
}
return 0;
}

Here are some issues I found:
"using namespace std;"
This is bad. This brings in all of the identifier names from the std namespace. The preference is to use the std prefix (e.g. std::cout) or choose from the std namespace, (e.g. using std::cout;).
Global variables
Prefer to not have global variables. Create them in main and pass them to functions.
For example, you have global x and y, and you use x and y as parameters in functions. This may lead to confusion between you, readers and the compilers, as to which variables you are referring to.
Passing by pointer
Prefer not to use pointers.
Pass by value (without pointers) for variables that can fit into a processor's register, like float, double, int, bool and char.
For classes and structures, pass by reference. If you are not modifying the parameter, pass by constant reference.
Don't create functions for simple content
Functions require an overhead to execute, usually at least 3 instructions (save parameters, branch to function, return from function). Some operations can be performed with less statements:
// Switch directions:
direction = ! direction;
If you must use functions, give the compiler the hint that you want them inline. This means that the compiler will paste the content of the function where the function call is made. Some compilers may do this for optimizations, but you have to tell the compiler to optimize.
Boolean switch statements
Switch statements are kind of overkill for Boolean varibles, since there are only 2 outcomes. Common coding guidelines are to use if and else.
'=' in conditional expressions
Remember, one = for assignment, two for comparison.
The language allows for an assignment in a comparison, but most likely, you were not thinking of assignment, but testing for equality.
Declare variables closest to usage
Make life easier on you, the compiler and reader, by declaring variables closest to where they are used. For example, in main, there is a loop variable. As a reader, I have to scroll to the top of your source to find the definition, when a better idea is to declare it in the main function, where it is used.
One variable declaration per line
A common coding guideline is one variable per line. Multiple lines have a negligible effect on the build time. However, this makes modifications easier. And when declaring pointers, reduces injected defects. Let your compiler optimize the code, your task should be write clear (easily readable) and concise code.
Increase the compiler's warning level
Force your compiler to turn on the warning level to its highest level.
Resolve all warnings.
A clean compilation has zero errors and zero warnings.
With compiler warnings at full, you would have noticed some of the issues I have identified.

Related

how to replace a value of a variable inside code from user input?

i am trying to add a developer mode in my program. since duty of car defers every month,i want give my user permission to change every single variables in my program alike duty lccost yen2taka freight
#include <iostream>
using namespace std;
class A
{
public:
int carbid,duty;
void Input()
{
cout<<"please insert the car price you want to bid for(in yen): ";
cin>>carbid;
cout<<"duty of the car: ";
cin>>duty;
}
int Exportcost()
{
int exportcost;
int servicechrg=10;
int freight=20;
exportcost=servicechrg+freight+carbid;
return exportcost;
}
int Yen2taka()
{
int yen2taka;
int taka2dollarrate=10;
int dollar2yen=1;
yen2taka=((Exportcost())/dollar2yen)*taka2dollarrate;
return yen2taka;
}
int Importcost()
{
int importcost;
int lccost=10;
int cnfcost=20;
importcost=lccost+cnfcost;
return importcost;
}
int Totalcosting()
{
int total;
int myprofit=10; //80000
total=myprofit+Importcost()+Yen2taka();
cout<<total;
return total;
}
void summary()
{
cout<<
}
};
int main()
{
x:
A ob;
ob.Input();
ob.Exportcost();
ob.Yen2taka();
ob.Importcost();
ob.Totalcosting();
int ch;
cout<<"press 1 to see the summery of the costing or 2 to restart costing again"<<endl;
cin>>ch;
switch(ch)
{
case 1:
ob.summary();
break;
case 2:
goto x;
}
}
At first, you should collect these parameters in a separate class:
class Configuration // maybe you find a better name...
{
int m_servicechrg = 10; // default
int m_freight = 20;
// ...
public:
int servicechrg() { return m_servicechrg; }
void servicechrg(int value); { /* check some limits? */ m_servicechrg = value; }
int freight() { return m_freight; }
void freight(int value); { /* check some limits? */ m_freight = value; }
// ...
};
// will allow you to do:
// C c; std::cout << c;
ostream& operator<<(ostream& s, Configuration const& c)
{
// which ever formatting is appropriate...
s << c.servicechrg() << ' ' << c.freight();
return s;
}
The setters could alternatively return bool to indicate invalid values.
Now you can use this class within main:
Configuration c;
A a;
int cost = a.exportCost(c); // you'd have to adjust signatures...
int value;
switch(ch)
{
case 4:
if(stc::cin >> freight) // catches invalid user input!
// one ALWAYS should do, otherwise you might end up in
// your program not working any more
{
c.freight(value);
// or, if you have:
if(!c.freight(value))
{
// some appropriate error message
// (it's better not to output in the setter, you are more flexible this
// way – maybe you want different messages at different occasions?)
}
}
else
{
// appropriate error handling
}
break;
default:
// handling invalid user input
// again, you always should; but stream state is not in error state,
// so you just can print appropriate error message
break;
}
See this answer for how to correctly handle stream errors.
If you wonder about the differences in error handling: First case is met if user enters non-numerical input, such as ss, second case, if input is numerical, but out of valid range (77).
Now if you don't want to pass the configuration as parameter all the time, you could make a global variable from (but careful, there are some dangers with global variables, use them as sparely as possible) or implement the singleton pattern.
Side notes: goto can be a fine tool sometimes, but it is a dangerous one (and the label's name x isn't a good one, prefer a name that clearly shows intention, such as REENTRY_POINT, LOOP_START, ...). If you can get along without unreasonable effort, prefer such variants:
bool isRunning = true;
do
{
// ...
case 2:
isRunning = false;
break;
}
while(isRunning);
Sure, an additional variable, an additional check; unfortunately, you cannot use break to exit a (pseudo-) endless loop (for(;;)) (but don't apply this pattern for nested loops, then it gets more and more unreadabla – and ineffcient: bool isExit = false; for(int i = 0; !isExit && i < n; ++i) { for(j = 0; j < n; ++j) { isExit = true; break; } } – see what I mean?). A variant might be:
for(;;)
{
switch(ch)
case 1:
// ...
//break; <- replace
continue;
case 2:
//
break;
} // end of switch
break; // break the surrounding for(;;) loop
}
But that's not really nice either.
A pretty nice variant allowing to exit the loop in the given case, as there isn't anyhting to do afterwards:
for(;;)
{
switch(ch)
{
case 2:
// maybe yet some cleaning up here
return 0;
default:
// ...
break;
}
}
Drawback: The function's exit point possibly is deeply nested inside the code.
There are yet other tricks to allow this pattern, like packing sub-sections of code in a lambda having a return inside and call that one directly. But that now really starts going beyond the scope...
Finally, if you insist on goto, my variant would rather be:
for(;;)
{
switch(ch)
{
case 2:
// ...
goto LOOP_EXIT;
default:
// ...
break;
}
}
LOOP_EXIT:
return 0; // e. g. main
(void)0; // if there isn't anything to do in the function any more
// (labels require an instruction afterwards!)
There won't be a hidden loop now and it is more obvious what you actually are doing. Currently, not really an issue, but if your code grows, the hidden loop gets more and more difficult to spot.
In such cases, I clearly mark the gotos so that another coder can immediately spot the critical code points:
///////////////////////////////////////////////////
// possibly some comment why applying this pattern
goto SOME_LABEL;
///////////////////////////////////////////////////
One could do the same with deeply nested function exit points (return).

Make compiler assume that all cases are handled in switch without default

Let's start with some code. This is an extremely simplified version of my program.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
The program compiles with a warning:
./test.cpp: In function ‘void updateColor(uint8_t)’:
./test.cpp:20:25: warning: ‘colorData’ may be used uninitialized in this function [-Wmaybe-uninitialized]
dummyColorRecepient = colorData;
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2. However, the compiler doesn't know that and it assumes that switch may not initialize colorData. (Any amount of static analysis during compilation won't help here because the real program is spread over multiple files.)
Of course I could just add a default statement, like default: colorData = 0; but this adds additional 24 bytes to the program. This is a program for a microcontroller and I have very strict limits for its size.
I would like to inform the compiler that this switch is guaranteed to cover all possible values of iteration.
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2.
From the perspective of the toolchain, this is not true. You can call this function from someplace else, even from another translation unit. The only place that your constraint is enforced is in main, and even there it's done in a such a way that might be difficult for the compiler to reason about.
For our purposes, though, let's take as read that you're not going to link any other translation units, and that we want to tell the toolchain about that. Well, fortunately, we can!
If you don't mind being unportable, then there's GCC's __builtin_unreachable built-in to inform it that the default case is not expected to be reached, and should be considered unreachable. My GCC is smart enough to know that this means colorData is never going to be left uninitialised unless all bets are off anyway.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
// Comment out this default case to get the warnings back!
default:
__builtin_unreachable();
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
(live demo)
This won't add an actual default branch, because there's no "code" inside it. In fact, when I plugged this into Godbolt using x86_64 GCC with -O2, the program was smaller with this addition than without it — logically, you've just added a major optimisation hint.
There's actually a proposal to make this a standard attribute in C++ so it could be an even more attractive solution in the future.
Use the "immediately invoked lambda expression" idiom and an assert:
void updateColor(const uint8_t iteration)
{
const auto colorData = [&]() -> uint16_t
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}();
dummyColorRecepient = colorData;
}
The lambda expression allows you to mark colorData as const. const variables must always be initialized.
The combination of assert + return statements allows you to avoid warnings and handle all possible cases.
assert doesn't get compiled in release mode, preventing overhead.
You can also factor out the function:
uint16_t getColorData(const uint8_t iteration)
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}
void updateColor(const uint8_t iteration)
{
const uint16_t colorData = getColorData(iteration);
dummyColorRecepient = colorData;
}
You can get this to compile without warnings simply by adding a default label to one of the cases:
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2: default:
colorData = 345;
break;
}
Alternatively:
uint16_t colorData = 345;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
}
Try both, and use the shorter of the two.
I know there have been some good solutions, but alternatively If your values are going to be known at compile time, instead of a switch statement you can use constexpr with a static function template and a couple of enumerators; it would look something like this within a single class:
#include <iostream>
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
template<const uint8_t Iter>
static constexpr uint16_t updateColor() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
int main() {
const uint16_t colorRecipient0 = ColorInfo::updateColor<ColorInfo::CR_0>();
const uint16_t colorRecipient1 = ColorInfo::updateColor<ColorInfo::CR_1>();
const uint16_t colorRecipient2 = ColorInfo::updateColor<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << colorRecipient0 << '\n'
<< "Recipient1: " << colorRecipient1 << '\n'
<< "Recipient2: " << colorRecipient2 << '\n';
return 0;
}
The cout statements within the if constexpr are only added for testing purposes, but this should illustrate another possible way to do this without having to use a switch statement provided your values will be known at compile time. If these values are generated at runtime I'm not completely sure if there is a way to use constexpr to achieve this type of code structure, but if there is I'd appreciate it if someone else with a little more experience could elaborate on how this could be done with constexpr using runtime values. However, this code is very readable as there are no magic numbers and the code is quite expressive.
-Update-
After reading more about constexpr it has come to my attention that they can be used to generate compile time constants. I also learned that they can not generate runtime constants but they can be used within a runtime function. We can take the above class structure and use it within a runtime function as such by adding this static function to the class:
static uint16_t colorUpdater(const uint8_t input) {
// Don't forget to offset input due to std::cin with ASCII value.
if ( (input - '0') == CR_0)
return updateColor<CR_0>();
if ( (input - '0') == CR_1)
return updateColor<CR_1>();
if ( (input - '0') == CR_2)
return updateColor<CR_2>();
return updateColor<CR_2>(); // Return the default type
}
However I want to change the naming conventions of the two functions. The first function I will name colorUpdater() and this new function that I just shown above I will name it updateColor() as it seems more intuitive this way. So the updated class will now look like this:
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
static uint16_t updateColor(uint8_t input) {
if ( (input - '0') == CR_0 ) {
return colorUpdater<CR_0>();
}
if ( (input - '0') == CR_1 ) {
return colorUpdater<CR_1>();
}
if ( (input - '0') == CR_2 ) {
return colorUpdater<CR_2>();
}
return colorUpdater<CR_0>(); // Return the default type
}
template<const uint8_t Iter>
static constexpr uint16_t colorUpdater() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
If you want to use this with compile time constants only you can use it just as before but with the function's updated name.
#include <iostream>
int main() {
auto output0 = ColorInfo::colorUpdater<ColorInfo::CR_0>();
auto output1 = ColorInfo::colorUpdater<ColorInfo::CR_1>();
auto output2 = ColorInfo::colorUpdater<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << output0 << '\n'
<< "Recipient1: " << output1 << '\n'
<< "Recipient2: " << output2 << '\n';
return 0;
}
And if you want to use this mechanism with runtime values you can simply do the following:
int main() {
uint8_t input;
std::cout << "Please enter input value [0,2]\n";
std::cin >> input;
auto output = ColorInfo::updateColor(input);
std::cout << "Output: " << output << '\n';
return 0;
}
And this will work with runtime values.
Well, if you are sure you won't have to handle other possible values, you can just use arithmetic. Gets rid of he branching and the load.
void updateColor(const uint8_t iteration)
{
dummyColorRecepient = 123 + 111 * iteration;
}
I'm going to extend the Lightness Races in Orbit's answer.
The code I'm using currently is:
#ifdef __GNUC__
__builtin_unreachable();
#else
__assume(false);
#endif
__builtin_unreachable() works in GCC and Clang but not MSVC. I used __GNUC__ to check whether it is one of the first two (or another compatible compiler) and used __assume(false) for MSVC instead.

constructors / Lab 9 Problems [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
My professor wants us to create a gladiator simulation where we name 5 gladiators, then create their stats, create the boss stats, then allow for the gladiators to fight the boss. During the fight, the health of everyone and randomly generated number damage dealt will be displayed until a winner is decided and from there, we will prompt the user if they would want a rematch.
Currently, I am stuck on figuring out what is and how do I use a constructor. Overall, I am lost with the project in total, but for now I want to understand this step by step. Inside the BossFight.h, consists of the prototype functions.
class BossFight {
private:
//Holds the party of gladiators that is banded together to fight the boss
Gladiator party[PSIZE];
//Holds the powerful boss that the party is fighting
Gladiator boss;
//Variables used for record keeping
int turnNum, fightsStarted, fightsWon;
//Will fill the party with gladiators, this function can call/reuse the createGladiator function.
void getParty();
//Will generate a boss for the party to fight. Has no crit or evasion, but 3* damage min and range, and 6* health
void getBoss();
//Tells the user who won, after how many turns, and the current record for the session
void displayFightResults(bool partyWon);
//One turn occurs, where each party member attacks the boss, then the boss attacks the party.
//Returned value indicates status of fight (continue, party win, party loss)
//Boss will randomly choose between attacking a single (randomly chosen) party member for full damage, or
//attacking the full party for half damage.
int takeTurn();
//Handles dealing damage to the entire party
void bossAttacksArea();
public:
//Responsible for generating the party and the boss, should initialize the other
//private variables as well
BossFight();
//User calls this when they want to run a fight. It will ask them if they want to use
//the same party, or get a new one.
void runFight();
};
What I have done so far is
#include <iostream>
#include <string>
#include "BossFight.h"
#include <stdlib.h>
#include <time.h> // Allows seed to generate new random numbers every time.
using namespace std;
const int SIZE = 5; //Party Size
Gladiator createGladiator(string name) // Data type Gladiator with its data named createGladiator
{
Gladiator stats; // Structure tag
for (int i = 0; i < SIZE; i++)
{
int maxHealth, evasion, critical;
stats.name = name;
// set max health
switch (rand() % 3) // % 3 means the range. So the starting number is 0 and final number is 2. Used to find a random number between the range 0-2.
// Uses that random number to open up one of the cases.
{
case 0: stats.maxHealth = 150;
break;
case 1: stats.maxHealth = 200;
break;
case 2: stats.maxHealth = 250;
break;
}
// set evasion
int numE = (rand() % 5); // Used to find a random number between the range 0-4.
switch (numE) // Uses that random number to open up one of the cases.
{
case 0: stats.evasion = 50;
break;
case 1: stats.evasion = 75;
break;
case 2: stats.evasion = 100;
break;
case 3: stats.evasion = 125;
break;
case 4: stats.evasion = 150;
break;
}
// Set Critical
int numC = (rand() % 5); // Used to find a random number between the range 0-4.
switch (numC) // // Uses that random number to open up one of the cases.
{
case 0: stats.critical = 50;
break;
case 1: stats.critical = 75;
break;
case 2: stats.critical = 100;
break;
case 3: stats.critical = 125;
break;
case 4: stats.critical = 150;
break;
}
// Set minDamage
int minimum, maximum;
minimum = 8;
maximum = 5;
int numMin = (minimum + rand() % (maximum + minimum)); // Used to find a random number between the minimum and maximum values.
stats.dmgMin = numMin;
// set DamageRange
int maxMin, maxMax;
maxMin = 16;
maxMax = 5;
int numMax = (maxMin + rand() % (maxMax - maxMin)); // Used to find a random number between the minimum and maximum values.
stats.dmgRange = numMax;
return stats; //Return all of the stats into the structure tag.
}
}
BossFight::BossFight() ***< -- stuck right here ***
{
getParty();
}
void BossFight::getBoss()
{
getBoss();
}
void getParty(string name[])
{
{
cout << "To begin with, enter 5 gladiator's name" << endl; // First for loop asking user for array input.
for (int i = 0; i < SIZE; i++)
{
cin >> name[i];
}
for (int i = 0; i < SIZE; i++)
{
cout << "Gladiator " << i + 1 << " name is " << endl;
cout << name[i] << endl;
}
}
}
int main()
{
srand(time(NULL)); //initiate random number generator seed.
string name[SIZE];
cout << "Hello user" << endl;
BossFight();
system("PAUSE");
}
I would appreciate any type of help. Do remember that I am taking an intro to computer science class, so I may not understand complex coding yet. I have been doing fine so far interpreting how the code should work in english, but find it hard to interpret how it should be via code.
Also, I am getting an error
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "private: void __thiscall
BossFight::getParty(void)" (?getParty#BossFight##AAEXXZ) referenced in
function "public: __thiscall BossFight::BossFight(void)"
(??0BossFight##QAE#XZ) ConsoleApplication6 Severity Code Description Project File Line Suppression
State Error LNK2019 unresolved external symbol "private: void
__thiscall BossFight::getParty(void)" (?getParty#BossFight##AAEXXZ) referenced in function "public: __thiscall BossFight::BossFight(void)"
(??0BossFight##QAE#XZ) ConsoleApplication6 C:\Users\1\documents\visual
studio 2017\Projects\ConsoleApplication6\ConsoleApplication6\1.obj 1
And was wondering what even caused this? All i have in my visual studio is my header and cpp file.
This is called a linker error. What the error is saying is that BossFight::getParty() is being used by the BossFight::BossFight() constructor implementation, but you haven't provided an implementation of the getParty() method.
It looks like you were trying to add an implementation by declaring and implementing a getParty(std::string*) function, but this is not an implementation of the BossFight::getParty() method.
To implement BossFight::getParty(), you will need something like:
void BossFight::getParty() {
// implementation here
}
You will probably also want to hang on to the BossFight object that you construct by giving it a name:
BossFight boss_fight; // This declares *and* constructs a BossFight object on the stack.

Switch statement of ranges

Is there a way to write a switch statement in c++ where you deal with ranges.
case 0-10 do a,
case 20-40 do b,
case 40-80 do c,
etc.
I can write it out using a bunch of if else if statements but wondering if there is a more efficient way.
Actually, you can do this through preprocessor abuse in C (although perhaps not in C++, due to some errors with P99 in C++, which I am confident could be overcome with enough perseverance).
See the following example, using P99:
#include "p99.h"
#define P99_SWITCH_RANGE(from, to) P99_FOR(from, P99_MINUS(to, from), P99_SWITCH_RANGE_GLUE_HELPER, P99_SWITCH_RANGE_CASE_LABEL_MAKER_HELPER)
#define P99_SWITCH_RANGE_GLUE_HELPER(from, i, past, cur) past: cur
#define P99_SWITCH_RANGE_CASE_LABEL_MAKER_HELPER(from, x, i) case P99_ADD(from, i)
int main(int argc, const char *argv[]) {
int x;
scanf("%i", &x);
switch (x) {
P99_SWITCH_RANGE(20, 30):
{
puts("between 20 and 30");
}
default: {
puts("not between 20 and 30");
}
}
}
Note that this example is left inclusive, right exclusive. I'm confident you could modify the macros to make it any way you'd like, so this is a decent starting point at the very least.
I can write it out using a bunch of if else if statements but wondering if there is a more efficient way.
No. There's not a more efficient way. Not to mention that the switch statement is really not supposed to be used for ranges.
You could use a map mapping keys to standard functions:
#include <iostream>
#include <map>
#include <functional>
using namespace std;
int main()
{
std::map<int, std::function<void()>> dispatcher;
// case (-inf, 10]
dispatcher[10] = []() {cout << 10;};
// case (10, 50]
dispatcher[50] = []() {cout << 50;};
// case (50, 100]
dispatcher[100] = []() {cout << 100;};
(dispatcher.lower_bound(1)->second)();
(dispatcher.lower_bound(10)->second)();
(dispatcher.lower_bound(11)->second)();
(dispatcher.lower_bound(50)->second)();
(dispatcher.lower_bound(51)->second)();
return 0;
}
Outputs 10105050100
If you are concerned about efficiency, you could map the ranges to values and then switch for them:
int range_to_value(int x)
{
if (x > 0 && x < 10) return 0;
if (x > 20 && x < 40) return 1;
// ...
}
void switch_range(int x)
{
switch( range_to_value(x) )
{
case 0: cout << 0; break;
case 1: cout << 1; break;
}
}
switch_range(1); // output 0
switch_range(9); // output 0
switch_range(22); // output 1
Range mapping is probably inlined, but will be computed every time. Most efficient will be large switch, doesn't matter how you write it (by hand, generator, preprocessor) because it will end up as a large jump table.
try this:
case 0 ... 10:
case 20 ... 40:
case 41 ... 80:
etc..

c++ tron 2d array repeating

I am trying to get a trail to appear behind the player bike but for some reason instead of a "x" appearing behind the player every time it moves, the player would actually duplicate itself. It sounds a little confusing but you should compile this code yourself and see what i mean. What I am trying to do is just have a trail of "x" behind the player instead of the player leaving a trail of "P". thanks
#include <iostream>
#include "windows.h"
#include <conio.h>
#include <ctime>
using namespace std;
//prototype functions used
void DisplayMap();
void PlayerBike();
void setCursorTo();
void SetBike();
//global variables that will be used by different functions
int PlayerX = 10;
int PlayerY = 70;
bool GameOver = false;
const int H = 25; // const variable so it doesnt change size
const int W = 82;// const variable so it doesnt change size
char Map[H][W]; // char map with HxW
char trail = 'x'; // this is where the trail is initialized as a *
int main()
{
SetBike();
DisplayMap();
while (GameOver == false){
setCursorTo();
PlayerBike();
} // end while loop
return 0;
}//end main
void DisplayMap(){ // display map function
for(int i = 0; i < H; i++ ){
for(int j = 0; j < W; j++){
if(i == 0 || i == 24 || j == 0 || j == 81 ){ Map[i][j] = 'x';} // characters in row 24x81 are changed to x
cout << Map[i][j]; // output map
} // end for loop
cout << "\n"; // create new line to output the map correctly
} //end for loop
} // end DisplayMap function
void SetBike(){
Map[PlayerX] [PlayerY] = 'P';
}
void PlayerBike(){
Map[PlayerY][PlayerX]= trail; // I would like this trail to repeat behind the player but it does not appear at all.
if (kbhit()) {// get user key input
char GetCh = getch(); // GetCh equal to the button the user presses
if (GetCh == 'w'){PlayerX = PlayerX - 1; Trailx = Trailx -1;}
else if (GetCh == 's'){PlayerX = PlayerX +1; Trailx = Trailx +1;}
else if (GetCh == 'd'){PlayerY = PlayerY +1;}
else if (GetCh == 'a'){PlayerY = PlayerY - 1;}
}// end kbhit
}// end PlayerBike function
void setCursorTo() // stops constant flashing on the map
{
HANDLE handle;
COORD position;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
position.X = 0;
position.Y = 0;
SetConsoleCursorPosition(handle, position);
}
Your DisplayMap function is flawed.
First, it seems you are not only displaying the map, you are also actively modifying it. Put the drawing-a-border into a separate initMap function, which also zeros out all other positions with a space (it seems you didn't do that yet, so perhaps that is where it goes wrong). You only need to call initMap once.
Next, do not draw the player P in the DisplayMap function. Draw this once, before entering the game loop. Then: if the user pressed a valid move key,
put an x on the player's position
update player position
put a P on the new position
redraw the screen by calling DisplayMap
and you'll see the trail stays put.
Possible refinements: before accepting a 'move' command by updating the position, check if the map contains a space or something else. If it contains a space, you can execute the move; if not, play an explosion animation (*oO*+.). Also, consider looking up the switch statement in your favourite C reference, to avoid endless long sequences of if..else.