Форум программистов, компьютерный форум CyberForum.ru

Крестики-нолики - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.60
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
01.08.2013, 22:52     Крестики-нолики #1
Добрый вечер. Хочу попробовать написать свои крестики-нолики. Игру еще не дописал, но уже появилась следующая проблема. По идее, если я ввожу координаты 1 4 или 2 4, то должно вывести сообщение о неправильном вводе, на деле же символ просто переносится на следующую строку. В чем проблема?

Код
#pragma warning(disable:4996);
#include <iostream>
#include <conio.h>

using namespace std;

char matrix[3][3];

void init_matrix(); // инициализация матрицы
void display_matrix(); // нарисовать матрицу
void get_player_move(); // получить координаты
bool is_nothing(int, int); // проверить координаты

int main()
{
	setlocale(LC_ALL, "Russian");
	init_matrix();
	for (;;)
	{
		system("cls");
		display_matrix();
		get_player_move();
	}
	system("pause");
	return 0;
}

void init_matrix()
{
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			matrix[i][j] = ' ';
		}
	}
}

void display_matrix()
{
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << matrix[i][j] << ' ';
		}
		cout << endl;
	}
}

void get_player_move()
{
	int x, y;
	cout << "Введите координаты: ";
	cin >> x >> y;
	if (is_nothing(x, y)) // проверяем верны ли координаты
	{
		matrix[--x][--y] = 'X';
	}
	else
	{
		cout << "Неверный ход. " << endl;
		get_player_move(); // запрашиваем координаты еще раз
	}
}

bool is_nothing(int x, int y)
{
	return (matrix[--x][--y] == ' ') ? true : false; 
}
Добавлено через 1 минуту
И сразу же такой вопрос. Может кто нибудь натолкнет на мысль, как лучше было бы создать "интеллект" для компа, чтобы не просто рандомно тыкал 0.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.08.2013, 22:52     Крестики-нолики
Посмотрите здесь:

C++ Крестики нолики на С
Крестики-нолики C++
C++ Крестики-нолики
C++ Крестики Нолики
Крестики нолики C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nikitko_Cent
128 / 98 / 8
Регистрация: 27.10.2011
Сообщений: 629
Завершенные тесты: 2
01.08.2013, 23:03     Крестики-нолики #2
Цитата Сообщение от dima55501 Посмотреть сообщение
И сразу же такой вопрос. Может кто нибудь натолкнет на мысль, как лучше было бы создать "интеллект" для компа, чтобы не просто рандомно тыкал 0.
В общем так:
Первый ход делать в центр\углы

далее:
1. сканируешь игровое поле на наличие прямых (т.е. столбцов, строк или диагоналей) с двумя твоими (считай, что ты - компьютер) значками и пустой ячейкой. Если такая прямая есть - втыкай третий свой значек -> win
2. если таких прямых не оказалось, то аналогично ищи прямые с двумя вражескими значками и пустой ячейкой. Если нашел - то втыкай в эту пустую ячейку свой значек, дабы предотвратить проигрыш.
3.если и таких прямых не нашлось, то пихай свой значек рандомно с приоритетом в центр\углы

При такой стратегии в свое время при написании крестиков ноликов, я столкнулся с одной проблемой - игрок может поставить "ловушку", когда у него будет одновременно две предвыигрышные ситуации. Но рассмотреть этот частный случай не составит особого труда (в плане написания кода).

Пример самой ловушки:

O.X
.O.
X.X

Где игрок играет крестиками
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
01.08.2013, 23:10     Крестики-нолики #3
dima55501, почитай в интернете, там есть описания алгоритмов для ии в крестики-нолики, если правильно напишите, то сами никогда не выйграете).
1) Переписал бы уж так,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void get_player_move()
{
    int x, y;
    cout << "Введите координаты: ";
    cin >> x >> y;
    if (is_nothing(x, y)) // проверяем верны ли координаты
    {
        matrix[--x][--y] = 'X';
    }
    else
    {
        cout << "Неверный ход. " << endl;
        return get_player_move(); // запрашиваем координаты еще раз
    }
}
Или вообще:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void get_player_move()
{
    int x, y;
    cout << "Введите координаты: ";
    cin >> x >> y;
    while (!is_nothing(x, y))
    {
         cout << "Неверный ход. " << endl;
         cout << "Введите координаты: ";
         cin >> x >> y;
    }
    matrix[--x][--y] = 'X';
}
Всё таки вы тут не граф обходите. Решения с рекурсией элегантный, но ей злоупотреблять не надо.

