Внимание: не для слабонервных! Сложный алгоритм и такая же реализация :-(
Смысл вопроса:
в моём коде (в некой функции, которая будет ниже) есть такой фрагмент кода
if (y + 2 < SIZE && x - 1 >= 0 && way[step_num - 1].blocked < 2
&& field[x - 1][y + 2] == false)
{
way[step_num].y = way[step_num - 1].y + 2;
way[step_num].x = way[step_num - 1].x - 1;
way[step_num].setedByWay = 2;
field[x - 1][y + 2] = true;
chessIsMoved = true;
}
else if (y - 2 >= 0 && x + 1 < SIZE && way[step_num - 1].blocked < 3
&& field[x + 1][y - 2] == false)
{
way[step_num].y = way[step_num - 1].y - 2;
way[step_num].x = way[step_num - 1].x + 1;
way[step_num].setedByWay = 3;
field[x - 1][y + 2] = true;
chessIsMoved = true;
}
В второй строке есть выражение на проверку значения элемента двумерного массива (field[x - 1][y + 2] == false). Но иногда во время проверки этого выражения программа выходит за границы массива и выдаёт ошибку. Получается нужно как-то разделить выражение (сделать последовательность проверки выражений). Но как? Если внести последнее выражение в тело if-a, то при возврате false не получится перейти к следующей проверке выражений (думаю не стоит использовать метки, ибо потом больно и стыдно будет смотреть на код). Если убрать else перед следующим ветвлением и всё-таки добавить метки (или попробовать решить эту проблему через switch), то нарушится логика приложения и с высокой вероятностью может выполниться не то действие, которое мне нужно.
Итак, а теперь что, как и зачем я хочу сделать.
Задание:
Дана шахматная доска размером 8х8 и шахматный конь. Программа
должна запросить у пользователя координаты клетки поля и поставить
туда коня. Задача программы найти и вывести путь коня, при котором
он обойдет все клетки доски, становясь в каждую клетку только один
раз. (Так как процесс отыскания пути для разных начальных клеток
может затянуться, то рекомендуется сначала опробовать задачу на
поле размером 6х6). В программе необходимо использовать рекурсию.
Весь код:
#include <iostream>
#include <conio.h>
#define SIZE 6//6x6 - размер доски
using namespace std;
struct coords {
short x;
short y;
short blocked = 0;//неверное направление пути
short setedByWay = 0;//направление, по которому конь переместился на данные координаты //(используется для отката)
/*
Направления:
1 - down(2)->right(1)
2 - down(2)->left(1)
3 - up(2)->right(1)
4 - up(2)->left(1)
5 - down(1)->right(2)
6 - down(1)->left(2)
7 - up(1)->right(2)
8 - up(1)->left(2)
*/
};
void getX(short* x);
void getY(short* y);
void setWay(coords* way, bool field[][SIZE], short step_num = 1);
bool setStep(coords* way, bool** field, short step_num);
void main()
{
short x, y;//кординаты, по которым изначально ставится конь на доске
coords way[SIZE*SIZE+1];//кординаты, по которым будет передвигаться конь
bool field[SIZE][SIZE] = { false };//отображение заполнённости игрового поля (false - ячейка свободна, true - на данной ячейке был конь)
getX(&x);
getY(&y);
while (x >= SIZE)
{
cout << "x must be <" << SIZE << '\n';
getX(&x);
}
while (y >= SIZE)
{
cout << "y must be <" << SIZE << '\n';
getY(&y);
}
//установка коня на начальную позицию (начало пути)
way[0].x = x;
way[0].y = y;
setWay(way, field);
for (short i = 0; i < SIZE*SIZE + 1; i++)
cout << way[i].x << '\t' << way[i].y << endl;
/*while ()
{
setStep(way, step_num);
}*/
_getch();
}
void getX(short* x)
{
cout << "x->";
cin >> *x;
}
void getY(short* y)
{
cout << "y->";
cin >> *y;
}
//записывает путь перемещения коня по доске в массив way
//step_num - номер перемещения (максимум SIZE^2) (индекс в массиве way), ибо 1 выполнение функции - 1 перемещение
void setWay(coords* way, bool field[][SIZE], short step_num)
{
//координаты, на которых сейчас стоит конь (с которых нужно сделать переход)
short y = way[step_num - 1].y;
short x = way[step_num - 1].x;
bool chessIsMoved = false;//true даёт разрешение на следующее перемещение коня
//если нету выхода за границы поля и данный путь (с каждой проверкой увеличивается значение) не заблокирован
//и поле, на которое планируется переход, нетронутое
if (y + 2 < SIZE && x + 1 < SIZE && way[step_num - 1].blocked < 1
&& field[x + 1][y + 2] == false)
{
//запись координат в путь
way[step_num].y = way[step_num - 1].y + 2;
way[step_num].x = way[step_num - 1].x + 1;
//установка пути, по которому выполнен переход на данную ячейку
way[step_num].setedByWay = 1;
//метка "ячейка занята"
field[x + 1][y + 2] = true;
//переход к следующему перемещению
chessIsMoved = true;
}
else if (y + 2 < SIZE && x - 1 >= 0 && way[step_num - 1].blocked < 2
&& field[x - 1][y + 2] == false)
{
way[step_num].y = way[step_num - 1].y + 2;
way[step_num].x = way[step_num - 1].x - 1;
way[step_num].setedByWay = 2;
field[x - 1][y + 2] = true;
chessIsMoved = true;
}
else if (y - 2 >= 0 && x + 1 < SIZE && way[step_num - 1].blocked < 3
&& field[x + 1][y - 2] == false)
{
way[step_num].y = way[step_num - 1].y - 2;
way[step_num].x = way[step_num - 1].x + 1;
way[step_num].setedByWay = 3;
field[x - 1][y + 2] = true;
chessIsMoved = true;
}
else if (y - 2 >= 0 && x - 1 >= 0 && way[step_num - 1].blocked < 4
&& field[x - 1][y - 2] == false)
{
way[step_num].y = way[step_num - 1].y - 2;
way[step_num].x = way[step_num - 1].x - 1;
way[step_num].setedByWay = 4;
field[x - 1][y + 2] = true;
chessIsMoved = true;
}
else if (y + 1 < SIZE && x + 2 < SIZE && way[step_num - 1].blocked < 5
&& field[x + 2][y + 1] == false)
{
way[step_num].y = way[step_num - 1].y + 1;
way[step_num].x = way[step_num - 1].x + 2;
field[x + 2][y + 1] = true;
way[step_num].setedByWay = 5;
chessIsMoved = true;
}
else if (y + 1 < SIZE && x - 2 >= 0 && way[step_num - 1].blocked < 6
&& field[x - 2][y + 1] == false)
{
way[step_num].y = way[step_num - 1].y + 1;
way[step_num].x = way[step_num - 1].x - 2;
way[step_num].setedByWay = 6;
field[x - 2][y + 1] = true;
chessIsMoved = true;
}
else if (y - 1 >= 0 && x + 2 < SIZE && way[step_num - 1].blocked < 7
&& field[x + 2][y - 1] == false)
{
way[step_num].y = way[step_num - 1].y - 1;
way[step_num].x = way[step_num - 1].x + 2;
way[step_num].setedByWay = 7;
field[x + 2][y - 1] = true;
chessIsMoved = true;
}
else if (y - 1 >= 0 && x - 2 >= 0 && way[step_num - 1].blocked < 8
&& field[x - 2][y - 1] == false)
{
way[step_num].y = way[step_num - 1].y - 1;
way[step_num].x = way[step_num - 1].x - 2;
way[step_num].setedByWay = 8;
field[x - 2][y - 1] = true;
chessIsMoved = true;
}
else //если нету свободных клеток, на которые можно переместиться, - блокировка данного пути,метка "данная клетка свободна" и откат (возврат на шаг назад)
{
way[step_num - 2].blocked = way[step_num - 1].setedByWay;
field[x][y] = false;
setWay(way, field, step_num - 1);
}
//if (way[SIZE*SIZE].x != way[0].x && way[SIZE*SIZE].y != way[0].y)//если все ходы выполнены, но конь стоит не в нужном месте
// setWay(way, field, step_num - 1);//откат
if (step_num == SIZE*SIZE && way[SIZE*SIZE].x != way[0].x && way[SIZE*SIZE].y != way[0].y)//полный возврат с рекурсии (ну и с функции) только при условии, если данная "итерация" - последняя и {конечная и начальная ячейки совпадают}
return;
if(chessIsMoved)
setWay(way, field, step_num + 1);
}
Когда-то гавнокодил на php и знаю, что в таких ситуациях неплохо использовать исключения, но мы это не проходили и сомневаюсь, что в c++ это будет решением.
PS: не судите строго - я только учусь (и да, это задание по процедурному программированию,а не ООП).