Єдина Країна!

Головне меню

Наша кнопка

Українські уроки про ІТ

Друзі

Підтримка української армії


Головна Програмування - C++ Базовий курс програмування на С++. Урок 15. Хрестики-нулики. Feel and relax

Базовий курс програмування на С++. Урок 15. Хрестики-нулики. Feel and relax
Написав Joker   
Понеділок, 14 грудня 2015 11:11
Переглядів: 5950

 

Сьогодні ми вивчимо

1. Розв’язок д/з минулого уроку

2. Що робимо?ma

3. За роботу!

4. Проблеми

5. Повний код

 

 

Розв’язок д/з минулого уроку

1. Вам дано масив. Поміняйте місцями елементи з парними і непарними індексами.

#include <iostream>
#include <conio
#include <time
#include <stdlib
using namespace std;

int main()
{
	srand(time(NULL));
	system("color A");

	const short int size = 5;
	int a[size];

	cout<< "First array: " <<endl;
	for (int i = 0; i <size; ++i)
	{
		a[i] = rand() % 2000;
		cout<< a[i] << "\t";
	}
	cout<<endl;

	int *pB = &a[1];
	int *pE = &a[2];

	while(pB != &a[size-1])
	{
		swap(*pB, *pE);

		if (pE == &a[size - 1])
			break;
		pB += 2;
		pE += 2;
	}

	cout<< "\n" << "New array: " <<endl;
	for (int i(0); i<size; ++i)
		cout<< a[i] << "\t";

	_getch();
	return  0;
}


2. Вам дано два масиви x[a], y[b]. Створіть третій масив, який буде вміщати:

- елементи обох попередніх масивів
- їх спільні елементи

 

 
/*
Вам дано два масиви x[a], y[b]
1	елементи обох попередніх масивів
2	їх спільні елементи
*/
#include  <iostream>
#include  <conio
#include  <algorithm>
#include  <time
#include  <stdlib
#include  <vector>
using namespace std;

int main ()
{
	srand(time(NULL));
	system("color A");

	int a,b;
	cout<< "Enter a, b --> ";
	cin>> a >> b;

	int *x = new int [a];
	int *y = new int [b];

	int size = 2*a+b;
	int *z = new int [size];

	for (int i=0; i<size; ++i)
		z[i] = -1;

	cout<< "\nX array: ";
	for (int i=0; i<a; ++i)
	{
		x[i] = rand()%10;
		cout<< x[i] << "\t";
	}

	cout<< "\nY array: ";
	for (int i=0; i<b; ++i)
	{
		y[i] = rand()%10;
		cout<< y[i] << "\t";
	}

	cout<< "\nZ array: ";
	for (int i=0; i<a+b; ++i)
	{
		if (i<a)
			z[i] = x[i];

		if (i>=a && i<b+a)
			z[i] = y[i-a];
	}

	for (int i=0, c=0; i<a; ++i)
	{
		for (int j=0; j<b; ++j)
		{
			if (x[i] == y[j]) { 
				z[a+b+c] = x[i];
				c++;
			}
		}
	}

	for (int i=0; i<size; ++i)
	{
		if (z[i] != -1)
		cout<< z[i] << "\t";
	}
	cout<<endl;

	delete[] x;
	delete[] y;
	delete[] z;

	_getch();
	return  0;
}


 

Що робимо?

У цьому уроці ми не будемо вивчати нічого нового (майже нічого). Я вирішив дещо узагальнити знання отримані з попередніх уроків у одному проекті. Цим проектом буде дуже примітивна гра. Ми спробуємо написати хрестики-нулики. Думаю, вам варто знову припинити читання статті і написати їх самим! До речі, найкращі ідеї приходять до голови під час відпочинку. Подивіться на що ви здатні. Ніхто не заперечує, що у вас може получитися краще ніж у мене, я теж вчуся.

 

За роботу!

Спершу потрібно визначити, що наша програма-гра буде робити. Думаю, що важко грати хрестики-нулики без таблиці. Давайте зробимо функцію яка буде виводити на екран таблицю і ті клітинки, що вже заповненні.  В мене цей код виглядає так:

void Show_Matrix (charTable[][size])
{
    // system("cls");

	for (int i=1; i<size; ++i)
    	{
		for (int j = 1; j<size; ++j)
	        {
			cout<<Table[i][j] << ' ';
		       j<3 ? cout<< '|' : cout<<endl;
	        }
		if(i<3)cout<< "--|--|--" <<endl;
	}
}

 

В ній є масив Table[][size]. size – розмір масиву, дорівнює  4. Саме цей масив буде заповнюватися O та X. Нагадаю, що у функціях не обов’язково вказувати розмір у перших дужках.

Тепер треба подумати як ми будемо здійснювати ходи. Наш масив виглядає так:

Я вирішив, що буду вводити номер клітинки, використовуючи цифри у жовтому квадратику. Перший рядок і перший стовпець я абсолютно не використовую.

Ще на початку програми я написав функцію яка повідомить гравця, як правильно здійснювати хід. Код:

void Logo ()
{
	cout<< "11|12|13" <<endl;
	cout<< "--|--|--" <<endl;
	cout<< "21|22|23" <<endl;
	cout<< "--|--|--" <<endl;
	cout<< "31|32|33" <<endl; 
}

Тепер найважливіше. Ми повинні ходити. Не важко здогадатися, що у найгіршому випадку ми здійснимо 9 ходів. Першим у нашій грі буде здійснювати хід завжди гравець, і завжди хрестики ходять першими. Через це всі ходи можна реалізувати за допомогою такого циклу. Частина коду:

do{
	if (count%2)
	{
		system("cls");
		Show_Matrix(Table);
		cout<< "\n" << "Хiд комп'ютер: ";
		move = PC_move(Table);
		cout<<move<<endl;
		Show_Matrix(Table);
	}
	else
	{
		cout<< "\n" << "Хiд гравця --> ";
		cin>>move;
		Check_free(Table, move);
		Table[move/10][move%10] = 'X';
	}
	count++;
              // Інший код
             …
             
}while (count< (size-1)*(size-1));

Добре тепер ми можемо ходити. Але тут ми зустріли ще декілька функцій. Першою є PC_move. Ця функція вираховує хід комп’ютера. Вона виглядає так:

int PC_move (charTable[][size])
{

    	// Горизонталь
    	int count = 0, key;
	for (int i=1; i<size; ++i)
	{
		for (int j=1; j<size; ++j)
	        {
			if (Table[i][j] == 'O')
				count++;
			else
				key = i*10+j;
	        }
		if (count == 2 &&Table[key/10][key%10] ==' ')  
	       {
			Table[key/10][key%10] = 'O';
			return key;
	       }
		count = 0;
    	}

    // Вертикаль

	for (int i=1; i<size; ++i)
	{
		count = 0, key = 0;
		for (int j=1; j<size; ++j)
	        {
			if (Table[j][i] == 'O')
				count++;
			else
				key = j*10+i;
	        }
		if (count == 2 &&Table[key/10][key%10] ==' ')  
	       {
			Table[key/10][key%10] = 'O';
			return key;
	       }
	}
    // Діагональ
	for (int i=1; i<size; ++i)
	{
		count = 0, key = 0;
		if (Table[i][i] == 'O')
			count++;
		else
			key = i*10+i;
	}
	if (count == 2 &&Table[key/10][key%10] ==' ')  
        {
		Table[key/10][key%10] = 'O';
		return key;
        }
	for (int i = 1, j = 3; i<size&& j>0; ++i, --j)
	{
		count = 0, key = 0;
		if (Table[i][j] == 'O')
			count++;
		else
			key = i*10+j;
	}
	if (count == 2 &&Table[key/10][key%10] ==' ')  
        {
		Table[key/10][key%10] = 'O';
		return key;
        }

    // Безвихідь
	for (int i=1; i<size; ++i)
    	{
		for (int j=1; j<size; ++j)
	        {
			if (Table[i][j] == ' ')
		        {
				Table[i][j] = 'O';
				return  i*10+j;
		         }
	        }
    	}
	return  -1;
}


