CodeInside
@CodeInside

Как вынести фрагмент условия?

Внимание: не для слабонервных! Сложный алгоритм и такая же реализация :-(
Смысл вопроса:
в моём коде (в некой функции, которая будет ниже) есть такой фрагмент кода
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: не судите строго - я только учусь (и да, это задание по процедурному программированию,а не ООП).
  • Вопрос задан
  • 324 просмотра
Пригласить эксперта
Ответы на вопрос 2
maaGames
@maaGames
Погроммирую программы
На самом деле данную проблему решают иначе. В шахматных числодробилках, как ив любых числодробилках, нужно стараться свести количество условий к минимуму. Вместо проверки выхода за границы матрицы (а это 4 проверки, либо две, если используются беззнаковые числа и переполнение), саму матрицу расширяют на единичку с каждой стороны и записывают туда флаговое или другое "блокирующее" значение.
Хотя, у вас проверка условий начинается с проверки выхода за границы массива и проблемы с ошибкой не должно было быть изначально... если бы не перепутали порядок в двумерном массиве. На самом деле field[y][x].
Ответ написан
Комментировать
@mamkaololosha
Это задача на "Поиск с возвратом, бэктрекинг". В условии же написано, что необходимо использовать рекурсию. Кешируйте пути. И когда некуда будет ходить завершайте работу. Потом проверяйте пути и ищите тот, в котором число посещенных клеток равно 6*6.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы