Странные шахматы как тестовое задание

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Добрый вечер хаброжители!

Сегодня я предоставлю вашему вниманию небольшую статью не связанную с моими предыдущими статьями. Где-то более года назад мне пришлось делать одно тестовое задание чтобы устроится на работу. Выполнил я его в срок, но конкуренция была большая и скорее всего взяли человека который сделал его с помощью рекомендованных технологий и красочнее.

Суть задачи, есть доска 8 на 8 клеток. У игрока есть 9 шашек они расположены в углу доски в квадрате 3 на 3, у противника тоже столько же шашек и они расположены симметрично по диагонали в другом углу в квадрате 3 на 3. Каждый игрок ходит по очереди, нужно дойти шашками на места изначального положения соперника через всю доску, кто первый дошел тот и победил. Ходить можно только на пустые клетки и только вверх, вниз, влево и вправо(по диагонали нельзя!).

Управление я добавил мышью, а играть против компьютерного алгоритма. Черные - человек, белые - ИИ.

Помимо всего прочего изначально необходимо отрисовать доску, шашки и делать манипуляции с полем.

Немного кода для наглядности:

Game::Game()
{
	run = true;//флаг признак нажатия кнопки выхода F5
	Matrix = new int* [8];//Поле 64 ячейки - значения 0 - для пустой ячейки, для игрока каждая пешка-шашка от 1 до 9, для компьютера значения в матрице от 10 до 18
	for (int i = 0; i < 8; i++)
		Matrix[i] = new int[8];
	//Квадраты координат нужны чтобы программа знала какие ячейки над указателем мыши, 64 квадрата
	QuadCoorXleft = new int* [8];//каждой ячейки матрицы Matrix соответстует квадрат координат для мыши xleft означает левую координату x
	QuadCoorXright = new int* [8];//xright - правая x
	QuadCoorYdown = new int* [8];//верхняя y координата
	QuadCoorYup = new int* [8];//нижняя y координата
	for (int i = 0; i < 8; i++)
	{
		QuadCoorXleft[i] = new int[8];
		QuadCoorXright[i] = new int[8];
		QuadCoorYdown[i] = new int[8];
		QuadCoorYup[i] = new int[8];
	}
	//Координаты пешек для отрисовки
	ChessX = new double[18];//X
	ChessY = new double[18];//Y
	//Выделяемая пешка ее координаты и значения
	ActiveX = -1;//X
	ActiveY = -1;//Y
	Active = -1;//Value
	firstplayer = true;//флаг того что можете игрок 1й ходить
	secondplayer = false;//флаг того что можете игрок 2й ходить
	ai = new bool[18];//ячейки флаги того что пешка на финишной позиции
	chessai tmp;
	for (int i = 0; i < 18; i++)
	{
		ai[i] = false;
		if (i > 8)
		{
			tmp.ai = ai[i];
			tmp.value = i+1;
			Ai.push_back(tmp);//Вектор с флагами финиша каждой пешки для искуственного интеллекта
		}
	}
	aicountfirstrow = 0;//счетчик кол-ва пешек ИИ(искуственного интеллекта) на верхней строчке(0-я)
	aicountsecondrow = 0;//счетчик кол-ва пешек ИИ на предверхней строчке(1-я)
	aicountthirdrow = 0;//счетчик кол-ва пешек ИИ на предпредверхней строчке(2-я)
}

Для отрисовки и захвата мыши используется библиотеки OpenGL и SDL2.

void Draw_Circle()
{
	//Отрисовка круга(пешек-шахмат) черного
	for (int i = 0; i <= 50; i++) {
		float a = (float)i / 50.0f * 3.1415f * 2.0f;
		glVertex2f(cos(a), sin(a));
	}
}
void Draw_Circle_Fill()
{
	//Отрисовка круга(пешек-шахмат) белого
	for (int i = 0; i <= 50; i++) {
		float a = (float)i / 50.0f * 3.1415f * 2.0f;
		glVertex2f(0.0, 0.0);
		glVertex2f(cos(a), sin(a));
	}
}

Самое удобное что можно использовать glTranslatef чтобы заполнить доску шашками с перемещениями

...
for (int i = 0; i < 9; i++)
		{
			glPushMatrix();
			glTranslatef(ChessX[i], ChessY[i], 0);
			glScalef(0.05, 0.05, 1);
			glBegin(GL_LINE_LOOP);
			Draw_Circle();
			glEnd();
			glPopMatrix();
		}
		//Рисуем белые пешки ИИ
		for (int i = 9; i < 18; i++)
		{
			glPushMatrix();
			glTranslatef(ChessX[i], ChessY[i], 0);
			glScalef(0.05, 0.05, 1);
			glBegin(GL_LINES);
			Draw_Circle_Fill();
			glEnd();
			glPopMatrix();
		}

