2D массив крестики-нолики — Что я делаю не так?

Возникли проблемы с получением моей игры … Есть мысли о том, что я мог бы сделать? Я просмотрел большую часть кода и инициализировал его, но по какой-то причине в большинстве функций говорится, что у меня нет подходящих точек. Кроме того, что drawBoard не имеет типа пустоты. Пожалуйста помоги

Спасибо

#include <iostream>

using namespace std;

// initialize a 2d board (3,3) with asterisk
void drawBoard(char board[][]);
char check_Winner(char [][]);

int main(){
char board[3][3]={{'*','*','*'},{'*','*','*'},{'*','*','*'}};
bool win = false;
bool in_row = false;
bool in_col = false;
int row;
int column;// run a loop:
while (!win) {
// Display the content of the board
drawBoard(char board[][]));
cout << "Player 1's turn:";
// Ask player one to chose a location (row, column)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
// check if move is valid

//check if location has astericks and its between 0 thru 2
bool valid = false;
while (!valid)
{
//check if the move is within range.
if(!(row <= 3 && row >= 1 && column <= 3 && column >= 1)){
cout << "Error: Either the row or column is not within range of the board.\n";
// ask again (error: row in column not within range)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}
else if(board[row-1][column-1] != '*')
{
cout << "Error: The (row,column) is already occupied.\n";
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}else {
valid = true;
}}
board[row-1][column-1] = 'X';
drawBoard(char board[][]);
// Check if someone won or  if there is a tie
check_Winner(char board[][]);
// Ask player two to chose a location (row, column)
cout << "Player 2's turn:";

cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
// check if move is valid

//check if location has astericks and its between 0 thru 2
bool valid = false;
while (!valid)
{
//check if the move is within range.
if(!(row <= 3 && row >= 1 && column <= 3 && column >= 1)){
cout << "Error: Either the row or column is not within range of the board.\n";
// ask again (error: row in column not within range)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}
else if(board[row-1][column-1] != '*')
{
cout << "Error: The (row,column) is already occupied.\n";
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}else
{
valid = true;
}
board[row-1][column-1] = 'O';
}
drawBoard(char board[][])
// Check if someone won or  if there is a tie
check_Winner(char board[][]);

}

system("pause");

return 0;
}
char check_Winner(char board[][]){
char winner = 'T';

// Checks for horizontal:
for (int i = 0; i < 3; i++)
if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
winner = board[i][0];

// Checks for vertical:
for (int i = 0; i < 3; i++)
if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
winner = board[0][1];

// Checks for diagnol:
if ((board[0][0] == board[1][1] && board[1][1] == board[2][2]) ||
(board[0][2] == board[1][1] && board[1][1] == board[2][0]))
winner = board[1][1];

// checking the result:
switch (winner) {
case 'T': cout << "IT'S A TIE";/* tie */ break;
case 'X': cout << "PLAYER 1 WON!";/* X won */ break;
case 'O': cout << "PLAYER 2 WON!";/* O won */ break;
default : cout << "NEXT PLAYER'S TURN...>"; continue;
}

}
void drawBoard(char board[][])
{

cout << "     1   2   3" << endl;
cout << "   +---+---+---+" << endl;

cout << " 1" << " | " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

cout << " 2" << " | " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

cout << " 3" << " | " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

}

1

Решение

Я вставил ваш код в codepad.org и скомпилировал его. Первое сообщение об ошибке:

Строка 6: ошибка: объявление ‘board’ в качестве многомерного массива должно иметь границы для всех измерений, кроме первого

Другими словами — если вы не скажете компилятору что-то о размерах вашего двумерного массива, он не будет знать, как найти элемент. Это почему? Ну, когда вы получаете доступ к двумерному массиву из m x n элементов, a [i] [j], вы действительно вычисляете

*(a + n * i + j)

потому что каждый раз, когда вы увеличиваете строку iпропускаешь другую n элементы.

Еще один способ думать об этом — «2D» элементы — это действительно один большой блок. Если у тебя есть

0  1  2  3
4  5  6  7
8  9 10 11

Они действительно хранятся как

0 1 2 3 4 5 6 7 8 9 10 11

И вы найдете элемент [1] [1], скажем, вычисляя смещение (1D индекс, если хотите) 1 * 4 + 1 = 5, И, конечно же, элемент 5 в линейном массиве имеет значение 5, что вы бы нашли, пройдя один вниз и один поперек.

Мы исправим эту первую ошибку компилятора, заменив

void drawBoard(char board[][]);
char check_Winner(char [][]);

с

void drawBoard(char board[][3]);
char check_Winner(char [][3]);

(как в стороне, я не уверен, почему check_Winner определяется как возвращение char (у вас нет return Winner; оператор в вашей функции …), и почему вы используете странное сочетание символов подчеркивания и заглавных букв в названии вашей функции. Мы вернемся к этому позже)

Далее компилятор жалуется на то, как вы вызываете эти функции. Вы должны называть их (в строке 23 и в других местах), а не как

drawBoard(char board[][]);

но просто как

drawBoard(board);

Поскольку вы уже определили, что вы передаете charи вам не нужно [][] напомнить компилятору о типе board (вы определили это ранее).

Следующая ошибка (после исправления), которую выдает компилятор,

In function 'int main()':

Line 72: error: redeclaration of 'bool valid'

Действительно, вы определили

bool valid = false;

в строке 33. После этого, при обращении к той же переменной, вы не должны ставить bool перед именем переменной — похоже, что вы (повторно) объявляете переменную. Просто положи

valid = true

в строке 72. (Кроме того, вы явно произвели копирование-вставку большого блока кода, и именно так закралась эта ошибка. Вы хотите серьезно подумать о поиске способа сделать «ход» единственной функцией, которая может быть призванным либо к игроку 1, либо к игроку 2 — тогда вам не нужно повторять весь этот код, и все будет выглядеть чище. И менее подвержено ошибкам.).

После исправления компилятор жалуется на строку 99:

In function 'int main()':

Line 99: error: expected ';' before 'check_Winner'

Как это часто бывает с подобными ошибками, проблема в строке раньше. Строка 97:

drawBoard(board)

отсутствует точка с запятой в конце, и должен быть

drawBoard(board);

После исправления компилятор жалуется на строку 130:

default : cout << "NEXT PLAYER'S TURN...>"; continue;

In function 'char check_Winner(char (*)[3])':

Line 130: error: continue statement not within a loop

continue оператор используется, чтобы сказать «переходите прямо к следующей итерации цикла, в котором вы находитесь» (while, for…). Но вы используете его внутри switch оператора, и нет цикла (в пределах функции, в которой вы находитесь), к которому может перейти код. Если вы просто оставите continue; выкл, код продолжится просто отлично.

На самом деле (хотя это не совсем то, о чем вы спрашиваете), break' не приведет к остановке программы; это просто приведет вас к концу функции, и код продолжит работу. Вот почему вам действительно нужно возвращаемое значение в вашем check_Winner функция — и вам нужно проверить его после того, как вы его вызвали, чтобы вы могли предпринять соответствующие действия (распечатать сообщение и выйти из игры).

Вынимая continue в строке 130 мы теперь нажали предупреждение в строке 133:

In function 'char check_Winner(char (*)[3])':

Line 133: warning: control reaches end of non-void function

Это говорит «вы объявили эту функцию, чтобы вернуть char, но вы забыли положить в return заявление! «. Добавить

return winner;

до окончания функции, и жалоба уходит.

Результатом всех этих правок является следующий код. Я не говорю, что это «хороший» код, но по крайней мере ошибки компилятора были удалены. Я надеюсь, что процесс, который я описал, будет полезен для вас в процессе обучения. У большинства компиляторов есть флаги для включения предупреждений и сообщений об ошибках; я сильно рекомендую вам всегда включить каждое предупреждение, которое вы можете, и обратите внимание на то, на что жалуется компилятор. Вы научитесь писать лучший код ..

отказ — Я писал это пока «в дороге», поэтому я мог использовать codepad.org только для базовой отладки. Он не позволяет интерактивное программирование, поэтому я не мог проверить, работает ли окончательный код — я могу только сказать вам, что он перестал жаловаться на ошибки в коде … Я на 99% уверен, что ваш check_Winner В коде есть логические ошибки — например, вы начинаете с

winner = 'T';

Это означает, что вы будете называть ничью, если не выполнено одно из других условий; Я думаю, что вы должны вызывать ничью, только если у вас нет звездочек (если вы хотите быть по-настоящему умным, вы можете назвать ничью, когда нет возможного решения, но это гораздо сложнее для кода).

В любом случае — вот код, который компилируется. Думаю, еще есть чем заняться, прежде чем вы получите рабочую игру

#include <iostream>

using namespace std;

// initialize a 2d board (3,3) with asterisk
void drawBoard(char board[][3]);
char check_Winner(char board[][3]);

int main(){
char board[3][3]={{'*','*','*'},{'*','*','*'},{'*','*','*'}};
bool win = false;
bool in_row = false;
bool in_col = false;
int row;
int column;// run a loop:
while (!win) {
// Display the content of the board
drawBoard(board);
cout << "Player 1's turn:";
// Ask player one to chose a location (row, column)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
// check if move is valid

//check if location has astericks and its between 0 thru 2
bool valid = false;
while (!valid)
{
//check if the move is within range.
if(!(row <= 3 && row >= 1 && column <= 3 && column >= 1)){
cout << "Error: Either the row or column is not within range of the board.\n";
// ask again (error: row in column not within range)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}
else if(board[row-1][column-1] != '*')
{
cout << "Error: The (row,column) is already occupied.\n";
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}else {
valid = true;
}}
board[row-1][column-1] = 'X';
drawBoard(board);
// Check if someone won or  if there is a tie
check_Winner(board);
// Ask player two to chose a location (row, column)
cout << "Player 2's turn:";

cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
// check if move is valid

//check if location has astericks and its between 0 thru 2
valid = false;
while (!valid)
{
//check if the move is within range.
if(!(row <= 3 && row >= 1 && column <= 3 && column >= 1)){
cout << "Error: Either the row or column is not within range of the board.\n";
// ask again (error: row in column not within range)
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}
else if(board[row-1][column-1] != '*')
{
cout << "Error: The (row,column) is already occupied.\n";
cout << "What is the row:?\n";
cin >> row;
cout << "What is the column?\n";
cin >> column;
}else
{
valid = true;
}
board[row-1][column-1] = 'O';
}
drawBoard(board);
// Check if someone won or  if there is a tie
check_Winner(board);

}

system("pause");

return 0;
}
char check_Winner(char board[][3]){
char winner = 'T';

// Checks for horizontal:
for (int i = 0; i < 3; i++)
if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
winner = board[i][0];

// Checks for vertical:
for (int i = 0; i < 3; i++)
if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
winner = board[0][1];

// Checks for diagnol:
if ((board[0][0] == board[1][1] && board[1][1] == board[2][2]) ||
(board[0][2] == board[1][1] && board[1][1] == board[2][0]))
winner = board[1][1];

// checking the result:
switch (winner) {
case 'T': cout << "IT'S A TIE";/* tie */ break;
case 'X': cout << "PLAYER 1 WON!";/* X won */ break;
case 'O': cout << "PLAYER 2 WON!";/* O won */ break;
default : cout << "NEXT PLAYER'S TURN...>";
}
return winner;
}
void drawBoard(char board[][3])
{

cout << "     1   2   3" << endl;
cout << "   +---+---+---+" << endl;

cout << " 1" << " | " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

cout << " 2" << " | " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

cout << " 3" << " | " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << " | " << endl;
cout << "   +---+---+---+" << endl;

}

Постскриптум.

Я не эксперт по C ++ ни в какой степени воображения. Но люди, которые являются склонны настаивать на том, чтобы не использовать using namespace std;и вместо этого написать

std::cout << "hello world" << std::endl;

и т. д. По мере того, как ваш код усложняется, становится все более очевидным, какая функция / константа принадлежит какому классу. Итак, мне сказали … Смотрите Почему "используя пространство имен std" считается плохой практикой? . И вопрос, и ответ получили ОЧЕНЬ много голосов … предполагая, что это важная вещь, о которой думают люди. Читайте дальше принятого ответа … внизу этой страницы есть несколько жемчужин.

1

Другие решения

Могу ли я предложить вам использовать typedef для вашей доски?

typedef char tttboard[3][3];

Ваша доска объявлений:

tttboard board={{'*','*','*'},{'*','*','*'},{'*','*','*'}};

ваши функции будут выглядеть так: (по ссылке!)

 void drawBoard(tttboard& board);
char check_Winner(tttboard& board);

И, как вам сказали в комментарии, вы называете это без char а также [][] как это:

drawBoard(board);
check_Winner(board);
1

По вопросам рекламы [email protected]