Думаю, ви замітили, що наш бот дурний як дошка. По-перше, він довго думає через таку велику к-сть циклів. По-друге, він не вміє оборонятися. В ситуації наведеній на картинці він обере варіант «безвихідь» і поставить нуль в 1 ряд, 3 клітинку. Ну але він працює, що хоча б трішки радує.

Наступна функція Check_free. Її робота заключається у тому, щоб перевірити вміст клітинки і заблокувати роботу програми, коли гравець намагається заповнити вже використану клітинку.

Код:

int Check_free (charTable[][size], int &move)
{
	while (!(Table[move/10][move%10] == ' '))
    	{
		cerr<< "Вибачте, дана клiтинка вже занята!" <<endl;
		cout<< "Ваш хiд --> ";
		cin>>move;
	}
	return move;
}

Цикл використано не даремно. Звісно ми могли використати звичайну конструкцію if, але вона б працювала тільки один раз, що не гарантує повної безпеки.

Нам залишилося визначити переможця. Це я робив за допомогою функції Check.

Код:

int Check (charTable[][size])  // 1 - перемога хрестикiв | -1 - перемога нуликiв | 0 - без перемоги
{
    // Горизонталь
    int temp_X = 0, temp_O = 0;
    for (int i=1; i<size; ++i)
    {
         for (int j=1; j<size; ++j)
        {
            if (Table[i][j] == 'X')
                temp_X++;
            if (Table[i][j] == 'O')
                temp_O++;
        }

        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;

        temp_O = temp_X = 0;
    }

    // Вертикаль
    temp_O = temp_X = 0;
    for (int i=1; i<size; ++i)
    {
         for (int j=1; j<size; ++j)
        {
             if (Table[j][i] == 'X')
                 temp_X++;
             if (Table[j][i] == 'O')
                 temp_O++;
        }

        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;

        temp_O = temp_X = 0;
    }


    // Дiагоналi
    temp_O = temp_X = 0;
    for (int i=0; i<size; ++i)
    {
        if (Table[i][i] == 'X')
             temp_X++;
        if (Table[i][i] == 'O')
             temp_O++;
    }
    if (temp_O == 3)
        return  -1;
    if (temp_X == 3)
        return  1;


    temp_O = temp_X = 0;
    for (int i=1, j=3; i<size&& j>0; ++i, --j)
    {
         if (Table[i][j] == 'X')
             temp_X++;
         if (Table[i][j] == 'O')
             temp_O++;
    }
    if (temp_O == 3)
        return  -1;
    if (temp_X == 3)
        return  1;

return  0;
}


Її код дуже схожий на той, що ж у функції PC_move. Перемога досягається, коли буде знайдено 3 однакові символи в певній послідовності. Дивлячись на значення яке повертає функція ми визначаємо переможця. Це вже у main. Ось повний код ф-ції main():

int main ()
{
	system ("color A");
	setlocale (LC_CTYPE, "ukr");

	char Table[size][size];

	for (int i=0; i<size; ++i)
	{
		for (int j=0; j<size; ++j)
			Table[i][j] = ' ';
	}

	int move, count = 0;

	Logo();

	do{
		if (count%2)
		{
			system("cls");

			Show_Matrix(Table);
			cout<< "\n" << "Хiд комп'ютер: ";
			move = PC_move(Table);
			cout<< move  <<endl;
			Show_Matrix(Table);
		}
		else
		{
			cout<< "\n" << "Хiд гравця --> ";
			cin>> move;
			Check_free(Table, move);
			Table[move/10][move%10] = 'X';
		}

	count++;
	//Show_Matrix(Table);

	//Перевiрка перемоги
	if (Check(Table) == 1)
	{
		system("cls");
		clog<< "\n\nПеремiг гравець!!!" <<endl;
		Show_Matrix(Table);

		_getch();
		return  0;
	}
	else if (Check(Table) == -1)
	{
		system("cls");
		clog<< "\n\nПеремiг комп'ютер!!!" <<endl;
		Show_Matrix(Table);

		_getch();
		return  0;
	}
	else
	{}

	}while (count < (size-1)*(size-1));

	system("cls");
	Show_Matrix(Table);
	clog<< "\n\n" << "Нiчия!!! " <<endl;

	_getch();
	return  0;
}