Добавлено через 2 минуты
И проверка координат:
C++
1
2
3
4
5
6
bool is_nothing(int x, int y)
{
    if ((x > 3) || (y > 3) || (y < 0) || (x < 0))
        return false;
    return (matrix[--x][--y] == ' ') ? true : false; 
}
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
01.08.2013, 23:12  [ТС]     Крестики-нолики #4
Цитата Сообщение от Wolkodav Посмотреть сообщение
Всё таки вы тут не граф обходите. Решения с рекурсией элегантный, но ей злоупотреблять не надо.
Ну я вообще увидел код в книжке и пытаюсь по аналогии свой сделать. В чем минус использования рекурсии в моем случае?
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
01.08.2013, 23:16     Крестики-нолики #5
dima55501, в вашем, ну как минимум она у вас тут не совсем правильно была составлена. А так, ресурсы используемы при рекурсии больше. При очень глубоких рекурсиях комп запросто может повиснуть( особенно винда).
Какую проблему не решает?

Добавлено через 41 секунду
При каких координатах?
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
01.08.2013, 23:22  [ТС]     Крестики-нолики #6
Wolkodav, да не, я просто не сразу увидел Ваш вариант функции is_nothing(). А так вроде все работает, спасибо.
Nikitko_Cent
128 / 98 / 8
Регистрация: 27.10.2011
Сообщений: 629
Завершенные тесты: 2
01.08.2013, 23:24     Крестики-нолики #7
Имхо, насчёт рекурсии Wolkodav прав. Лично я придерживаюсь такого правила - если я вижу, что некую задачу можно решить без использования рекурсии (т.е. циклами), и это решение будет легко пониматься при чтении и не будет громоздким, то я использую именно это решение, т.к. рекурсия - более затратный и потенциально опасный метод решения задач, нередко приводящий к переполнению стека.
Не могу утверждать, что моя точка зрения абсолютно верная, но посоветую тебе придерживаться её
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
01.08.2013, 23:26  [ТС]     Крестики-нолики #8
Nikitko_Cent, спасибо, буду иметь ввиду.
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
01.08.2013, 23:29     Крестики-нолики #9
dima55501, практика была у меня очень печальная, не на С++, на питоне правда. Был сервер (web), надо был там короче с файлами работать. Как самый деловой сделал всё рекурсией ( а имеенно копирование), и в один прекрасный момент сервак не выдержал и рухнул( нагрузка было действительно неподъёмная), было пичально. С тех пор очень аккуратен с рекурсией.
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
01.08.2013, 23:31  [ТС]     Крестики-нолики #10
Wolkodav, нда... Не думал, что рекурсия так коварна.
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
01.08.2013, 23:33     Крестики-нолики #11
dima55501, да вообщем везде надо с головой подходить и стараться не особо по шаблону идти.
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
02.08.2013, 00:10  [ТС]     Крестики-нолики #12
В общем очередная проблема возникла Вроде программу дописал, условие проверки конца игры специально полностью списал из книги, а вот все равно где то есть ошибка. Заключается она в проверке окончания игры. Чтобы легче было проверять, ходы совершает только компьютер и выиграть он может в разных условиях, вот скрины:
1ый - нолики и в строке, и в столбце. Игра не закончилась вовремя.
2ой - нету 3ех ноликов ни в строке, ни в столбце.

Был бы очень благодарен за помощь.

Код
#pragma warning(disable:4996);
#include <iostream>
#include <conio.h>
#include <time.h>

using namespace std;

char matrix[3][3];

void init_matrix(); // инициализируем матрицу
void display_matrix(); // выводим матрицу на экран
void get_player_move(); // ход игрока
void get_comp_move(); // ход компьютера
bool is_nothing(int, int); // проверка правильности хода
char is_over(); // проверка конца игры

int main()
{
	srand(time(NULL));
	setlocale(LC_ALL, "Russian");
	char over = ' ';
	init_matrix();
	do
	{
		system("cls");
		display_matrix();
		/*get_player_move();
		over = is_over();
		if (over != ' ')
		{
			break;
		}*/
		get_comp_move();
		over = is_over();
	}
	while (over == ' ');
	system("cls");
	display_matrix();
	if (over == 'X')
	{
		cout << "Ты выиграл. " << endl;
	}
	else if (over == 'O')
	{
		cout << "Ты проиграл. " << endl;
	}
	system("pause");
	return 0;
}

void init_matrix()
{
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			matrix[i][j] = ' ';
		}
	}
}

void display_matrix()
{
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			cout << matrix[i][j] << ' ';
		}
		cout << endl;
	}
}

void get_player_move()
{
	int x, y;
	cout << "Введите координаты: ";
	cin >> x >> y;
	while (!is_nothing(x, y))
	{
		cout << "Неверный ход. " << endl;
		cout << "Введите координаты: ";
		cin >> x >> y;
	}
	matrix[--x][--y] = 'X';
}

void get_comp_move() // ставит О в случайную клетку
{
	int x, y;
	x = rand() % 3 + 1;
	y = rand() % 3 + 1;
	while (!is_nothing(x, y))
	{
		x = rand() % 3 + 1;
		y = rand() % 3 + 1;
	}
	matrix[--x][--y] = 'O';
}