...

Ходы игрока:

void Game::Move_Up()
{
	//Ход игрока вверх
	if (Active > 0 && ActiveX != 0 && Matrix[ActiveX-1][ActiveY] == 0)//Если выделенная пешка и не самая верхняя строчка и ячейка выше пустая
	{
		Matrix[ActiveX-1][ActiveY] = Matrix[ActiveX][ActiveY] ;//присваиваем ячейке выше текущюю(выделенную пешку)
		Matrix[ActiveX][ActiveY] = 0;//затираем старую ячейку на пустую 
		ChessY[Active-1] += 0.2;//перемещаем координату У пешки вверх для отрисовки
		ActiveX = -1;//стираем координаты выделенной пешки
		ActiveY = -1;//стираем координаты выделенной пешки
		Active = -1;//делаем неактивной текущую выделенную фигуру
		std::cout << " Player MoveUp " << Active << std::endl;
		firstplayer = false;
		secondplayer = true;//меняем флаги хода от игрока к ИИ
	}
}
void Game::Move_Down()
{
	//Ход игрока вниз
	if (Active > 0 && ActiveX != 7 && Matrix[ActiveX+1][ActiveY] == 0)//Если выделенная пешка и не самая нижняя строчка и ячейка ниже пустая
	{
		Matrix[ActiveX+1][ActiveY] = Matrix[ActiveX][ActiveY] ;//присваиваем ячейке ниже текущюю(выделенную пешку)
		Matrix[ActiveX][ActiveY] = 0;//затираем старую ячейку на пустую 
		ChessY[Active-1] -= 0.2;//перемещаем координату У пешки вниз для отрисовки
		ActiveX = -1;//стираем координаты выделенной пешки
		ActiveY = -1;//стираем координаты выделенной пешки
		Active = -1;//делаем неактивной текущую выделенную фигуру
		std::cout << "Player MoveDown " << Active << std::endl;
		firstplayer = false;
		secondplayer = true;//меняем флаги хода от игрока к ИИ
	}
}
void Game::Move_Right()
{
	//Ход игрока вправо
	if (Active > 0 && ActiveY != 7 && Matrix[ActiveX][ActiveY+1] == 0)//Если выделенная пешка и не самая правая строчка и ячейка справа пустая
	{
		Matrix[ActiveX][ActiveY+1] = Matrix[ActiveX][ActiveY] ;//присваиваем ячейке справа текущюю(выделенную пешку)
		Matrix[ActiveX][ActiveY] = 0;//затираем старую ячейку на пустую 
		ChessX[Active-1] += 0.2;//перемещаем координату Х пешки вправо для отрисовки
		ActiveX = -1;//стираем координаты выделенной пешки
		ActiveY = -1;//стираем координаты выделенной пешки
		Active = -1;//делаем неактивной текущую выделенную фигуру
		std::cout << "MoveRight " << Active << std::endl;
		firstplayer = false;
		secondplayer = true;//меняем флаги хода от игрока к ИИ
	}
}
void Game::Move_Left()
{
	//Ход игрока влево 
	if (Active > 0 && ActiveY != 0 && Matrix[ActiveX][ActiveY-1] == 0)//Если выделенная пешка и не самая левая строчка и ячейка слева пустая
	{
		Matrix[ActiveX][ActiveY-1] = Matrix[ActiveX][ActiveY] ;//присваиваем ячейке слева текущюю(выделенную пешку)
		Matrix[ActiveX][ActiveY] = 0;//затираем старую ячейку на пустую 
		ChessX[Active-1] -= 0.2;//перемещаем координату Х пешки влево для отрисовки
		ActiveX = -1;//стираем координаты выделенной пешки
		ActiveY = -1;//стираем координаты выделенной пешки
		Active = -1;//делаем неактивной текущую выделенную фигуру
		std::cout << "MoveLeft " << Active << std::endl;
		firstplayer = false;
		secondplayer = true;//меняем флаги хода от игрока к ИИ
	}
}

Ходы компьютера почти аналогичны ходам игрока, в конце будет ссылка на полный код игры, если кому интересно.

