//Проход по каждой клетки, которая может входить в ряд
for (int i = 0;i<5;i++)
{
//Проверка, не вышли ли за границы поля
if ((y-4+i) < 0) continue;
if ((x+4-i) > (size_x - 1)) continue;
if ((x-i) < 0) break;
if ((y+i) > (size_y - 1)) break;
//Проход по всем возможным рядам, отстоящим от клетки не более чем на 5
for (int j=0;j<5;j++)
{
if ((fields[x+4-i-j][y-4+i+j] != id) && (fields[x+4-i-j][y-4+i+j] != 0))
{
//Конец ряда
series_length = 0;
break;
}
if (fields[x+4-i-j][y-4+i+j] != 0) series_length++; //Ряд увеличивается
}
if (series_length == 1) series_length = 0; //Ряд из самой клетки не учитываем
if (series_length == 5) series_length = 100; //Выигрышная ситуация, ставим большое значение
//Плюсуем серию к общей сумме
unsigned long pow_st = valuation_factor;
if (series_length == 100)
{
if (id == 2)
pow_st = 10000;//Большое значение при своем выигрыше
else
pow_st = 1000; //Большое значение при выигрыше соперника, но меньшее, чем при своем
}
else
{
for (int i=0;i<series_length;i++)//Возводим оценочный коэффициент в степень длины серии
{
pow_st*=valuation_factor;
}
}
sum += pow_st;
series_length = 0;
}
//Возвращаем исходное значение
fields[x][y] = 0;
return sum;
}
//В меню нажата кнопка Новая игра
void CChildView::OnNewGame()
{
new_game(); //Функция начала новой игры
this->OnPaint();
this->Invalidate();
}
//Выбрано поле 10x10
void CChildView::OnX1010()
{
//Ставим галочку в меню
switch (size_x)
{
case 19:
set_chеcked_menu(ID_X1919,ID_X1010);
break;
case 30:
set_chеcked_menu(ID_X3030,ID_X1010);
break;
case 50:
set_chеcked_menu(ID_X5050,ID_X1010);
break;
case 100:
set_chеcked_menu(ID_X100100,ID_X1010);
break;
}
size_x = 10;
size_y = 10;
//Стартуем новую игру
new_game();
//Устанавливаем новые размеры окна
resize_window();
}
//Выбрано поле 19x19
void CChildView::OnX1919()
{
//Ставим галочку в меню
switch (size_x)
{
case 10:
set_chеcked_menu(ID_X1010,ID_X1919);
break;
case 30:
set_chеcked_menu(ID_X3030,ID_X1919);
break;
case 50:
set_chеcked_menu(ID_X5050,ID_X1919);
break;
case 100:
set_chеcked_menu(ID_X100100,ID_X1919);
break;
}
size_x = 19;
size_y = 19;
//Стартуем новую игру
new_game();
//Устанавливаем новые размеры окна
resize_window();
}
//Выбрано поле 19x19
void CChildView::OnX3030()
{
//Ставим галочку в меню
switch (size_x)
{
case 10:
set_chеcked_menu(ID_X1010,ID_X3030);
break;
case 19:
set_chеcked_menu(ID_X1919,ID_X3030);
break;
case 50:
set_chеcked_menu(ID_X5050,ID_X3030);
break;
case 100:
set_chеcked_menu(ID_X100100,ID_X3030);
break;
}
size_x = 30;
size_y = 30;
//Стартуем новую игру
new_game();
//Устанавливаем новые размеры окна
resize_window();
}
//Выбрано поле 50x50
void CChildView::OnX5050()
{
//Ставим галочку в меню
switch (size_x)
{
case 10:
set_chеcked_menu(ID_X1010,ID_X5050);
break;
case 19:
set_chеcked_menu(ID_X1919,ID_X5050);
break;
case 30:
set_chеcked_menu(ID_X3030,ID_X5050);
break;
case 100:
set_chеcked_menu(ID_X100100,ID_X5050);
break;
}
size_x = 50;
size_y = 50;
//Стартуем новую игру
new_game();
//Устанавливаем новые размеры окна
resize_window();
}
//Выбрано поле 100x100
void CChildView::OnX100100()
{
//Ставим галочку в меню
switch (size_x)
{
case 10:
set_chеcked_menu(ID_X1010,ID_X100100);
break;
case 19:
set_chеcked_menu(ID_X1919,ID_X100100);
break;
case 30:
set_chеcked_menu(ID_X3030,ID_X100100);
break;
case 50:
set_chеcked_menu(ID_X5050,ID_X100100);
break;
}
size_x = 100;
size_y = 100;
//Стартуем новую игру
new_game();
//Устанавливаем новые размеры окна
resize_window();
}
//Функция начала новой игры
void CChildView::new_game()
{
if ((old_size_x != 0) || (old_size_y != 0))
{
//Освобождаем память динамических массивов
try
{
for (int i=0;i<old_size_x;i++)
{
delete fields[i];
delete calc_fields[i];
}
delete fields;
delete calc_fields;
}
catch(...)
{
this->MessageBox(CA2T("Ошибка работы с памятью"),0,0);
this->CloseWindow();
}
}
//Присваиваем старым значениям новые
old_size_x = size_x;
old_size_y = size_y;
//Выделяем память под массивы
try
{
fields = new unsigned char*[size_x];
calc_fields = new float*[size_x];
for(int i=0;i<size_x;i++)
{
fields[i] = new unsigned char[size_y];
calc_fields[i] = new float[size_y];
}
}
catch(...)
{
this->MessageBox(CA2T("Ошибка выделения памяти"),0,0);
this->CloseWindow();
}
//Обнуляем массивы
for (int i=0;i<size_x;i++)
for (int j=0;j<size_y;j++)
{
fields[i][j] = 0;
}
//Сбрасываем флаг начала игры
end_game = false;
//Проверяем, не должен ли компьютер ходить первым
if (!player_first_step)
ii();
}
//Установка новых размеров окна
void CChildView::resize_window()
{
//Устанавливаем размеры окна в соответствии с размером поля
RECT Rect;//Размеры внутренней области
RECT WindowRect;//Размеры окна
this->GetWindowRect(&Rect);
this->GetParent()->GetWindowRect(&WindowRect);
this->GetParent()->MoveWindow(WindowRect.left,WindowRect.top,
size_y*15 + 4 + (WindowRect.right - Rect.right) + (Rect.left - WindowRect.left),
size_x*15 + 4 + (WindowRect.bottom - Rect.bottom) + (Rect.top - WindowRect.top),1);
}
//Установка галочки в меню
void CChildView::set_chеcked_menu(unsigned int old_id,unsigned int new_id)
{
//Создаем структуру элемента меню
MENUITEMINFO menuItemInfo;
menuItemInfo.cbSize = sizeof(MENUITEMINFO);
menuItemInfo.fMask = MIIM_STATE;//Работа с состоянием элемента
//Получаем указатель на меню
CMenu *pMenu=this->GetParent()->GetMenu();
//Ставим галочку в новом элементе
menuItemInfo.fState = MFS_CHECKED;
pMenu->SetMenuItemInfoW(new_id,&menuItemInfo,0);
//Снимаем галочку в старом элементе
menuItemInfo.fState = MFS_UNCHECKED;
pMenu->SetMenuItemInfoW(old_id,&menuItemInfo,0);
return;
}
//Выбран первый ход человека
void CChildView::OnStepH()
{
//Ставим галочку в меню
if (player_first_step == false)
set_chеcked_menu(ID_STEP_C,ID_STEP_H);
player_first_step = true;
//Старт новой игры
new_game();
//Перерисовка окна
this->OnPaint();
this->Invalidate();
}
//Выбран первый ход компьютера
void CChildView::OnStepC()
{
//Ставим галочку в меню
if (player_first_step == true)
set_chеcked_menu(ID_STEP_H,ID_STEP_C);
player_first_step = false;
//Старт новой игры
new_game();
//Перерисовка окна
this->OnPaint();
this->Invalidate();
}
//Выбран уровень компьютера - новичок
void CChildView::OnLevelBeg()
{
//Ставим галочку в меню
if (comp_level == 0)
{
set_chеcked_menu(ID_LEVEL_PROF,ID_LEVEL_BEG);
}
else if (comp_level == 1)
{
set_chеcked_menu(ID_LEVEL_AMAT,ID_LEVEL_BEG);
}
comp_level = 2;
attack_factor = 1;
//Старт новой игры
new_game();
//Перерисовка окна
this->OnPaint();
this->Invalidate();
}
//Выбран уровень компьютера - любитель
void CChildView::OnLevelAmat()
{
//Ставим галочку в меню
if (comp_level == 2)
{
set_chеcked_menu(ID_LEVEL_BEG,ID_LEVEL_AMAT);
}
else if (comp_level == 0)
{
set_chеcked_menu(ID_LEVEL_PROF,ID_LEVEL_AMAT);
}
comp_level = 1;
attack_factor = 10;
//Старт новой игры
new_game();
//Перерисовка окна
this->OnPaint();
this->Invalidate();
}
//Выбран уровень компьютера - профессионал
void CChildView::OnLevelProf()
{
//Ставим галочку в меню
if (comp_level == 2)
{
set_chеcked_menu(ID_LEVEL_BEG,ID_LEVEL_PROF);
}
else if (comp_level == 1)
{
set_chеcked_menu(ID_LEVEL_AMAT,ID_LEVEL_PROF);
}
comp_level = 0;
attack_factor = 1;
//Старт новой игры
new_game();
//Перерисовка окна
this->OnPaint();
this->Invalidate();
7. Примеры выполнения программы
Примеры выполнения программы приведены на рисунках 2, 3, 4, 5.
Рисунок 2 – Вид окна программе при запуске.
Рисунок 3 – Игровая ситуация при игре на поле 30x30 на сложности любитель.
Рисунок 4 – Выигрыш компьютера при игре на сложности профессионал.
Рисунок 5 – Победа игрока при игре на сложности любитель на поле 30x30.
В ходе выполнения курсовой работы был разработан алгоритм действий компьютерного игрока при игре в крестики-нолики пять в ряд на бесконечном поле.
В ходе выполнения работы удалось добиться достаточно сильного уровня игры на сложности профессионал.
Разработанный алгоритм был реализован на языке C++ на платформе Microsoft Visual Studio 2008.
Список литературы
1. Арчер Т., Уайтчепел Э. Visual C++ .NET. Библия пользователя — Вильямс, 2007.
2. Либерти Д., Джонс Б. Освой самостоятельно C++ за 21 день. — Вильямс, 2007.
3. Материалы сайта http://www.firststeps.ru/mfc/steps.
4. Подбельский В.В. Язык C++. — М.:"Финансы и статистика", 2003.