Ошибка в цикле проверки на уникальное значение
Для практики делаю крестики-нолики, когда проверяю ячейку, была ли она уже использована возникает проблема, если несколько раз подряд ввести уже использованную ячейку, а после новую, то ячейка всё равно отобразится как повторяющаяся
#include <iostream>
using namespace std;
void CheckMove(int cellNumber, int* usedCells, int turn, int player);
void FieldDraw(char* upArr, char* divArr, char* midArr, char* lowArr)
{
for (int i = 0; i < 9; i++)
{
cout << upArr[i];
}
cout << endl;
for (int i = 0; i < 9; i++)
{
cout << divArr[i];
}
cout << endl;
for (int i = 0; i < 9; i++)
{
cout << midArr[i];
}
cout << endl;
for (int i = 0; i < 9; i++)
{
cout << divArr[i];
}
cout << endl;
for (int i = 0; i < 9; i++)
{
cout << lowArr[i];
}
cout << endl;
}
void ChangePlayer(int &player)
{
if (player == 1)
player = 2;
else
player = 1;
}
void SymbChoice(char& FSymb, char& SSymb)
{
cout << "Player 1 Choose your symbol" << endl;
cin >> FSymb;
cout << "Player 2 Choose your symbol" << endl;
cin >> SSymb;
}
void AskMove(int player, int& cellNumber, int *usedCells, int turn)
{
cin >> cellNumber;
while (cin.fail())
{
cin.clear();
cin.ignore(100, '\n');
cin >> cellNumber;
}
CheckMove(cellNumber, usedCells, turn, player);
}
void CheckMove(int cellNumber, int *usedCells, int turn, int player)
{
if (cellNumber < 1 || cellNumber > 9)
{
cout << "Please use 1 - 9" << endl;
AskMove(player, cellNumber, usedCells, turn);
}
for (int i = 0; i < 8; i++)
{
if (cellNumber == usedCells[i])
{
cout << "This cell has been used, please choose another one" << endl;
AskMove(player, cellNumber, usedCells, turn);
}
}
usedCells[turn] = cellNumber;
}
void ChangeSymb(char FSymb, char SSymb, int cellNumber, int player, char* upArr, char* midArr, char* lowArr)
{
char symb;
if (player == 1)
symb = FSymb;
else
symb = SSymb;
switch (cellNumber)
{
case 1:
upArr[0] = symb;
break;
case 2:
upArr[4] = symb;
break;
case 3:
upArr[8] = symb;
break;
case 4:
midArr[0] = symb;
break;
case 5:
midArr[4] = symb;
break;
case 6:
midArr[8] = symb;
break;
case 7:
lowArr[0] = symb;
break;
case 8:
lowArr[4] = symb;
break;
case 9:
lowArr[8] = symb;
break;
}
}
int main()
{
int player = 1;
int turn = 0;
char FPSymb = 'X';
char SPSymb = '0';
bool victory = false;
int cellNumber = 0;
int usedCells [9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
char upArr[9] = { '1' , ' ' , '|' , ' ' , '2' , ' ' , '|' , ' ' , '3' };
char divArr[9] = { '=' , '=' , '=' , '=' , '=' , '=' , '=' , '=' , '=' };
char midArr[9] = { '4' , ' ' , '|' , ' ' , '5' , ' ' , '|' , ' ' , '6' };
char lowArr[9] = { '7' , ' ' , '|' , ' ' , '8' , ' ' , '|' , ' ' , '9' };
//SymbChoice(FPSymb, SPSymb);
while (!victory)
{
FieldDraw(upArr, divArr,midArr, lowArr);
if (player == 1)
cout << "PLayer 1 Enter the cell number" << endl;
else
cout << "PLayer 2 Enter the cell number" << endl;
AskMove(player, cellNumber, usedCells, turn);
ChangeSymb(FPSymb, SPSymb, cellNumber, player, upArr, midArr, lowArr);
ChangePlayer(player);
turn++;
}
return 0;
}
Ответы (1 шт):
Ну просто ошибка в сигнатурах функций.
void AskMove(, int& cellNumber, , )
void CheckMove(int cellNumber, , , )
И поскольку функции вызываются друг из друга, то получается крах.
Т.е. в AskMove передается ссылка на переменную из main, потом она в CheckMove передает по значению, а потом CheckMove передает в AskMove ссылку на локальную переменную внутри себя, а вовсе не ту, которая объявлена в main.
Но даже если это исправить, программа всё равно будет периодически рушиться. Перекрестный вызов функций друг из друга - это плохо. Код не читаемый, логика не понятна и не отслеживается. Рано или поздно будет переполнение стэка (stackoverflow) из-за множественного вложенного вызова функций.
Стиль плохой.
Если функция называется AskMove, то она должна только спрашивать.
Если функция называется CheckMove, то она должна проверять возможность хода и просто возвращать да/нет.
Что-то вроде:
bool CheckMove(int cellNumber, int *usedCells, int turn, int player)
{
bool State = true;
if (cellNumber < 1 || cellNumber > 9)
{
cout << "Please use 1 - 9" << endl;
State = false;
}
for (int i = 0; i < 8; i++)
{
if (cellNumber == usedCells[i])
{
cout << "This cell has been used, please choose another one" << endl;
State = false;
}
}
return State;
}
И тогда в main сделать цикл (спрашивать пока не будет введен корректный ход):
bool State = false;
while(!State)
{
AskMove();
State = CheckMove();
if(State) usedCells[turn] = cellNumber;
}
Таким образом - никаких перекрестных вызовов, линейное выполнение программы, логика работы понятна.
В дополнение - раз уж всё равно занята память под хранение признака заполненных ячеек usedCells, то проще проверять без цикла, в одну операцию - номер ячейки является индексом в массиве:
Установить, что ячейка занята:
usedCells[ cellNumber-1 ] = 1;
Проверка, что ячейка занята
if( usedCells[ cellNumber-1 ] )
{
}
И массив usedCells тогда можно сделать bool, a не int