void Game::ReccurentWalk()
{
	//Реккурентный ход ИИ
	current = -1, currentI = -1, currentJ = -1;//изначально выделенная пешка не определена
	for (int i = 0; i < Ai.size(); i++)//поиск по массиву
		if (!Ai[i].ai)//если не завершены ходы для конкретных пешек
		{
			if (Check_MoveUp(Ai[i].value) || Check_MoveLeft(Ai[i].value))//Можно ли походить вверх или влево?
			{
				current = Ai[i].value;//запоминаем текущую пешку
				break;
			}
			else
			{
				//Если походить нельзя стираем из массива ходов пешку
				std::vector<chessai>::iterator position = std::find_if(Ai.begin(), Ai.end(), find_s(Ai[i].value));
				if (position != Ai.end()) // == vector.end() means the element was not found
					Ai.erase(position);
			}
		}
	for (int i = 0; i < 8; i++)
		for (int j = 0; j < 8; j++)
			if (Matrix[i][j] == current)//ищем в матрице пешку и запоминаем индексы
			{
				currentI = i;
				currentJ = j;
				break;
			}
	if (currentI != -1 && currentJ != -1)//если какая либо найдена ходим либо вверх либо влево
	{
		if (!Move_UpAI(currentI, currentJ))
			if (!Move_LeftAI(currentI, currentJ))
			{
				ReccurentWalk();
			}
	}
	else
	{
		//если не найдена заполняем массив ходов снова пешками
		chessai tmp;
		for (int i = 0; i < 18; i++)
		{
			ai[i] = false;
			if (i > 8)
			{
				tmp.ai = ai[i];
				tmp.value = i + 1;
				Ai.push_back(tmp);
			}
		}
		//ищем ту которая может походить вправо или вниз
		for (int i = 0; i < Ai.size(); i++)
			if (!Ai[i].ai)
			{
				if (Check_MoveRight(Ai[i].value) || Check_MoveDown(Ai[i].value))
				{
					current = Ai[i].value;
					break;
				}
				else
				{
					//если не может то стираем из массива
					std::vector<chessai>::iterator position = std::find_if(Ai.begin(), Ai.end(), find_s(Ai[i].value));
					if (position != Ai.end()) // == Vector.end() means the element was not found
						Ai.erase(position);
				}
			}
		//ищем ее индексы в матрице
		for (int i = 0; i < 8; i++)
			for (int j = 0; j < 8; j++)
				if (Matrix[i][j] == current)
				{
					currentI = i;
					currentJ = j;
					break;
				}
		//ходим вправо или вниз
		if(!Move_RightAI(currentI, currentJ))
			if (!Move_DownAI(currentI, currentJ))
			{
				std::cout <<"Artificial Intellegence asked: WTF?" << std::endl;
			}
	}
	chessai tmp;
	if(Ai.empty())//если список ходов пуст заполняем снова всеми
		for (int i = 0; i < 18; i++)
		{
			ai[i] = false;
			if (i > 8)
			{
				tmp.ai = ai[i];
				tmp.value = i + 1;
				Ai.push_back(tmp);
			}
		}
}

Ну и собственно опишу словами, что делает ИИ. Он собирает три пешки вверху на 0-ой строке и если ходить нельзя влево, то двигает вверх остальные 3 пешки на 1 строку, аналогично и на 2-ю строку. Если ходить влево и вверх нельзя, то он берет любую шашку и двигает либо вниз либо вправо если можно конечно, то есть стремится всегда двигать влево или вверх( при условии что выше меньше двух шашек в строке).

Ну собственно и геймплей:

https://youtu.be/XaQVeSKdQcs

И ссылка на исходный код:

https://github.com/Beginerok/DominiGames

Источник: https://habr.com/ru/post/563398/


Интересные статьи

Интересные статьи

Одна из самых важных (на мой взгляд) функций в Битрикс24 это бизнес-процессы. Теоретически они позволяют вам полностью избавиться от бумажных служебок и перенести их в эл...
Всем привет! Не так давно на работе в рамках тестирования нового бизнес-процесса мне понадобилась возможность авторизации под разными пользователями. Переход в соответствующий р...
Привет! Мы учимся на первом курсе бакалавриата «Прикладная математика и информатика» в Питерской Вышке. Во время работы над семестровым командным проектом по С++ мы решили написать...
Если в вашей компании хотя бы два сотрудника, отвечающих за работу со сделками в Битрикс24, рано или поздно возникает вопрос распределения лидов между ними.
Бизнес-смыслы появились в Битриксе в начале 2016 года, но мало кто понимает, как их правильно использовать для удобной настройки интернет-магазинов.