Dungeon crawler not working - c++

I am making a simple randomly generated dungeon crawler and when I ran it, sometimes the end or player weren't in the map, they were generated off map. After I fixed it I put limitations and checker to see if Player and End were created but now after I run it, it just gets stuck.
//Traps, Ending and Player generation
void TEPgen()
{
srand(time(0));
//Traps
for(i=0; i<22; i++)
{
a=(rand()%11);
b=(rand()%11);
map[a][b]='T';
}
//Ending
Egeneration:
a=(rand()%11);
b=(rand()%11);
for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
if(((a+i)>9) && ((a-i)<0) && ((b+j)>9) && ((b-j)<0) )
goto Egeneration;
}
}
y=a;x=b;
map[y][x]='E';
//Player
Pgeneration:
a=(rand()%11);
b=(rand()%11);
for(i=0; i<3; i++)
{
for(j=0; j<3; j++)
{
if(map[a+i][b+j]=='E' && map[a-i][b-j]=='E' && ((a+i)>9) && ((a-i)<0) && ((b+j)>9) && ((b-j)<0))
goto Pgeneration;
}
}
//Generation checker
Gencheck:
for(i=0; i<10; i++)
{
for(j=0; j<10; j++)
{
if(map[i][j]=='E')
E+=1;
else
goto Egeneration;
if(map[i][j]=='P')
P+=1;
else
goto Egeneration;
}
}
next:
map[a][b]='P';
mapview();
}

There are other issues with your code, but the problem in your question is caused by the code under the Gencheck label. If you follow through the logic, is does (roughly) the following:
Loop through every cell in the map
If it is equal to 'E', then increment the E counter
If it is equal to 'P', then increment the P counter
If either of these tests fails, then go back to Egeneration
Hopefully this clarifies why your code enters an infinite loop: the cell is never equal to both 'E' and 'P' and so the program will always fail one of these two checks and go back to Egeneration.

Related

Why does my for loop not get argv properly?

