C++로 지뢰찾기를 만들었는데, 하다가 계속 프로그램이 중지되요 ㅠㅠ

docsip의 이미지

아래는 지뢰찾기에 해당하는 소스코드인데요.
하다가 계속 프로그램이 중단됩니다. ㅠㅠ
예를 들어 seed에 1을 넣고 Choice에 0을 넣으면 프로그램이 중단됩니다 ㅠㅠ
뭐가 문제인가요?

#include
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::setw;

enum say_Yes_or_No { Yes, No };
enum result_of_Games { Success, Failure, Quit };

void initialize_Grid(char Grid[10][10]);
void get_seedValue(int&);
void dispose_the_Mines(int Cell[10][10]);
say_Yes_or_No Do_this_Number_exist(int randomNumber, int Cell[10][10]);
void locate_Mines(int Cell[10][10]);
void How_many_mines_are_in_Neighborhood(int Cell[10][10]);
void initialize_realCell(char realCell[10][10], int tempCell[10][10]);
void fill_in_the_Grid(char Cell[10][10], char Grid[10][10], int Choice);
void Game_set(char realCell[10][10], int tempCell[10][10], char Grid[10][10]);
result_of_Games Find_out_All_Mines(char realCell[10][10], char Grid[10][10], int Choice);
void How_many_minefree_cells_is_it(char Grid[10][10], int& counting);
say_Yes_or_No Does_the_Grid_Have_Mine(char Grid[10][10]);
int main()
{
//Declare the Cells, Grids and Seed.
int tempCell[10][10] = {0};
char realCell[10][10] = {'\0'};
char Grid[10][10] = {'\0'};
int seed;

get_seedValue(seed);

srand(seed);

Game_set(realCell, tempCell, Grid);

int Choice=0;
Find_out_All_Mines(realCell, Grid, Choice);

return 0;
}

result_of_Games Find_out_All_Mines(char realCell[10][10], char Grid[10][10], int Choice)
{
int how_much=0;
do {
int counting = 0;

How_many_minefree_cells_is_it(Grid, counting);
counting -= 20;


cout << endl
<< "0 1 2 3 4 5 6 7 8 9" << endl;
cout << "--------------------" << endl;
for (int i = 0; i<10; i++)
for (int j = 0; j < 10; j++)
{
cout << Grid[i][j] << setw(2);
if (j == 9)
cout << "|" << setw(2) << i << endl;
}

cout << endl
<< "Choose one of " << counting << " mine-free cells: ";
cin >> Choice;
if (Choice >= 0 && Choice <= 99)
fill_in_the_Grid(realCell, Grid, Choice);
else
{
if (how_much > 0 && Choice == 'Q')
return Quit;
while ((Choice < 0 || Choice > 99)||(Grid[Choice/10][Choice%10] != '#'))
{

if (cin.fail())
{
cin.clear();
cin.ignore(2147483647, '\n');
}
cout << "Choose again(Enter Q if you want to quit.): ";
cin >> Choice;

}

}
how_much++;
fill_in_the_Grid(realCell, Grid, Choice);
if (counting == 0)
{
cout << endl
<< "0 1 2 3 4 5 6 7 8 9" << endl;
cout << "--------------------" << endl;
for (int i = 0; i<10; i++)
for (int j = 0; j < 10; j++)
{
cout << Grid[i][j] << setw(2);
if (j == 9)
cout << "|" << setw(2) << i << endl;
}

cout << endl;
cout << "Congratulations! You cleared the game.";
return Success;
}

if (Does_the_Grid_Have_Mine(Grid) == Yes)
{
cout << endl
<< "0 1 2 3 4 5 6 7 8 9" << endl;
cout << "--------------------" << endl;
for (int i = 0; i<10; i++)
for (int j = 0; j < 10; j++)
{
cout << Grid[i][j] << setw(2);
if (j == 9)
cout << "|" << setw(2) << i << endl;
}

cout << endl;
cout << "BOOM! Game Over." << endl;
return Failure;
}
} while (1);
}

void How_many_minefree_cells_is_it(char Grid[10][10], int& counting)
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
if (Grid[i][j] == '#')
counting++;
}

