Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Листинг 13.4. Умная «Муха» (BFLY.C).






// ВКЛЮЧАЕМЫЕ ФАЙЛЫ /////////////////////////////////////

#include < stdio.h>

#include < graph.h>

#include < math.h>

// ОПРЕДЕЛЕНИЯ //////////////////////////////

#define STATE_CHASE 1

#define STATE_RANDOM 2

#define STATE_EVADE 3

#define STATE_PATTERN 4

// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ///////////////////////

// Указатель на системную переменную, содержащую значение таймера.

// Содержимое этой 32-битовой ячейки обновляется 18.2 раза

//в секунду

unsigned int far *clock=(unsigned int far *)0х0000046C;

// Х- и Y-компоненты шаблонов траекторий, по которым

// будет двигаться " Муха"

int patterns_x[33[20]={1, 1, 1, 1, 1, 2, 2, -1, -2, -3, -1,

0, 0, 1, 2, 2, -2, -2, -1, 0,

0, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 3, 3, 3, 3,

2, 1, -2, -2, -1,

0, -1, -2, -3, -3, -2, -2,

0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1};

int patterns_y[3][20]={0, 0, 0, 0, -l, -l, -l, -l, -l, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 0, 0, 0, 1, 1, 1, 2, 2, -1, -1, -1, -2, -2, -1, -1, 0, 0, 0, 1, 1, 1, 1, 1};

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

void Timer(int clicks)

{

//Эта функция использует значение таймера для формирования

// задержки. Необходимое время задержки задается в " тиках"

// интервалах в 1/18.2 сек. Переменная, содержащая 32-битовое

// текущее значение системного таймера, расположена

// по адресу 0000: 046Ch

unsigned int now;

// получить текущее время

now = *clock;

// Ничего не делать до тех пор. пока значение таймера не

// увеличится на требуемое количество " тиков".

// Примечание: один " тик" соответствует примерно 55мс.

while(abs(clock - now) < clicks){}

} // конец функции Timer

// ОСНОВНАЯ ФУНКЦИЯ /////////////////////////////////

void main(void)

{

int px=160, py=100, // начальные координаты игрока

ex=0, ey=0; // начальные координаты противника

int done=0, // флаг окончания работы программы

doing_pattern=0, // флаг выполнения шаблона

current_pattern, // номер текущего шаблона

pattern element, // текущая команда шаблона

select_state=0, // флаг необходимости смены состояния

clicks=20, // количество циклов, в течение которых

// сохраняется текущее состояние

fly_state = STATE CHASE; // " Муха" начинает с преследования

float distance; // используется при расчете

// расстояния между игроком и " Мухой"

_setvideomode(_MRES256COLOR);

printf(" Brainy Fly - Q to Quit");

//основной игровой цикл

while(! done)

{

// очистка точек

_setcolor(0);

_setpixel(px, py);

_setpixel(ex, ey);

// перемещение игрока

if (kbhit()) {

// определяем направление движения

switch(getch()}

{

case 'u': // вверх

{

py-=2;

} break;

case 'n': // вниз

{

py+=2;

} break;

case 'j': // вправо

{

px+=2;

} break;

case 'h'': // влево

{

px-=2;

} break;

case 'q':

{ done=l;

} break;

} // конец оператора switch

}

// конец обработки нажатия клавиши

// теперь перемещаем противника

// начинается работа " мозга"

// определяем текущее состояние КА

switch(fly_state)

{

case STATE_CHASE:

{

_settextposition(24, 2);

printf(" current state: chase " };.

// реализуем Алгоритм Преследования

if (px> ex) ex++;

if (px< ex) ex--;

if (py> ey) ey++;

if (py< ey) ey--;

//не пора ли перейти к другому состоянию?

if (--clicks==0) select_state=l;

} break;

case STATE_RANDOM:

(

_settextposition(24, 2};

printf(" current state: random ");

// перемещаем " Муху" в случайном направлении

ex+=curr_xv;

ey+=curr_yv;

//не пора ли перейти к другому состоянию?

if (--clicks=0) select_state=l;

} break;

case STATE_EVADE:

{

_settextposition(24, 2);

printf(" current state: evade ");

// реализуем Алгоритм Уклонения

if (px> ex) ex--;

if (px< ex) ex++;

if (py> ey) ey—;

if (py< ey) ey++;

//не пора ли перейти к другому состоянию?

if (--clicks==0) select_state=l;

} break;

case STATE_PATTERN:

{

_settextposition(24, 2);

printf(" current state: pattern ");

// перемещаем " Муху", используя следующий

// элемент текущего шаблона

ex+=patterns_x[current_pattern][pattern_element];

ey+=patterns_y[current_pattern][pattern_element];

// обработка шаблона закончена?

if (++pattern element==20)

{

pattern_element = 0;

select_state=l;

} // конец проверки завершения шаблона

} break;

default; break;

} // конец обработки текущего состояния

// надо ли менять, состояние?

if (select_state==l)

{

// Выбор нового состояния основан на

// игровой ситуации и неявной логике.

// Для выбора используется расстояние до игрока

distance = sqrt(.5+fabs((рх-ех)*(рх-ех)+(ру-еу)*(ру-еу)));

if (distance> 5& & distance< 15& & rand()%2==1)

{

// выбираем новый шаблон

current_pattern = rand()%3;

// переводим " мозг" в состояние действий по шаблону

fly_state = STATE_PATTERN;

pattern_element = 0;

} // конец обработки ситуации " близко к игроку"

else if (distance< 10) // слишком близко, убегаем!

clicks=20;

fly_state = STATE_EVADE;

} // конец обработки ситуации " слишком близко"

else

if (distance> 25& sdistance< 100& & rand()%3==1)

{

// преследуем игрока clicks=15;

fly_state = STATE_CHASE;

} // конец обработки ситуации Преследование

else

if (distance> 30& & rand()%2==l)

{

clicks=10;

fly_State = STATE_RANDOM;

curr_xv = -5 + rand()%10; //от -5 до +5

curr_yv = -5 + rand()%10; //от -5 до +5

} // конец " неявной логики"

else

{

clicks=5;

fly_state = STATE_RANDOM;

curr_xv = -5 + rand()%10; //от -5 до +5

curr_yv = -5 + rand()%10; //от -5 до +5

} // конец оператора else // сбрасываем флаг смены состояния

select_state=0;

} // конец Алгоритма Смены Состояния

// Убеждаемся, что " Муха" находится в пределах экрана

if (ex> 319) ех=0;

i£ (ex< 0) ех=319;

if (ey> 199) еу=0;

if (ey< 0) еу=199;

// конец работы " мозга"

_setcolor(12);

_setpixel(ex, ey);

// Немного подождем...

Timer(1);

} // Конец цикла while

_setvideomode(_DEFAULTMODE);

} // Конец функции main