Все, програма майже готова. Через велику к-сть функції я вирішив розділити код по двох окремих документах. Всі функції будуть зберігатися у файлі func.h , а ф-ція main у файлі main.cpp. Саме main.cpp є основним і він повинен мати підключення до func.h. Для цього потрібно, щоб обидва файли були у одній папці. Далі просто додаємо його за допомогою include. Ось так:

#include "func.h"

 

Проблеми

Наша гра досить далека від досконалості. Декілька із проблем:

- Бот грає не оптимально і довго думає. У інтернеті можна знати стратегію гри, і навчити бота грати за нею.
- Мало кому подобається грати у cmd (командному рядку), але ми поки що не вміємо робити щось цікавіше.
- Ввід клітинок теж не комільфо.  Карл Дуглас придумав комп’ютерну мишку ще у 1964.
- Гравець може грати тільки з ботом.
- Гравець ходить завжди першим.

Все починається з малого!

 

Повний код

На випадок, якщо ви не зрозуміли щось вище і хотіли б все попробувати. Ось повний код:

- main.cpp

#include <iostream>
#include <conio.h>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cstring>
#include  "func.h"
#define size 4
using namespace std;


int main ()
{
    system ("color A");
    setlocale (LC_CTYPE, "ukr");

    charTable[size][size];

    for (int i=0; i<size; ++i)
   {
	for (int j=0; j<size; ++j)
		Table[i][j] = ' ';
   }

   int move, count = 0;

   Logo();

   do{
	if (count%2)
	{
		system("cls");

		Show_Matrix(Table);
		cout<< "\n" << "Хiд комп'ютер: ";
		move = PC_move(Table);
		cout<<move<<endl;
		Show_Matrix(Table);
	}
	else
	{
		cout<< "\n" << "Хiд гравця --> ";
		cin>>move;
		Check_free(Table, move);
		Table[move/10][move%10] = 'X';
	}

       count++;
       //Show_Matrix(Table);

       //Перевiрка перемоги
      if (Check(Table) == 1)
      {
	   system("cls");
	   clog<< "\n\nПеремiг гравець!!!" <<endl;
	   Show_Matrix(Table);

	  _getch();
	return  0;
      }
      elseif (Check(Table) == -1)
      {
	   system("cls");
	   clog<< "\n\nПеремiг комп'ютер!!!" <<endl;
	   Show_Matrix(Table);

	   _getch();
           return  0;
      }
      else
      {}

    }while (count< (size-1)*(size-1));

    system("cls");
    Show_Matrix(Table);
    clog<< "\n\n" << "Нiчия!!! " <<endl;

   _getch();
   return  0;
}


 

- func.h

 

 
#include  <iostream>
#define  size 4
using namespace std;

void  Logo ()
{
cout<< "11|12|13" <<endl;
cout<< "--|--|--" <<endl;
cout<< "21|22|23" <<endl;
cout<< "--|--|--" <<endl;
cout<< "31|32|33" <<endl; 
}

int Check_free (char Table[][size], int &move)
{
    while (!(Table[move/10][move%10] == ' '))
    {
         cerr<< "Вибачте, дана клiтинка вже занята!" <<endl;
         cout<< "Вашхiд --> ";
         cin>> move;
    }
    return  move;
}

void  Show_Matrix (char Table[][size])
{
    // system("cls");

    for (int i=1; i<size; ++i)
    {
        for (int j = 1; j<size; ++j)
        {
            cout<< Table[i][j] << ' ';
            j<3 ?cout<< '|' : cout<<endl;
        }
        if(i<3)cout<< "--|--|--" <<endl;
    }
}