bool is_nothing(int x, int y)
{
	if (x <= 0 || x > 3 || y <= 0 || y > 3) // если введены неверные координаты
	{
		return false;
	}
	return (matrix[--x][--y] == ' ') ? true : false; // если клетка уже занята
}

char is_over()
{
	int i;
	for (i = 0; i < 3; i++) // проверяем строки
	{
		if (matrix[i][0] == matrix[i][1] && matrix[i][0] == matrix[i][2])
		{
			return matrix[i][0];
		}
	}
	for (i = 0; i < 3; i++) // проверяем столбцы
	{
		if (matrix[0][i] == matrix[1][i] && matrix[0][i] == matrix[2][i])
		{
			return matrix[0][i];
		}
	}
	if (matrix[0][0] == matrix[1][1] && matrix[1][1] == matrix[2][2]) // проверяем главную диагональ
	{
		return matrix[0][0];
	}
	if (matrix[0][2] == matrix[1][1] && matrix[1][1] == matrix[2][0]) // проверяем побочную диагональ
	{
		return matrix[0][2];
	}
}
Миниатюры
Крестики-нолики   Крестики-нолики  
Wolkodav
 Аватар для Wolkodav
599 / 452 / 32
Регистрация: 18.09.2012
Сообщений: 1,685
02.08.2013, 23:28     Крестики-нолики #13
dima55501, ой, тут что-то намучено, завтра разберусь...
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
03.08.2013, 00:32     Крестики-нолики #14
Крестики-нолики для поля 3 на 3 всегда можно свести как минимум к ничьей. Вот вам наглядное дерево ходов. Кодируете его в каком-нибудь удобном виде с точностью до поворотов. При каждом ходе игрока подбираете поворотом состояние ячеек и делаете свой ход в соответствии с деревом.
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
03.08.2013, 00:47  [ТС]     Крестики-нолики #15
Wolkodav, ок, спасибо.
OhMyGodSoLong, да я сейчас даже не про ничью. Я про то, что в условии проверки конца игры есть ошибка, которую я никак не могу найти.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
03.08.2013, 04:20     Крестики-нолики #16
dima55501, Нашо ты еще координаты вводишь? Просто каждой ячейке присвой номер и выведи на экран
C++
1
2
3
0 1 2
3 4 5
6 7 8
Когда пользователь походит цифру заменяй на крестики или нолики так удобнее.
И что бы победителя определить тебе нужно после каждого хода делать 8 проверок: 3 строки, 3 столбца и две диагонали, можно в виде функции оформить, которая б осуществляла поиск по массиву, например у тебя б внутренняя реализация поле допустим int desk[3][3] инициализирован от 0 до 8 , хода первого игрока ты изменяешь нужную ячейку допустим на 100, хода второго игрока изменяешь нужную ячейку на 200, выводишь поле, где заменяешь 100 на крестик, а 200 на нолик или наоборот.
Создал бы ты функцию допустим bool winner(int) передаешь ей 100 она проверяет строки диагонали столбцы на предмет равенства соткам, затем можешь передать 200 тоже проверяет для двести, ну это что бы компактно было, что бы 2 функции не писать.

ИИ я думаю должен делать 8 проверок и искать где в строке не хватает одного крестика или одного нолика, если он находит такую строку то ставит туда крестик или нолик, тут в принципе также пишешь одну функцию, в которую передаешь нолик комп играет за нолик, он вначале делает 8 проверок в поисках двух нулей, что бы поставить третий и выиграть, если он не находит нули, то делает 8 проверок для крестиков в поисках двух крестиков что бы не дать выиграть вам, ну и если не находит ни двух крестиков, ни двух ноликов, то проверяешь ячейку под номером 5, то есть середину, свободна туда ставишь.
Для ИИ я думаю этого достаточно, можно еще доделать если не удалось поставить в середину, то стараться ставить на свободную либо диагональ, либо строку, столбец, что бы не занята была фишкой противника, но я думаю смысла в этом нету в любом случае центр сразу занимают, поэтому можно ставить где попало, да я думаю до этого условия программа не будет доходить, так как будут находится две занятые ячейки.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.08.2013, 10:49     Крестики-нолики
Еще ссылки по теме:

C++ Крестики-нолики
Крестики нолики C++
C++ Крестики нолики

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
dima55501
 Аватар для dima55501
29 / 33 / 6
Регистрация: 14.07.2013
Сообщений: 146
03.08.2013, 10:49  [ТС]     Крестики-нолики #17
ninja2, спасибо за идею, но это уже надо будет почти все переделывать. Мне бы хотелось доделать свой вариант, если это возможно.
Yandex
Объявления
03.08.2013, 10:49     Крестики-нолики
Ответ Создать тему
Опции темы

Текущее время: 13:13. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru