Bardzo prosty algorytm SI (Sztucznej Inteligencji), poprawiona wersja
LOSMARCELOS
Potrzebne są 3 komponenty
PLAYER_IMAGE1
ENEMY_IMAGE1
oraz Timer1
Ten kod prezentuje algorytm pościugu.
Za graczem PLAYER_IMAGE1 bedzie podążać ENEMY_IMAGE1 (przeciwnik).
Ikonki, bitmapy na komponentach możemy sobie wczytać jakie chcemy.
unit INTEL_W1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TForm1 = class(TForm)
Player_Image1: TImage;
Enemy_Image1: TImage;
Timer1: TTimer;
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
Application.ProcessMessages;
{obsluga klawiatury}
if Key = VK_LEFT then
Player_Image1.Left := Player_Image1.Left - 2; // jesli kursor w lewo - przesun gracza w lewo
if Key = VK_RIGHT then
Player_Image1.Left := Player_Image1.Left + 2; // jesli kursor w prawo - przesun gracza w prawo
if Key = VK_UP then
Player_Image1.Top := Player_Image1.Top - 2; // jesli kursor do gory - przesun gracza do gory
if Key = VK_DOWN then
Player_Image1.Top := Player_Image1.Top + 2; // jesli kursor do dolu - przesun gracza do dolu
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered := True; // zalacz podwojne buforowanie,
// w celu unikniecia migotania obrazkow przy przesuwaniu
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// Mechanizm naszej sztucznej prymitywnej inteligencji
if Player_Image1.Left > Enemy_Image1.Left then
Inc(Enemy_Image1.Left);
if Player_Image1.Left < Enemy_Image1.Left then
Dec(Enemy_Image1.Left);
if Player_Image1.Top > Enemy_Image1.Top then
Inc(Enemy_Image1.Left);
if Player_Image1.Top < Enemy_Image1.Top then
Dec(Enemy_Image1.Left);
{
tak ten kod wyglądal pierwotnie w C
if (px>ex) ex++;
if (px<ex) ex--;
if (py>ey) ey++;
if (py<ey) ey--; }
end;
end.
Poprawiłem błąd.
===============================================
Automaty skończone zależne od stanu otoczenia.
(wymagany kompilator MS C/C++ 7.0, jak bede mieć czas to zrobie konwersje na Borland C++ i BGI, a może później na C++ Buildera lub Delphi).
Tylko nie wiem gdzie umieścić artykuł, bo częśc jest w Delphi, część w C/
Może do kategori "Z pogranicza" ?
// MODUŁY /////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <graph.h>
#include <math.h>
// DEFINICJE /////////////////////////////////////////////////////////////////
#define STATE_CHASE 1
#define STATE_RANDOM 2
#define STATE_EVADE 3
#define STATE_PATTERN 4
// ZMIENEN GLOBALNE ////////////////////////////////////////////////////////////
unsigned int far *clock = (unsigned int far *)0x0000046C; // wskaźnik na zegar wewnętrzny
// składowe x i y wzoru w postaci 2-wymiarowych tablic
int patterns_x[3][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,-1,-1,-1,-1,-1,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 };
//////////////////////////////////////////////////////////////////////////////
Timer(int clicks)
{
//funkcja wykorzystuje wewn. zegar do uzyskania przerwy w programie
unsigned int now;
// odczytaj aktualny czas
now = *clock;
//każde tyknięcie zegara to ok 55 ms
while(abs(*clock - now) < clicks){}
} /
// M A I N ///////////////////////////////////////////////////////////////////
main()
{
int px=160,py=100, // pozycja startowa gracza
ex=0,ey=0, // pozycja startowa przeciwnika
curr_xv,curr_yv; // prędkość "muchy" podczas wykonywania chaotycznych ruchów
int done=0, // znacznik wyjscia
doing_pattern=0, // znaczniki odtwarzania wzoru
current_pattern, // aktualnie odtwarzany wzor
pattern_element, // aktualnie wykonywany element wzoru
select_state=0, // zmiana stanu
clicks=20, // liczba "cykli"
fly_state = STATE_CHASE; // od jakiego stanu sie zaczyna ruch much - STATE CHASE - poscig
float distance; // odleglosc (dystans) miedzy mucha a graczem
_setvideomode(_MRES256COLOR);
printf(" Nacisnij Q aby wyjsc");
// glowna petla gry
while(!done)
{
// wymazanie kropek
_setcolor(0);
_setpixel(px,py);
_setpixel(ex,ey);
// przesun gracza
if (kbhit())
{
// ruch gracza, na podstawie klawiszy
switch(getch())
{
case 'u': // GÓRA
{
py-=2;
} break;
case 'n': // DÓŁ
{
py+=2;
} break;
case 'j': // PRAWA
{
px+=2;
} break;
case 'h': // LEWA
{
px-=2;
} break;
case 'q':
{
done=1;
} break;
} // koniec bloku switch
} // koniec bloku if
// przesuń przeciwnika
// w jakim stanie jest "mózg" przeciwnika
switch(fly_state)
{
case STATE_CHASE:
{
_settextposition(24,2);
printf("Biezacy stan : poscig ");
// mucha goni gracza
if (px>ex) ex++;
if (px<ex) ex--;
if (py>ey) ey++;
if (py<ey) ey--;
// przejscie do innego stanu
if (--clicks==0)
select_state=1;
} break;
case STATE_RANDOM:
{
_settextposition(24,2);
printf("Biezacy stan : ruchy chaotyczne ");
// mucha porusza sie chaotycznie
ex+=curr_xv;
ey+=curr_yv;
// czas na inny stan
if (--clicks==0)
select_state=1;
} break;
case STATE_EVADE:
{
_settextposition(24,2);
printf("Biezacy stan : ucieczka ");
// mucha ucieka od gracza
if (px>ex) ex--;
if (px<ex) ex++;
if (py>ey) ey--;
if (py<ey) ey++;
// czas na nastepny stan
if (--clicks==0)
select_state=1;
} break;
case STATE_PATTERN:
{
_settextposition(24,2);
printf("Biezacy stan : wzór ");
// mucha porusza sie wg wzoru
ex+=patterns_x[current_pattern][pattern_element];
ey+=patterns_y[current_pattern][pattern_element];
// zakonczono odtwarzanie wzoru
if (++pattern_element==20)
{
pattern_element = 0;
select_state=1;
} // koniec bloku if
} break;
default:break;
} // koniec bloku switch
// czy stan powinien ulec zmianie ?
if (select_state==1)
{
// wybranie stanu korzystajac ze stanu otoczenia
// i korzystając z "logiki rozmytej"
// wykorzystanie odległości gracza d wybrania funkcji nowego stanu
distance = sqrt(.5 + fabs((px-ex)*(px-ex) + (py-ey)*(py-ey)));
if (distance > 5 && distance <15 && rand()%2==1)
{
// losowe wybranie wzoru
current_pattern = rand()%3;
// wprowadzenie "mózgu" w stan odtwarzania wzoru
fly_state = STATE_PATTERN;
pattern_element = 0;
} // koniec bloku if
else
if (distance < 10) // uciekamy :-) !
{
clicks=20;
fly_state = STATE_EVADE;
} // mucha sciga gracza !
else
if (distance > 25 && distance <100 && rand()%3==1) // let's chase player
{
clicks=15;
fly_state = STATE_CHASE;
} // koniec bloku if
else
if (distance > 30 && rand()%2==1)
{
clicks=10;
fly_state = STATE_RANDOM;
curr_xv = -5 + rand()%10; // -5 to +5
curr_yv = -5 + rand()%10; // -5 to +5
} // koniec bloku if
else
{
clicks=5;
fly_state = STATE_RANDOM;
curr_xv = -5 + rand()%10; // -5 to +5
curr_yv = -5 + rand()%10; // -5 to +5
} // koniec bloku else
// wyzerowanie znacznika zmiany stanu
select_state=0;
} // koniec bloku if
// sprawdzenie, czy mucha pozostaje na ekranie
if (ex>319) ex=0;
if (ex<0) ex=319;
if (ey>199) ey=0;
if (ey<0) ey=199;
// rysowanie kropek
_setcolor(9);
_setpixel(px,py);
_setcolor(12);
_setpixel(ex,ey);
// momencik przerwy
Timer(1);
} // koniec pętli while
_setvideomode(_DEFAULTMODE);
} // koniec funkcji main
Literatura w której jest opisana SI (ujęta z różnych aspektów)
LaMothe, Ratcliff, Seminatore & Tyler, Sztuczki i tajemnice programowania gier, Warszawa, 1996.
J.Grębosz - Symfonia C++, Kraków, 2002.
Cichosz P., Systemy uczące się, WNT, Warszawa, 2000.
Ziembiński Z. Logika Praktyczna, PWN, Warszawa, 1974.
Pozdrawiam! :-)
Lepsza sztuczna inteligencja niż ludzka głupota.
Jaki zaawansowany kod.... :-)
Szczególnie to "SI"....
do komentarza abc:
inc() i dec() nie tylko mniej zajmuje, ale i szybciej jest wykonywane przez procesor :]
Pierwotnie kod był nie w C++ ale czystym C dla DOS (dokładniej przy użyciu kompilatora Microsoft C/C++ 7.0).
Ja zrobiłem konwersje dla Delphi pod Windows.
W załączniku jest oryginał z 1994 roku w C.
Jak już mówiłem, później wrzuce bardziej zaawansowany algorytm.
Pozdrawiam!
no i pousuwaj jeszcze chociaz te beginy i endy :/ troche ich za duzo... niepotrzebnie zajmuja miejsce (na stronie) :D
@Marooned:
5: ten kod jest czystym tlumaczeniem na Delphi z jakiejs innej strony - doskonale pamietam ten kod w C++ tylko nie moge se przypomniec linka...
Wnoszę o usunięcie tego - powody:
artykuł ciekawy, tylko co to ma wspólnego z SI ?
Poprawiłem błąd, dodałem źródło + exe, oraz kod pierwowzoru w C, exe w C pod dosa ;)
Poza tym to miałbyć prosty algorytm więc nie oczekujcie super inteligencji. Może później zrobie coś bardziej skomplikowanego.
To raczej gotowiec, a nie artykul...
ales narobil SI i po co te begin ... end ??
btw mowisz ze bierzesz sie za pisanie gier wiec podpowiem Ci, ze zle rozwiazales sprawe z klawiszami. Tworzysz tablice klawiszy gdzie masz stany keydown i keyup i potem sprawdzasz je w zdarzeniu ontimer. Dzieki temu Twoja postac ma okreslona predkosc
Do SI to chyba daleko temu..
hmm... sry, ale ja juz to gdzies widzialem :] Nie pamietam dokladnie gdzie ale takie cos bylo...
jest blad w kodzie:
if Player_Image1.Top > Enemy_Image1.Left then
if Player_Image1.Top < Enemy_Image1.Left then
przyrownujesz top do left...
powinno byc
if Player_Image1.Top > Enemy_Image1.Top then
if Player_Image1.Top < Enemy_Image1.Top then
a tak to moze poczatkujacych cos natchnie :]
if Player_Image1.Left > Enemy_Image1.Left then inc(Enemy_Image1.Left)
else if Player_Image1.Left < Enemy_Image1.Left thendec(Enemy_Image1.Left)
else if Player_Image1.Top > Enemy_Image1.Left theninc(Enemy_Image1.Top)
else if Player_Image1.Top < Enemy_Image1.Left thendec(Enemy_Image1.Top);
Popieram abc, coraz wiecej ludzi pisze te nie potrzebne beginy i endy czy { } w przypadku c/c++ (w kojocie to samo :| ), pytanie jest po co?? :|
if Player_Image1.Left > Enemy_Image1.Left then
inc(Enemy_Image1.Left);
if Player_Image1.Left < Enemy_Image1.Left then
dec(Enemy_Image1.Left);
if Player_Image1.Top > Enemy_Image1.Left then
inc(Enemy_Image1.Top)
if Player_Image1.Top < Enemy_Image1.Left then
dec( Enemy_Image1.Top );
Jakoś tak mniej zajmuje :]
Ale ogÓlnie jak by to powiedzieli gracze GG ;]