jeudi 19 octobre 2017

C++: Adding a logically correct if statement crashes my program

I am a novice and I've run into a problem I can't seem to fix. Namely, I have these two seperate working blocks of code, yet if I use both of them the program crashes (returning an error code of 3221225477).

#include <conio.h>
#include <iostream>
#include <string>
#include <windows.h>
#include <chrono>
#include <thread>
#include <vector>
#include <time.h>

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define ENTER 13

using namespace std;

struct set {
int speed=0;
bool obs=0;
} settings;

void gotoyx( int y, int x ) { //moves the console cursor
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle( STD_OUTPUT_HANDLE ), coord);
}

void setup() { //used to determine the snake's speed, expressed as delay between movement
int c = 0;
string o1=">SLOW", o2=" MEDIUM", o3=" FAST";
while(settings.speed==0)
{
    c = 0;
    gotoyx(c, c); //sets cursor at top-left
    cout << "Please choose your speed setting:\n"<< o1 << endl << o2 << endl << o3 << endl;
    switch((c=getch())) {
    case KEY_UP:
        if(o2.at(0)=='>'){
            o1[0]='>';
            o2[0]=' ';
        }
        else if(o3.at(0)=='>'){
            o2[0]='>';
            o3[0]=' ';
        }
        break;
    case KEY_DOWN:
        if(o1.at(0)=='>'){
            o2[0]='>';
            o1[0]=' ';
        }
        else if(o2.at(0)=='>'){
            o3[0]='>';
            o2[0]=' ';
        }
        break;
    case ENTER:
        if(o1.at(0)=='>') {
            cout << "You chose SLOW.\n";
            settings.speed=160; 
        }
        else if(o2.at(0)=='>') {
            cout << "You chose MEDIUM.\n";
            settings.speed=120;
        }
        else {
            cout << "You chose FAST.\n";
            settings.speed=80;
        }
        settings.obs=1;
        cout << "Press a key to continue.";
        getch();
        break;
    default:
        break;
    }
}
}

void draw_border() {
for(int i=0; i<80; i++){ //80 fills screen vertically - TOP
    cout<<"#";
}
for(int i=0; i<23; i++){ //25 fills screen horizontally (2 used for top and bottom)
    cout<<"#";
    for(int i=0; i<78; i++){
    cout<<" ";
    }
    cout<<"#";
}
for(int i=0; i<80; i++){ //80 fills screen vertically - BOTTOM
    cout<<"#";
}
}

void ShowConsoleCursor(bool showFlag) { //blinking-underscore-with-console
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);

CONSOLE_CURSOR_INFO     cursorInfo;

GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = showFlag; // set the cursor visibility
SetConsoleCursorInfo(out, &cursorInfo);
  }

int keypad(int out){                                        //reads arrow keys during game
    if (GetAsyncKeyState(VK_UP) & 0x8000 && out!=1 ) {  //MSB set if currently pressed
        out=0;                                          //if nothing is pressed it returns
    }                                                   //the last pressed button
    else if (GetAsyncKeyState(VK_DOWN) & 0x8000 && out!=0) {
        out=1;
    }
    else if (GetAsyncKeyState(VK_LEFT) & 0x8000 && out!=3) {
        out=2;
    }
    else if (GetAsyncKeyState(VK_RIGHT) & 0x8000 && out!=2) {
        out=3;
    }
    return out;                                         
}

int main() {
ShowConsoleCursor(false);                               //disable blinking console cursor
setup();
int tmp=0, cntr_g=0, cntr_o=0;
system("cls");                                          //clear screen after inital setup
draw_border();
gotoyx(tmp, tmp);                                       //using cursor to scroll to console top
vector<vector<int>> snake_pos;                          //tracks snake location
snake_pos.emplace(snake_pos.begin(), std::initializer_list<int>{13,40});
int y = snake_pos[0][0];                                //Y coordinate of snake head
int x = snake_pos[0][1];                                //X coordinate of snake head
gotoyx(y, x);
cout<<"*";
int key, boost_y, boost_x, obstacle_y, obstacle_x;
bool b_flag=0;
vector<vector<int>> boost (1, vector<int>(2, 0));
vector<vector<int>> obstacle (1, vector<int>(2, 0));
while(1){
    key=keypad(key);
    if (key==0) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y-1, x});
    }
    else if (key==1) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y+1, x});
    }
    else if (key==2) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y, x-1});
    }
    else if (key==3) {
        snake_pos.emplace(snake_pos.begin(), std::initializer_list<int> {y, x+1});
    }

    y = snake_pos[0][0]; x = snake_pos[0][1];           //updating snake head coordinates

    if (y==0 | y==24 | x==0 | x==80 ) {                 //checking whether player hit wall
        return 0;
    }
    for (tmp=1; tmp!=snake_pos.size()-1; ++tmp) {       //checking whether player hit self
        if (y==snake_pos[tmp][0] && x==snake_pos[tmp][1]) {
            return 0;
        }
    }

    //check if obstacle was hit [not here yet]

    ++cntr_g;                                           //generating growth boost block
    if (cntr_g==settings.speed/5) {
        label_growth:
        srand(time(NULL));
        boost_x=(rand()%78)+1;
        boost_y=(rand()%23)+1;
        for (tmp=0; tmp!=snake_pos.size()-1; ++tmp) {
            if (boost_y==snake_pos[tmp][0] && boost_x==snake_pos[tmp][1]) {
                goto label_growth;
            }
        }
        gotoyx(boost_y, boost_x); cout<<"O";
        boost.emplace_back(std::initializer_list<int> {boost_y, boost_x});
        cntr_g=0;
    }

    /*
    ++cntr_o;                                               //generating obstacle block
    if ((cntr_o==settings.speed/4) && (settings.obs==1)) {  //also check if obs enabled
        label_obstacle:
        srand(time(NULL));
        obstacle_x=(rand()%78)+1;
        obstacle_y=(rand()%23)+1;
        for (tmp=0; tmp!=snake_pos.size()-1; ++tmp) {       //check overlap with snake
            if (obstacle_y==snake_pos[tmp][0] && obstacle_x==snake_pos[tmp][1]) {
                goto label_obstacle;
            }
        }
        for (tmp=0; tmp!=boost.size()-1; ++tmp) {           //check overlap with boosts
            if (obstacle_y==boost[tmp][0] && obstacle_x==boost[tmp][1]) {
                goto label_obstacle;
            }
        }
        gotoyx(obstacle_y, obstacle_x); cout<<"X";
        obstacle.emplace_back(std::initializer_list<int> {obstacle_y, obstacle_x});
        cntr_o=0;
    }*/

    gotoyx(y, x); cout<<"*"; b_flag=0;                  //updating graphics for new snake
    for (tmp=0; tmp!=boost.size()-1; ++tmp) {           
        if (y==boost[tmp][0] && x==boost[tmp][1]) {
            boost.erase(boost.begin()+tmp);
            b_flag=1;
            break;
        }
    }
    if (b_flag==0){                                     //if snake didn't grow, last block stays
        gotoyx(snake_pos.back()[0], snake_pos.back()[1]); cout<<" ";
        snake_pos.pop_back();
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(settings.speed));
}

return 0;
}

Namely, the problem is with the if statement for the growth block portion, and the obstacle block portion. The program(game) works as intended when one of them is commented out, but doesn't if both of them are left in. In fact, even just leaving in the cntr_o++; without the following if statement is enough to crash it.

Aucun commentaire:

Enregistrer un commentaire