say_Yes_or_No Does_the_Grid_Have_Mine(char Grid[10][10])
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
if (Grid[i][j] == 'B')
return Yes;
return No;
}
//****************Fill all Grid with "#"****************//
void initialize_Grid(char Grid[10][10])
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
Grid[i][j] = '#';
}
//******************************************************//
void get_seedValue(int& seed)
{
do {
if (cin.fail())
{
cin.clear();
cin.ignore(214748364, '\n');
}
cout << "Please specify the game seed number: ";
cin >> seed;
} while (seed < 0);
}

//****************It's all about initializing Cell.****************//
void dispose_the_Mines(int Cell[10][10])
{
int randomNumber;
int i = 0;
while (i < 20)
{
randomNumber = rand() % 100;
if (Do_this_Number_exist(randomNumber, Cell) == Yes)
continue;
else if (Do_this_Number_exist(randomNumber, Cell) == No)
{
Cell[randomNumber / 10][randomNumber % 10] = randomNumber;
i++;
}
}
}
say_Yes_or_No Do_this_Number_exist(int randomNumber, int Cell[10][10])
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
if (Cell[i][j] == randomNumber)
return Yes;
return No;
}
void locate_Mines(int Cell[10][10])
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (Cell[i][j] == 0)
;
else
Cell[i][j] = 66;
}
}
}
void How_many_mines_are_in_Neighborhood(int Cell[10][10])
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (Cell[i][j] == 66)
;
else
{
if (Cell[i - 1][j - 1] == 66)
Cell[i][j]++;
if (Cell[i - 1][j] == 66)
Cell[i][j]++;
if (Cell[i - 1][j + 1] == 66)
Cell[i][j]++;
if (Cell[i][j - 1] == 66)
Cell[i][j]++;
if (Cell[i][j + 1] == 66)
Cell[i][j]++;
if (Cell[i + 1][j - 1] == 66)
Cell[i][j]++;
if (Cell[i + 1][j] == 66)
Cell[i][j]++;
if (Cell[i + 1][j + 1] == 66)
Cell[i][j]++;
}
}
}
}
void initialize_realCell(char realCell[10][10], int tempCell[10][10])
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
{
if (tempCell[i][j] == 0)
realCell[i][j] = '.';
else if (tempCell[i][j] == 66)
realCell[i][j] = 'B';
else
realCell[i][j] = (tempCell[i][j] + 48);
}
}
//*****************************************************************//
void fill_in_the_Grid(char Cell[10][10], char Grid[10][10], int Choice)
{
if (Choice >= 0 && Choice <= 99)
switch (Cell[Choice / 10][Choice % 10])
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case 'B':
Grid[Choice / 10][Choice % 10] = Cell[Choice / 10][Choice % 10]; break;
case '.':
Grid[Choice / 10][Choice % 10] = Cell[Choice / 10][Choice % 10];
fill_in_the_Grid(Cell, Grid, Choice - 10);
fill_in_the_Grid(Cell, Grid, Choice - 1);
fill_in_the_Grid(Cell, Grid, Choice + 1);
fill_in_the_Grid(Cell, Grid, Choice + 10);
break;
default:
break;
}
else
;

}

void Game_set(char realCell[10][10], int tempCell[10][10], char Grid[10][10])
{
dispose_the_Mines(tempCell);
locate_Mines(tempCell);
How_many_mines_are_in_Neighborhood(tempCell);
initialize_realCell(realCell, tempCell);
initialize_Grid(Grid);
}

익명 사용자의 이미지

답변하기에 앞서,