So Im new to coding, and I was wondering why my for loop is not going through argv correctly. When I run it, it doesnt run at all. Here is the bit of code that matters:
int main(int argc, char* argv[]){
bool isCapital[500];
bool capital;
bool isSpace[500];
bool space;
bool palindrome;
cout<<"Test";
for(int j=1; argv[j][0]!='-'; j++){
cout<<argv[j][0];
if('-'==argv[j][0]){
cout<<j;
for(int i=0; argv[j][i]!='\0'; i++){
if((argv[j][i])==('c'|'C')){
isCapital[j]=true;
break;
cout<<isCapital[j];
}
}
for(int i=0; argv[j][i]!='\0'; i++){
if((argv[j][i]==('s'|'S'))){
isSpace[j]=true;
break;
}
}
}
}
There are a couple of bugs in your code but I think the code below is major one:
for(int j=1; argv[j][0]!='-'; j++){
cout<<argv[j][0];
if('-'==argv[j][0]){
so let us look at it in more details.
for(int j=1; argv[j][0]!='-'; j++){
^^^^^^^^^^^^^^^
This part says: only execute the body of the for-loop if argv[j][0] is not a -
This line:
if('-'==argv[j][0]){
says: only execute the body of the if-statement if argv[j][0] is a -
These two are contradictions so execution never enters the body of the if-statement
Maybe you want this line
for(int j=1; argv[j][0]!='-'; j++){
to be
for(int j=1; j < argc; j++){
BTW:
As written in a comment by #swordfish
1) Notice that
if((argv[j][i])==('c'|'C'))
is probably not what you want. You probably want:
if(argv[j][i] == 'c' || argv[j][i] == 'C')
2) Notice that your loop condition should consider argc
3) That isCapital and isSpace should be initialized to "all false"

C++ Tetris: A function that deletes lines

I've been studying this tetris tutorial and I've come across the function that deletes lines and brings the row/s down one level. I'm kind of understanding what is going on with these functions, but some parts are confusing me. I'll try and explain it best I can, but here is the link to the lesson if you need it: http://javilop.com/gamedev/tetris-tutorial-in-c-platform-independent-focused-in-game-logic-for-beginners/
This, to me, looks like a function to get the array to start at the last number of a line:
void Board::DeleteLine (int pY)
{
// Moves all the upper lines one row down
for (int j = pY; j > 0; j--)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
mBoard[i][j] = mBoard[i][j-1];
}
}
}
Then, there is the function that is causing me problems, which I will explain:
void Board::DeletePossibleLines ()
{
for (int j = 0; j < 20; j++)
{
int i = 0;
while (i < 10)
{
if (mBoard[i][j] != 1) break;
i++;
}
if (i == 10) DeleteLine (j);
}
}
In case you're not familiar, the idea here is to delete a row that consists entirely of 1. But if (mBoard[i][j] != 1) break; would stop the loop if the first line wasn't 1. How would the loop reach a 1 that is somewhere in the middle of the mBoard[][] array if break stops it from doing anything possible straight away?
Am I missing something here? This is my interpretation of it. Perhaps somebody sees something I do't?
Edit:
Thanks for the replies, appreciated.
You could structure the code like this aswell:
for (int j = 0; j < 20; j++)
{
int i = 0;
while (i < 10)
{
if (mBoard[i][j] != 1)
{
break; //only breaks the while loop and will continue with if (i == 10)
}
else
{
i++;
}
}
if (i == 10)
{
DeleteLine (j);
}
}
Now you can clearly see, that the break; is only interrupting your while loop but not your for loop.
The break will jump out of the while loop. So if you encounter a line which has a non-1 somewhere in the middle, i will be the index in the line, and the for loop will continue with the next line (j), starting with i=0 again.
break only interrupts one loop, the while loop in your case. The for loop continues happily.
On a side note, this while could easily (and should) be refactored into a for, and can be compacted according to its recognizable for-if-break pattern :
for (int j = 0; j < 20; ++j)
{
int i;
for(i = 0; i < 10 && mBoard[i][j] == 1; ++i);
if (i == 10) DeleteLine (j);
}

For loops are skipped, why?

I have an assignment in which i have to create a console program in c++ that draws Hexagons in a given style. The problem i am having is; my For loops are never entered and i can't figure out why. here's the snippet of code I'm having trouble with.
void display()
{
int counter=0;//var that keeps track of the layer that is being drawn
for(int i=0;i>=size;i++)//spaces before first layer of hexagon
{
cout<<" ";
}
for (int k=0; k>size;k++)//top layer of hexagon
{
cout<<"_";
}
cout<<endl;//ends the first layer
for (counter; counter>=size-1;counter++)//outer loop for the top half that controls the size
{
for( int j=0;j>(size-counter);j++)//adds spaces before the shape
{
cout<<" ";
}
cout<<"/";
for( int p=0; p>(size+(counter*2));p++)//loop for the hexagon fill
{
cout<<fill;
}
cout<<"\\"<<endl;
}
for(counter;counter==0;counter--); //loop for bottom half of the hexagon
{
for( int j=0;j>(size-counter);j++)//adds spaces before the shape
{
cout<<" ";
}
cout<<"\\";
for( int p=0; p>(size+(counter*2));p++)//loop for the hexagon fill
{
cout<<fill;
}
cout<<"/"<<endl;
}
cout<<"\\";
for(int r=0; r>=size;r++){cout<<"_";}
cout<<"/"<<endl;
}
the 'Size' and 'fill' are selceted earlier in the program during my main()
I'm probably missing something very simple but I've been struggling with this for a while. Any help would be greatly appricated!
Your loops use > and start at 0. It seems you want < instead. For example
for(int i=0;i<size;i++)//spaces before first layer of hexagon
{
cout<<" ";
}
I am not sure what is the content of your size variable but it looks like you have got your loop conditions wrong:
for(int i=0;i>=size;i++)
probably should be:
for(int i=0;i<size;i++)
The same goes for other loops.
Assuming your size is a postive number, it works as per your condition.
Change the > conditojs to < in your conditions.
In your conditions, invert the > to <
< means inferior, you want to do a
for i = 0; if i < size; i++
You do
for i = 0 ; if i > size ; i ++
if size is superior to i (0) the loop will never trigger
Aren't all of your < and > reversed? Because
(int k=0; k>size;k++)
makes no sense to me.
for loops in C++ are while loops, not until loops.
C++ has only while loops (with the meaning of as long as):
for (int i=0; i<10; ++i)
....
int i=0;
while (i<10) {
....
++i;
}

How to exit (go to next element of parent loop) a for loop inside a for loop

for (int i = 0; i<10; i++)
{
//do some validation for record length
//if it is not valid
continue; // goes to the next iteration in for loop for 'i'
for (int j = 0; j<5; j+=2)
{
//do some more validation for individual record
//if it is not valid
Here it should go to the next i if i use continue. Here it will go to the next j
Can anyone please let me know how to do this?
You need to specifically test for a flag in the outer loop if there is something after the inner loop:
for(some_outer_vars){
bool should_skip = false;
// ...
for(some_inner_vars){
// ...
if(your_condition){
should_skip = true;
break;
}
}
if(should_skip)
continue;
// ...
}
Using break; inside the j loop will exit the j loop completely.
But at least spend a couple minutes deciding if an alternate algorithm, approach, or termination condition could remove the need to break in the middle of a loop.
Do you have anything after the inner loop? If not, you can just use break:
for (i = 0; i < 10; i++)
{
if (i is no good)
continue;
for (j = 0; j < 5; j++)
{
if (j is no good)
break;
}
}
If you do need to do something later, you can use break in combination with some other flag.
Place break; instead. This should get you out of the inner loop.
for (int i = o; i<10; i++)
{
}
for (int j = 0; j<5; j+=2)
{
break;
}
"break;" will end your current j loop and go to the next i.
If you can't arrange the logic so that break in the inner loop gets straight to continuing the outer loop, then do this:
for (int i = 0; i<10; i++)
{
if (!valid(i)) continue;
for (int j = 0; j<5; j+=2)
{
if (!valid(i,j)) goto continue_i;
do_whatever_with_i_and_j()
}
more_stuff_here();
continue_i:
}
There, I've said it. The code is shorter, simpler, easier to read and easier to analyse than the version that sets a flag, then breaks, then immediately checks the flag again and conditionally continues.
Another option is this
void inner_loop(int i) {
if (!valid(i)) return;
for (int j = 0; j<5; j+=2)
{
if (!valid(i,j)) return;
do_whatever_with_i_and_j()
}
more_stuff_here();
}
for (int i = 0; i<10; i++)
{
inner_loop(i);
}
Depending what the inner loop does, though, you might find yourself building quite a mechanism to give it access to whatever it's supposed to modify.
Community wiki, because this (or situations like it) has been argued so many times on SO as to practically define "subjective and argumentative".
I try to avoid break and continue when dealing with loops because they are easy to miss and their meanings change if you have to restructure the code later. You can use j=5; when you need to exit the inner loop. If you add a third loop or a switch the meaning of that line doesn't change. Sometimes you will need to add if statements inside your loops testing i and j or even a new variable like bool iIsInvalid but I think that makes the control flow easier to read.

Can I use break to exit multiple nested 'for' loops?

Is it possible to use the break function to exit several nested for loops?
If so, how would you go about doing this? Can you also control how many loops the break exits?
No, don't spoil it with a break. This is the last remaining stronghold for the use of goto.
AFAIK, C++ doesn't support naming loops, like Java and other languages do. You can use a goto, or create a flag value that you use. At the end of each loop check the flag value. If it is set to true, then you can break out of that iteration.
Just to add an explicit answer using lambdas:
for (int i = 0; i < n1; ++i) {
[&] {
for (int j = 0; j < n2; ++j) {
for (int k = 0; k < n3; ++k) {
return; // yay we're breaking out of 2 loops here
}
}
}();
}
Of course this pattern has a certain limitations and obviously C++11 only but I think it's quite useful.
Another approach to breaking out of a nested loop is to factor out both loops into a separate function, and return from that function when you want to exit.
Of course, this brings up the other argument of whether you should ever explicitly return from a function anywhere other than at the end.
break will exit only the innermost loop containing it.
You can use goto to break out of any number of loops.
Of course goto is often Considered Harmful.
is it proper to use the break function[...]?
Using break and goto can make it more difficult to reason about the correctness of a program. See here for a discussion on this: Dijkstra was not insane.
How about this?
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
//Some statement
if (condition)
{
j=50;
k=50;
}
}
}
}
Although this answear was already presented, i think a good approach is to do the following:
for(unsigned int z = 0; z < z_max; z++)
{
bool gotoMainLoop = false;
for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
{
for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
{
//do your stuff
if(condition)
gotoMainLoop = true;
}
}
}
A code example using goto and a label to break out of a nested loop:
for (;;)
for (;;)
goto theEnd;
theEnd:
One nice way to break out of several nested loops is to refactor your code into a function:
void foo()
{
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
// If condition is true
return;
}
}
}
}
I know this is an old thread but I feel this really needs saying and don't have anywhere else to say it. For everybody here, use goto. I just used it.
Like almost everything, goto is not 100% either/xor "bad" or "good". There are at least two uses where I'd say that if you use a goto for them - and don't use it for anything else - you should not only be 100% okay, but your program will be even more readable than without it, as it makes your intention that much clearer (there are ways to avoid it, but I've found all of them to be much clunkier):
Breaking out of nested loops, and
Error handling (i.e. to jump to a cleanup routine at the end of a function in order to return a failure code and deallocate memory.).
Instead of just dogmatically accepting rules like "so-so is 'evil'", understand why that sentiment is claimed, and follow the "why", not the letter of the sentiment. Not knowing this got me in a lot of trouble, too, to the point I'd say calling things dogmatically "evil" can be more harmful than the thing itself. At worst, you just get bad code - and then you know you weren't using it right so long as you heard to be wary, but if you are wracking yourself trying to satisfy the dogmatism, I'd say that's worse.
Why "goto" is called "evil" is because you should never use it to replace ordinary ifs, fors, and whiles. And why that? Try it, try using "goto" instead of ordinary control logic statements, all the time, then try writing the same code again with the control logic, and tell me which one looks nicer and more understandable, and which one looks more like a mess. There you go. (Bonus: try and add a new feature now to the goto-only code.) That's why it's "evil", with suitable scope qualification around the "evil". Using it to short-circuit the shortcomings of C's "break" command is not a problematic usage, so long as you make it clear from the code what your goto is supposed to accomplish (e.g. using a label like "nestedBreak" or something). Breaking out of a nested loop is very natural.
(Or to put it more simply: Use goto to break out of the loop. I'd say that's even preferable. Don't use goto to create the loop. That's "evil".)
And how do you know if you're being dogmatic? If following an "xyz is evil" rule leads your code to be less understandable because you're contorting yourself trying to get around it (such as by adding extra conditionals on each loop, or some flag variable, or some other trick like that), then you're quite likely being dogmatic.
There's no substitute for learning good thinking habits, moreso than good coding habits. The former are prior to the latter and the latter will often follow once the former are adopted. The problem is, however, that far too often I find, the latter are not explicated enough. Too many simply say "this is bad" and "this needs more thought" without saying what to think, what to think about, and why. And that's a big shame.
(FWIW, in C++, the need to break out of nested loops still exists, but the need for error codes does not: in that case, always use exceptions to handle error codes, never return them unless it's going to be so frequent that the exception throw and catch will be causing a performance problem, e.g. in a tight loop in a high demand server code, perhaps [some may say that 'exceptions' should be 'used rarely' but that's another part of ill-thought-out dogmatism: no, at least in my experience after bucking that dogma I find they make things much clearer - just don't abuse them to do something other than error handling, like using them as control flow; effectively the same as with "goto". If you use them all and only for error handling, that's what they're there for.].)
goto can be very helpful for breaking nested loops
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
for (l = 0; l < 1000; l++){
....
if (condition)
goto break_me_here;
....
}
}
}
}
break_me_here:
// Statements to be executed after code breaks at if condition
I'm not sure if it's worth it, but you can emulate Java's named loops with a few simple macros:
#define LOOP_NAME(name) \
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] CAT(_namedloop_break_,name): break; \
[[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
} \
else
#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
Example usage:
#include <iostream>
int main()
{
// Prints:
// 0 0
// 0 1
// 0 2
// 1 0
// 1 1
for (int i = 0; i < 3; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << i << ' ' << j << '\n';
if (i == 1 && j == 1)
BREAK(foo);
}
}
}
Another example:
#include <iostream>
int main()
{
// Prints:
// 0
// 1
// 0
// 1
// 0
// 1
int count = 3;
do LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << ' ' << j << '\n';
if (j == 1)
CONTINUE(foo);
}
}
while(count-- > 1);
}
The break statement terminates the execution of the nearest enclosing do, for, switch, or while statement in which it appears. Control passes to the statement that follows the terminated statement.
from msdn.
I do think a goto is valid in this circumstance:
To simulate a break/continue, you'd want:
Break
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
Continue
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
Break any number of loops by just one bool variable see below :
bool check = true;
for (unsigned int i = 0; i < 50; i++)
{
for (unsigned int j = 0; j < 50; j++)
{
for (unsigned int k = 0; k < 50; k++)
{
//Some statement
if (condition)
{
check = false;
break;
}
}
if (!check)
{
break;
}
}
if (!check)
{
break;
}
}
In this code we break; all the loops.
Other languages such as PHP accept a parameter for break (i.e. break 2;) to specify the amount of nested loop levels you want to break out of, C++ however doesn't. You will have to work it out by using a boolean that you set to false prior to the loop, set to true in the loop if you want to break, plus a conditional break after the nested loop, checking if the boolean was set to true and break if yes.
I know this is old post . But I would suggest a bit logical and simpler answer.
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < conditionj; j++)
{
for(unsigned int k=0; k< conditionk ; k++)
{
// If condition is true
j= conditionj;
break;
}
}
}
bool found = false;
for(int i=0; i < m; ++i){
for(int j=0; j < n; ++j)
if(grid[i][j] == '*'){
q.push(make_pair(i,j));
found = true;
break;
}
if(found)
break;
}
My suggestion is use a check variable to break a desired loop. The result code may not be so pleasant.
You can use preprocessors in order to make desired breaking under the hood. This approach can hides ugly codes and extra complexity.
For example, I created my custom break mechanism as follow:
Wanted code:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
for (int k = 0; k < 100; k++) {
//do something
if (desiredCondition) {
breakToLevel = 0;
}
if (breakToLevel < 3) {
break;
}
}
if (breakToLevel < 2) {
break;
}
}
if (breakToLevel < 1) {
break;
}
}
Defined macros:
#define BREAK_TO(L) breakToLevel = (L);
#define CHECK_BREAK(L) if (breakToLevel < (L)) break;
and result:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
for (int k = 0; k < 100; k++) {
//do something
if (desiredCondition) {
BREAK_TO(0)
}
CHECK_BREAK(3)
}
CHECK_BREAK(2)
}
CHECK_BREAK(1)
}
while (i<n) {
bool shouldBreakOuter = false;
for (int j=i + 1; j<n; ++j) {
if (someCondition) {
shouldBreakOuter = true;
}
}
if (shouldBreakOuter == true)
break;
}
you can use "goto" to leave nested loops
below is my original code including "goto"
int main()
{
string str;
while (cin >> str)
{
if (str == "0")
break;
int sum = 0;
for (auto ch : str)
{
if (ch <= 'z' && ch >= 'a')
sum += (ch - 'a' + 1);
else if (ch >= 'A' && ch <= 'Z')
sum += (ch - 'A' + 1);
else
{
cout << "Fail" << endl;
goto fail;
}
}
cout << sum << endl;
fail:
}
return 0;
}
however, I could avoid "goto" by adding a function "calculate"
void calculate(const string &str)
{
int sum = 0;
for (auto ch : str)
{
if (ch <= 'z' && ch >= 'a')
sum += (ch - 'a' + 1);
else if (ch >= 'A' && ch <= 'Z')
sum += (ch - 'A' + 1);
else
{
cout << "Fail" << endl;
return;
}
}
cout << sum << endl;
}
int main()
{
string str;
while (cin >> str)
{
if (str == "0")
break;
calculate(str);
}
return 0;
}
You can use try...catch.
try {
for(int i=0; i<10; ++i) {
for(int j=0; j<10; ++j) {
if(i*j == 42)
throw 0; // this is something like "break 2"
}
}
}
catch(int e) {} // just do nothing
// just continue with other code
If you have to break out of several loops at once, it is often an exception anyways.
Breaking out of a for-loop is a little strange to me, since the semantics of a for-loop typically indicate that it will execute a specified number of times. However, it's not bad in all cases; if you're searching for something in a collection and want to break after you find it, it's useful. Breaking out of nested loops, however, isn't possible in C++; it is in other languages through the use of a labeled break. You can use a label and a goto, but that might give you heartburn at night..? Seems like the best option though.