скачать рефераты
  RSS    

Меню

Быстрый поиск

скачать рефераты

скачать рефератыКурсовая работа: Программа "Крестики-нолики 5 в ряд на неограниченном игровом поле"

void CChildView::set_chеcked_menu(unsigned int old_id,unsigned int new_id) – Служит для снятия галочки и установки новой в главном меню при выборе размеров поля, уровня игры компьютера и очереднсоти хода.

Входные параметры:

unsigned int old_id – id элемента меню, с которого необходимо снять галочку;

unsigned int new_id – id элемента меню, на который необходимо поставить галочку;

Возвращаемое значение:

Нет.

Алгоритм работы:

Снимает галочку в главном меню с элемента, определяемого переменной old_id и ставит галочку на элемент, определяемый переменной new_id.

void CChildView::OnStepH() – В главном меню выбрана очередность хода – человек.

Входные параметры:

Нет.

Возвращаемое значение:

Нет.

Алгоритм работы:

Изменяется значение переменной player_first_step. Вызывается функция new_game для начала новой игры. Выполняется перерисовка окна.

void CChildView::OnStepС() – В главном меню выбрана очередность хода – компьютер.

Входные параметры:

Нет.

Возвращаемое значение:

Нет.

Алгоритм работы:

Изменяется значение переменной player_first_step. Вызывается функция new_game для начала новой игры. Выполняется перерисовка окна.

void CChildView::OnLevelBeg() – В главном меню выбран уровень сложности начинающий.

Входные параметры:

Нет.

Возвращаемое значение:

Нет.

Алгоритм работы:

Изменяется значение переменной comp_level. Значение коэффициента агрессивности игры компьютера attack_factor устанавливается в 1. Вызывается функция new_game для начала новой игры. Выполняется перерисовка окна.

void CChildView::OnLevelAmat() – В главном меню выбран уровень сложности любитель.

Входные параметры:

Нет.

Возвращаемое значение:

Нет.

Алгоритм работы:

Изменяется значение переменной comp_level. Значение коэффициента агрессивности игры компьютера attack_factor устанавливается в 1. Вызывается функция new_game для начала новой игры. Выполняется перерисовка окна.

5. Алгоритм работы программы

Алгоритм выполнения очередного хода:

Игрок выполняет очередной ход при нажатии левой кнопки мыши на игровом поле. При этом вызывается функция обработчика OnLButtonDown, которая содержит основной алгоритм выполнения очередного хода игроком и компьютером. Алгоритм работы функции приведен на рисунке 1.

Рисунок 1 – Блок-схема работы функции OnLButtonDown.


Алгоритм расчета очередного хода компьютерного соперника:

Расчет очередного хода компьютерного соперника выполняется при помощи вызова функции ii. Расчет производится при старте игры, если приоритет хода принадлежит компьютеру или после хода игрока вызовом из функции OnLButtonDown.

Расчет производится по следующему алгоритму:

1)         Рассчитывается суммарная оценочная функция  для всех непустых клеток игрового поля. Под оценочной функцией понимается некое значение, присваиваемое клетке и обозначающее выгодность хода в данную клетку.

Расчет производится при помощи функции calculate, которая позволяет рассчитать оценочную функцию для отдельной клетки в случае хода в эту клетку игроком или компьютером.

Суммарная оценочная функция вычисляется по формуле:

, где

 – значение суммарной оценочной функции;

– значение оценочной функции при постановке в клетку крестика, рассчитанное с помощью вызова функции calculate;

 – значение оценочной функции при постановке в клетку нолика, рассчитанное с помощью вызова функции calculate;

 – коэффициент агрессивности ИИ, задается переменной attack_factor.

Как видно из формулы, значение суммарной оценочной функции учитывает выгоду как своего хода в данную клетку, так и выгоду, которую получил бы соперник от хода в данную клетку. Причем чем больше коэффициент агрессивности, тем больше учитывается выгода соперника и соответственно компьютерный игрок следует защитной стратегии.

Значение коэффициента агрессивности на уровнях новичок и профессионал равно 1, компьютер ведет себя агрессивно. На уровне любитель значение равно 10, алгоритм находится в глубокой обороне.

Для уровней новичок и любитель также дополнительно вносится случайность значения суммарной оценочной функции: на уровне новичок значение суммарной оценочной функции умножается на случайное число, принимающее значение [0,1], на уровне любитель умножается на случайное число, принимающее значение [0.5,1].

2)         Находится клетка с максимальным значением суммарной оценочной функции. Если таких клеток несколько, то из них выбирается случайная. Ход делается в найденную клетку, массив fields обновляется путем установки соответствующего элемента в значение 2.

Алгоритм расчета оценочной функции:

Расчет оценочной функции для клетки игрвого поля производится вызовом функции calculate. Входными параметрами являются индексы поля в массиве fields (текущая клетка) и идентификатор, какой символ(крестик или нолик) будет поставлен в текущую клетку. Этот символ временно ставится в массив fields до окончания работы функции.

Расчет производится по следующей схеме. Просматриваются все ряды, продолжением которых может являться текущая клетка. Под рядом подразумевается последовательность из 5 клеток, каждая из которых может быть пустой или содержащей такой же символ, как и в текущей. Для этого проходятся все клетки на расстоянии не более 4 от данной, сначала по вертикали, затем по горизонтали, затем по 2 диагоналям. Для каждой проходимой клетки рассчитывается длина ряда, в которую она входит вместе с текущей. Под длиной ряда понимается количество одинаковых символов(крестиков или ноликов) в последовательности из 5 клеток. Если ряд прерывается противоположным символом, то длина ряда принимается равной нулю.


Значение оценочной функции рассчитывается по формуле:

, где  – общее количество ненулевых длин рядов;

– коэффициент оценочной функции;

 – длина -го ряда.

Степенная функция выбрана потому, что увеличение длины ряда даже на 1 существенно повышает его важность и не может быть выражена линейной функцией.

В случае нахождения ряда длиной 5, т. е. выигрышной ситуации, значение длины приравнивается к 10000, если расчет ведется при постановке крестика в текущую клетку и 1000 при постановке нолика в текущую клетку. Значение при постановке крестика выше, т. к. при нахождении такой ситуации компьютерный игрок должен в первую очередь стремиться к своему выигрышу, а не к предотвращению выигрыша соперника.

6. Текст программы

Файл ChildView.cpp:

//Модуль, содержащий основной алгоритм работы программы

#include "stdafx.h"

#include "XO.h"

#include "ChildView.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// CChildView

CChildView::CChildView()

{

}

CChildView::~CChildView()

{

}

BEGIN_MESSAGE_MAP(CChildView, CWnd)

ON_WM_PAINT()

ON_WM_LBUTTONDOWN()

ON_COMMAND(ID_NEW_GAME, &CChildView::OnNewGame)

ON_COMMAND(ID_X1010, &CChildView::OnX1010)

ON_COMMAND(ID_X100100, &CChildView::OnX100100)

ON_COMMAND(ID_X1919, &CChildView::OnX1919)

ON_COMMAND(ID_X3030, &CChildView::OnX3030)

ON_COMMAND(ID_X5050, &CChildView::OnX5050)

ON_COMMAND(ID_STEP_H, &CChildView::OnStepH)

ON_COMMAND(ID_STEP_C, &CChildView::OnStepC)

ON_COMMAND(ID_LEVEL_BEG, &CChildView::OnLevelBeg)

ON_COMMAND(ID_LEVEL_AMAT, &CChildView::OnLevelAmat)

ON_COMMAND(ID_LEVEL_PROF, &CChildView::OnLevelProf)

END_MESSAGE_MAP()

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)

NULL ));

//Глобальные переменные