0. 300여 줄 코드를 디버그해달라고 부탁하는 글 치고 질문글(https://archive.is/vfy2m)이 너무 성의없다는 생각 안 드십니까.
include 헤더는 다 날라갔고, 소스 코드 indentation도 하나도 안 되어 있고.
kldp 초심자라서 <code> 사용법은 모르실 수 있다고 해도 http://codepad.org/, http://ideone.com/ 등 다른 방법도 있는데, 질문 올리고 나서 한 번 다시 읽어보시지도 않으신 것 같네요.

남의 코드 읽고 리뷰해드리는건 꽤 귀찮은 일입니다. 깔끔하게 복붙하거나 다운받아서 바로 컴파일할 수 있게 올려놓아도 해 줄 사람 한 명이 있을까 말까에요.

1. 원래 대등한 프로그래머끼리는 아무래도 좋은 코딩 스타일 같은 건 웬만하면 서로 터치 안하는데 말이죠
지금은 제가 조언 드리는 입장이니까 실례하겠습니다.

더 많은 사람들에게 익숙한 bool 대신 enum say_Yes_or_No; 같은 걸 쓰시는 이유는 무엇인가요.
YesNo를 조건문에 직접 명시해서 혼동을 줄여보려는 의도라던가 등 무슨 이유가 있으셨겠지만 별로 좋은 방식은 아니라고 생각됩니다.
특히 enum형 상수는 정수형 상수로 암시적 변환되기 때문에, Yes가 0으로 암시적 변환되어서 비직관적이게도 false로 해석될 수 있다는 점을 보면 더욱 그렇죠.
정 그런 용도로 쓰고 싶으시면 아예 별도의 class로 정의하거나, C++11의 enum class를 알아보세요.

혼자 만들어서 혼자 읽을 프로그램 코드라면 아무래도 상관없는데 이렇게 독창적인 스타일을 만들어서 남들더러 읽으라고 하면 의욕이 확 깎입니다.

2. 질문글이 너무 성의없어서 솔직히 그냥 훑어보기만 하려고 했는데 벌써 문제 있는 부분이 세 군데는 보이네요.
못 찾았다면 모르되 찾았으면 알려드리는 것이 바람직하겠죠.

1) How_many_mines_are_in_Neighborhood 함수의 루프 안에 있는 배열 참조는 배열 인덱스 범위를 벗어납니다.
예컨대 Cell[i - 1][j - 1]i=0, j=0일 때 어디를 가리키게 될까요?
물론 대개의 아키텍처&컴파일러 조합으로 질문자님이 프로그램을 실행했을 때 이 부분에서 프로그램이 눈에 띄는 에러를 발생시키지는 않을 겁니다.
하지만 표준에 따르면 배열의 범위를 벗어나는 배열 참조는 미정의 동작을 유발합니다. 거기까지 안 가더라도, 만에 하나 운이 없어서 배열 범위 밖에서 지뢰(66)가 발견되면 어쩌실 건데요?

덧, 미정의 동작보다는 덜 무섭지만 그래도 무서운 로직 에러 하나: 예컨대 i=3, j=0이면 Cell[i - 1][j - 1]는 어딜 가리킬까요. 이게 지뢰찾기 프로그램의 올바른 로직인가요?

2) fill_in_the_Grid함수는 DFS를 재귀로 구현하고 있는데 무한 재귀호출의 여지가 있습니다.
프로그램이 죽는 이유가 아마 여기 있을 거 같네요. 한 번 방문한 셀은 다시 방문하지 않도록 막아야 하는데 그런 조건이 없습니다.
그러면, 예컨대 인접한 두 셀이 둘 다 '.'일 경우(10×10 보드인데다 지뢰는 20개뿐이니 이런 경우가 꽤 있을겁니다.) 그 사이를 왔다갔다하면서 계속 재귀를 돌게 됩니다. 그러다가 스택 오버플로우로 죽는거죠.

3) fill_in_the_Grid의 재귀호출 DFS 탐색 코드에도 로직 에러가 있군요.
예컨대 행의 맨 왼쪽 셀이 '.'이면 그 윗 행의 가장 오른쪽 셀까지도 열리는 구조인데요.(fill_in_the_Grid(Cell, Grid, Choice - 1);) 제가 아는 지뢰찾기 규칙과 다릅니다. 벽에 부딛치면 거기서 멈춰야죠.

이상입니다. 대체적으로 배열 인덱스 관련해서 실수가 있는 거 같은데 이 부분은 확실히 주의를 기울여야 할 만한 이유가 있는 부분입니다. 질문자님이 초심자라면 더더욱 그렇죠.
제 생각엔 더 찾아보면 버그가 더 있을 것 같은데, 질문글이 깔끔하게 정리되고 나면 한 번 생각해 보도록 하죠. -_-;

mauri의 이미지

추천드립니다!!!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.