Полезное:
Как сделать разговор полезным и приятным
Как сделать объемную звезду своими руками
Как сделать то, что делать не хочется?
Как сделать погремушку
Как сделать так чтобы женщины сами знакомились с вами
Как сделать идею коммерческой
Как сделать хорошую растяжку ног?
Как сделать наш разум здоровым?
Как сделать, чтобы люди обманывали меньше
Вопрос 4. Как сделать так, чтобы вас уважали и ценили?
Как сделать лучше себе и другим людям
Как сделать свидание интересным?
Категории:
АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника
|
Листинг 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. Распределение вероятностей для трех существ в игре.
|