unsigned char** fields;//Игровое поле ( = 0 - ничего нет, = 1 - нолик,

//= 2 - крестик, = 3 - выигравший нолик, = 4 - выигравший крестик

//= 5 - последний поставленный нолик, = 6 - последний поставленный крестик)

float** calc_fields;//Рассчитанное значение оценочной функции

int size_x = 19;//Размер поля по x (19 - по умолчанию)

int size_y = 19;//Размер поля по y (19 - по умолчанию)

int old_size_x = 0;//Старый размер поля по x

int old_size_y = 0;//Старый размер поля по y

int attack_factor = 1;   //Коэффициент агрессивности ИИ (1 - по умолчанию)

int valuation_factor = 3;//Оценочный коэффициент (4 - по умолчанию)

bool end_game = false;//Наступил конец игры?

int last_x = 0;//Координата x последнего хода

int last_y = 0;//Координата y последнего хода

bool player_first_step = true;//Приоритетность хода (true - человек)

int comp_level = 0;//Уровень игры компьютера (0 - эксперт)

//Перерисовка окна

void CChildView::OnPaint()

{

CPaintDC dc(this);

//Выведем поле

CBrush brushBgnd(RGB(0xF4, 0xA4, 0x60));//Кисть для заднего фона

CPen penO(PS_SOLID,2,RGB(0x00, 0x00, 0xFF));//Перо для нолика

CPen penX(PS_SOLID,2,RGB(0x00, 0x80, 0x00));//Перо для крестика

CPen penWin(PS_SOLID,2,RGB(0xFF, 0x00, 0x00));//Перо для выигрышных крестика или нолика

CPen penLast(PS_SOLID,2,RGB(0xFF, 0xFF, 0x00));//Перо для вывода последнего крестика или нолика

CPen penBlack(PS_SOLID,1,RGB(0x00, 0x00, 0x00)); //Перо для вывода сетки

dc.SelectObject(&brushBgnd); //Выбираем кисть с задним фоном

for (int y=0;y<size_y;y++)

{

for(int x=0;x<size_x;x++)

{

//Выводим сетку

dc.SelectObject(&penBlack);

if ((x == 0) && (y == 0))

{

dc.Rectangle(0,0,y*15+15,x*15+15);

}

else if (x == 0)

{

dc.Rectangle(y*15-1,0,y*15+15,x*15+15);

}

else if (y == 0)

{

dc.Rectangle(0,x*15-1,y*15+15,x*15+15);

}

else

{

dc.Rectangle(y*15-1,x*15-1,y*15+15,x*15+15);

}

//Устанавливаем перо для содержимого клетки

switch (fields[x][y])

{

case 0:

continue;

break;

case 1:

dc.SelectObject(&penO);

break;

case 2:

dc.SelectObject(&penX);

break;

case 3:

case 4:

dc.SelectObject(&penWin);

break;

}

//Проверяем, не текущий ли ход

if ((last_x == x) && (last_y == y))

{

dc.SelectObject(&penLast);

}

//Выводим содержимое клетки

switch (fields[x][y])

{

case 0:

continue;

break;

//Выводим нолик

case 1:

case 3:

case 5:

dc.Ellipse(y*15+2,x*15+2,y*15+13,x*15+13);

break;

//Выодим крестик

case 2:

case 4:

case 6:

dc.MoveTo(y*15+2,x*15+2);

dc.LineTo(y*15+12,x*15+12);

dc.MoveTo(y*15+2,x*15+12);

dc.LineTo(y*15+12,x*15+2);

break;

}

//Возвращаем значения для последних выведенных элементов

if ((fields[x][y] == 5) || (fields[x][y] == 6))

{

fields[x][y] -= 2;

}

}

}

}

//Нажатие на левую кнопку мыши, здесь производится основной расчет

void CChildView::OnLButtonDown(UINT, CPoint xy)