Запустив программу, вы наверняка обратите внимание на кажущуюся сложность поведения «Мухи». А ведь для получения такого результата использована весьма простая схема! Возможно, и вы заметите то, что увидел я - чуть ли не человеческую способность мыслить.

Управление приоритетным состоянием

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

В имитаторе движения «Мухи» каждое состояние выполнялось до полного завершения. Но если включить в программу проверку выполнения или невыполнения некоторых условий, это позволило бы КА «выпрыгнуть» из состояния, не дожидаясь окончания его «отработки».

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

Вероятностные автоматы

Наверное, вы уже поняли, как вероятность и случайные числа могут быть использованы для выбора направлений и состояний. Мы научились использовать случайные последовательности для конструирования «характера» персонажей. Я имею в виду, что «Муха» в нашем предыдущем примере могла самостоятельно выбирать различные состояния, основываясь на окружающей обстановке. Если несколько изменить метод выбора состояний, основанны на генерации случайных чисел (то есть, создать условия, при которых вход в опредёленное состояние стал бы легче или тяжелее), то, в конечном счете, нам удалось бы изменить " характер" «Мухи».

Скажем, нам захотелось иметь в игре две «мухи». Если одну и ту же программу использовать для создания траектории движения каждой «мухи», они бы действовали одинаково. Во многих случаях большего и не требуется. Однако гораздо интересней иметь много «мух» с небольшими различиями в поведении. Это можно было бы реализовать изменением диапазона случайных чисел-во всех строках программы, где выбираются состояния «мухи». Но такой подход будет очень грубым. Мы пойдем другим путем — путем создания общего метода управления характером персонажей, основанного на вероятности.

В искусственном интеллекте «индивидуальность» означает возможность существ по-разному выполнять определенные действия при одних и тех же обстоятельствах. Например, у меня есть несколько достаточно активных друзей, которые захотели бы слегка проучить плута, попытавшегося их надуть. Но у меня также есть друзья, которые более спокойны и предпочитают сначала думать, а потом действовать. Скорее всего, мошеннику удалось бы как-то с ними договориться. То, что мы видим на данном примере и является «индивидуальностью». Каким именно способом это будет достигнуто, не принципиально, важен конечный результат.

В видеоиграх мы могли бы иметь несколько противников, которые постоянно преследуют нас, пока другие в это время неподвижны и стреляют. Третьи трусливы и предпочитают убегать, а не сражаться. Анализируя ситуацию, мы видим, что имеется все тот же набор состояний, но вероятности перехода в них различны для каждого создания. Для моделирования этого процесса мы могли бы сослаться на «таблицу вероятностей» в той части программы, которая выбирает новое состояние. Эта таблица могла бы содержать различные степени вероятности переходов существ в то или иное состояние. К примеру, взгляните на таблицу 13.1, в которой перечислены соотношения вероятностей для трех различных существ в одной игре.

Таблица 13.1. Распределение вероятностей для трех существ в игре.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.