int PC_move (char Table[][size])
{


    // Горизонталь
    int count = 0, key;
    for (int i=1; i<size; ++i)
    {
        for (int j=1; j<size; ++j)
        {
            if (Table[i][j] == 'O')
                count++;
            else
                key = i*10+j;
        }
        if (count == 2 && Table[key/10][key%10] ==' ')  
            {
                Table[key/10][key%10] = 'O';
                return  key;
            }
        count = 0;
    }

    // Вертикаль

    for (int i=1; i<size; ++i)
    {
        count = 0, key = 0;
        for (int j=1; j<size; ++j)
        {
            if (Table[j][i] == 'O')
                count++;
            else
                key = j*10+i;
        }
        if (count == 2 && Table[key/10][key%10] ==' ')  
            {
                Table[key/10][key%10] = 'O';
                return  key;
            }   }
    // Діагональ
    for (int i=1; i<size; ++i)
    {
        count = 0, key = 0;
        if (Table[i][i] == 'O')
            count++;
        else
            key = i*10+i;
    }
        if (count == 2 && Table[key/10][key%10] ==' ')  
            {
                Table[key/10][key%10] = 'O';
                return  key;
            }
    for (int i = 1, j = 3; i<size && j>0; ++i, --j)
    {
        count = 0, key = 0;
        if (Table[i][j] == 'O')
            count++;
        else
            key = i*10+j;
    }
        if (count == 2 && Table[key/10][key%10] ==' ')  
            {
                Table[key/10][key%10] = 'O';
                return  key;
            }

    // Безвихідь
    for (int i=1; i<size; ++i)
    {
        for (int j=1; j<size; ++j)
        {
            if (Table[i][j] == ' ')
            {
                Table[i][j] = 'O';
                return  i*10+j;
            }
        }
    }
    return  -1;
}

int Check (char Table[][size])  // 1 – перемога хрестикiв | -1 – перемога нуликiв | 0 – без перемоги
{
    // Горизонталь
    int temp_X = 0, temp_O = 0;
    for (int i=1; i<size; ++i)
    {
        for (int j=1; j<size; ++j)
        {
            if (Table[i][j] == 'X')
                temp_X++;
            if (Table[i][j] == 'O')
                temp_O++;
        }

        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;

        temp_O = temp_X = 0;
    }

    // Вертикаль
    temp_O = temp_X = 0;
    for (int i=1; i<size; ++i)
    {
        for (int j=1; j<size; ++j)
        {
            if (Table[j][i] == 'X')
                temp_X++;
            if (Table[j][i] == 'O')
                temp_O++;
        }

        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;

         temp_O = temp_X = 0;
    }


    // Дiагоналi
     temp_O = temp_X = 0;
    for (int i=0; i<size; ++i)
    {
        if (Table[i][i] == 'X')
             temp_X++;
        if (Table[i][i] == 'O')
             temp_O++;
    }
        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;


    temp_O = temp_X = 0;
    for (int i=1, j=3; i<size && j>0; ++i, --j)
    {
        if (Table[i][j] == 'X')
              temp_X++;
        if (Table[i][j] == 'O')
              temp_O++;
    }
        if (temp_O == 3)
            return  -1;
        if (temp_X == 3)
            return  1;

    return  0;
}


Оскільки ми просто частково узагальнили наші знання, то вправ для перевірки не буде!

Я не проти вдосконалити нашу гру, можемо обговорити проблеми і шляхи їх вирішення у коментарях.


( 10 Проголосувало )

Схожі статті:
Новіші матеріали:
Старіші матеріали:

Коментарі
Добавити новий
Залишити коментар
Ім`я:
e-mail:
 
Тема:
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 
Введіть цей настирливий код
Русская редакция: www.freedom-ru.net & www.joobb.ru

3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."

 

Підписка

Хто онлайн?

Немає
На даний момент 36 гостей на сайті

Український рейтинг
TOP.TOPUA.NET