Сьогодні ми вивчимо
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;
}
Оскільки ми просто частково узагальнили наші знання, то вправ для перевірки не буде!
Я не проти вдосконалити нашу гру, можемо обговорити проблеми і шляхи їх вирішення у коментарях.
Схожі статті:
Новіші матеріали:
Старіші матеріали:
|