{

//Проверка, не закончена ли игра

if (!end_game)

{

//Ставим в массив игрового поля нолик в зависимости от координат мыши

if (fields[xy.y/15][xy.x/15] == 0)

{

fields[xy.y/15][xy.x/15] = 1;

last_x = xy.y;

last_y = xy.x;

}

else

return;

//Проводим анализ, не закончена ли игра

if (!end_analyze())

{

//Игра не закончена

//Ход компьютера

ii();

//Проверяем, не закончена ли игра

if (end_analyze())

{

//Игра закончена, выводим сообщение и отрисовываем на экран

this->OnPaint();

this->Invalidate();

this->MessageBox(CA2T("Вы проиграли"),0,0);

end_game = true;//Ставим признак конца игры

return;

}

}

else

{

//Игра закончена, выводим сообщение и отрисовываем на экран

this->OnPaint();

this->Invalidate();

this->MessageBox(CA2T("Вы выиграли"),0,0);

end_game = true;//Ставим признак конца игры

return;

}

//Перерисовка окна

this->OnPaint();

this->Invalidate();

}

return;

}

//Функция вычисления, не закончена ли игра

int CChildView::end_analyze()

{

//Проход по всему полю (расчет ведется для каждой клетки)

for (int i=0;i<size_x;i++)

{

for (int j=0;j<size_y;j++)

{

//Пропускаем пустую клетку

if (fields[i][j]==0) continue;

int tek = fields[i][j];//Значение текущей клетки

int end;//Текущая длина ряда

int u;//Доп. счетчик

/////////////////////////////////////////

//Смотрим вправо от текущей клетки

end = 0;

for (int k = j;k<j+5;k++)

{

if ((k == size_y) || (fields[i][k] != tek))

{

//Нет ряда из 5

break;

}

end++;

}

if (end == 5)

{

//Есть ряд из 5 - конец игры

for (int k = j;k<j+5;k++)

{

fields[i][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом

}

return 1;

}

/////////////////////////////////////////

//Смотрим вниз и вправо от текущей клетки

end = 0;

u=i;

for (int k = j;k<j+5;k++)

{

if ((k == size_y) || (u==size_x) || (fields[u][k] != tek))

{

//Нет ряда из 5

break;

}

end++;

u++;

}

if (end == 5)

{

//Есть ряд из 5 - конец игры

u=i;

for (int k = j;k<j+5;k++)

{

fields[u][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом

u++;

}

return 1;

}

/////////////////////////////////////////

//Смотрим вниз и влево от текущей клетки

end = 0;

u=i;

for (int k = j;k>j-5;k--)

{

if ((k == -1) || (u==size_x) || (fields[u][k] != tek))

{

//Нет ряда из 5

break;

}

end++;

u++;

}

if (end == 5)

{

//Есть ряд из 5 - конец игры

u=i;

for (int k = j;k>j-5;k--)

{

fields[u][k]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом

u++;

}

return 1;

}

/////////////////////////////////////////

//Смотрим вниз от текущей клетки

end = 0;

for (int k = i;k<i+5;k++)

{

if ((k == size_x) || (fields[k][j] != tek))

{

//Нет ряда из 5

break;

}

end++;

}

if (end == 5)

{

//Есть ряд из 5 - конец игры

for (int k = i;k<i+5;k++)

{

fields[k][j]=tek+2; //Заполняем все клетки в ряду значением + 2 для отсветки красным цветом

}

return 1;

}

}

}

//Игра не окончена

return 0;

}

//Функция расчета действий компьютера

void CChildView::ii()

{

float max = -1;//Максимальное значение оценочной функции

int cur_x = 0,cur_y = 0;//Текущие x и у

int povtor_num = 0;//Количество повторов одинаковых значений оценочной функции

int cur_povtor = 0;//Номер текущего повтора

//Расчитываем оценочную функцию для всех клеток

Страницы: 1, 2, 3


Новости

Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

  скачать рефераты              скачать рефераты

Новости

скачать рефераты

© 2010.