[ Webhosting profitux.cz ]
hertpl: Undefined index: page_title(template line: 74) in templates/articles_print.html on line 39

Programování inteligentních agentů - 5. díl

Interakce agentů

Článek obsahuje skript: Simulace Axelrodova turnaje

Úvod

Rozhodnutí. Dělat je musíme všichni. Jsou běžnou, ale ne vždy příjemnou a bezbolestnou součástí našich životů. Rozhodujeme se na mnoha úrovních a to jak o věcech jednodušších a krátkodobých, jako je kupříkladu pohyb některou částí našeho těla, tak o věcech složitých vyžadujících celý komplex akcí - plánujeme si budoucnost.

Jakým způsobem ale volit, kterou akci provést v daný okamžik?

Mnozí lidé si často myslí, že správnost dané akce podléhá jistým subjektivním kvalitám. Že je - tak říkajíc - "věcí názoru". Přestože je možné jim v některých případech dát za pravdu, mnohdy je volba optimální strategie jednoznačná, a racionální akce je tak dána často jednoznačně. I v případech, kdy volba akce jednoznačná není, je možno některé jiné akce vyloučit - označit je jako iracionální - a zúžit tak repertoár v danou chvíli možných akcí. Umět se racionálně rozhodovat je nezbytným přepokladem pro to být úspěšný. Časté iracionální chování vede k prohrám.

Rozhodování je samozřejmě i součástí života inteligentního agenta.

Jak se agent rozhoduje?

Principy rozhodování bývaly často zužovány na zkoumání uvažování jednoho individuálního agenta, který je umístěn do nějakého prostředí. U agenta se přitom předpokládalo, že je schopen toto prostředí vnímat pomocí senzorů, a že je s ním schopný interagovat prostřednictvím akcí a měnit tak jeho stav.

To, co si agent musí při takto pojatém (individuálním) rozhodování uvědomovat jsou dvě věci.

Pakliže agent podnikne nějakou akci, dojde ke změně stavu světa. Agent si musí být těchto změn vědom. Pokud se tedy agent nachází v nějakém světě, musí mít ke každé své potenciální akci přiřazen také stav světa po provedení této akce.

Už zde narážíme na první závažný problém - na tzv. problém rámce. Název údajně pochází z kreslených seriálů, kde se postavičky v popředí pohybovaly a manipulovaly s objekty, kdežto pozadí scény zůstalo nezměněno. Problém rámce spočívá v tom jak určit, jaké jsou efekty a "neefekty" daných akcí, to znamená co daná akce může a co nemůže ovlivnit. Přestože teoreticky je možno nad problémem rámce mávnout rukou a prostě jen obohatit formální sytém o tzv. "rámcové axoimy", které tyto efekty a neefekty explicitně vyjmenují, při praktických aplikacích se tvrdě narazilo. Výpočetní složitost takovéhoto ad-hoc řešení se ukázala jako neúnosná do té míry, že ji na počítačích využívajících současnou logiku nejspíš nikdy nebude možno řešit navyšováním výpočetního výkonu.

Poznámka: Řešení problému rámce se kterými jsem se zatím setkal jsou jen "řešením v uvozovkách". Například Reiterovy successor state axioms sice snižují počet nutných axiomů, ale ty jsou zase komplexnější.

Každý stav, do kterého se svět dostane poté, co agent provede danou akci, je pro agenta nějak (ne)příznivý. Je proto nutno uvést, jaký "zisk" vstup do daného světa agentovi přinese. Specifikujeme proto tzv. "utility funkci" na světech, značíme u(w). Poznamenejme, že tato utility funkce nemusí být jen "krátkozraká", jak by se možná mohlo někomu zpočátku zdát. Je teoreticky možno definovat ji "tranzitivně", může nějak zohledňovat plán do budoucna. Formálně řečeno, potenciálně může být u(w) = f(u(w1), ..., u(wn)).

Mohlo by se teď zdát, že takto pojaté rozhodování je dostatečně obecné a stačí nám. Jenže...

Rozhodování v prostředí s více agenty

... ne vždy je možno budoucí zisk, který nám přinese provedení dané akce určit, protože může být závislý na tom, jakou akci provede jiný agent.

Uvažujme nyní následující situaci:

Vězňovo dilema

Policie přistihne dva muže, jak se sklánějí nad mrtvým tělem a jeden mu prohledává kapsy, druhý sundává z ruky hodinky. Je nad slunce jasné, že nebožtík je právě okrádán. Policie však nemá důkazy, že zlodějové jsou navíc vrahy. Proto oba muže zatkne a při výslechu zavře každého z nich do samostatné místnosti. Oba vězni teď řeší dilema - mají totiž na výběr, a to ze dvou možností:

  • spolupracovat se svým komplicem (C, cooperate), čili zapírat a zapírat, například stylem: "My už ho tam tak našli, nevěděli jsme co dělat a zpanikařili jsme!"
  • zradit a zaprodat svého komplice (D, defect), třeba říct: "Já to nebyl, ten druhý chlap je sprostým vrahem a mě do toho jen zatáhl!"

Situace, které mohou na základě výpovědí nastat, jsou následující:

  • (C,C) - oba vězni spolu spolupracují - to znamená oba zapírají. Potom oba půjdou sedět na 2 roky za okrádání zemřelého, více policie udělat nemůže
  • (C,D) a (D,C) - jeden vězeň zapírá, ale druhý ho zradí. Policie z toho vyvodí, že jeden je vrahem a druhý je nevinný, byl do toho namočen. Zrádce dostane rok s podmínkou, napráskaný jde sedět na doživotí za vraždu, vyhrožování "komplicovi" a nepravdivou výpověď
  • (D,D) - oba vězni se vzájemně zradí. Policie je obviní z vraždy, ale za to, že s ní spolupracovali jim oběma vyměří "jen" 25 let natvrdo

Předpokládejme, že vězni nejsou spolu nějak zásadně zpřízněni. Starají se tedy jenom o sebe a snaží se o to, strávit co nejkratší čas ve vězení. Dále předpokládejme, že jsou oba dostatečně inteligentní na to, aby byli schopni uvažovat o své výpovědi racionálně.

Jaké budou výpovědi vězňů?

Možné výsledky této "hry" (které se říká vězňovo dilema) shrneme ještě jednou, tentokrát v "tabulce", které se v teorii her říka "pay-off matrix" ("výplatní matice").

1.vězeň/2.vězeň C D
C 2/2 inf./1
D 1/inf. 25/25

Ve hře předpokládáme, že maximalizujeme jakýsi zisk (minimalizujeme dobu pobytu ve vězení), jinými slovy: jedná se o optimalizační úlohu. U většiny optimalizačních úloh nám zásadním způsobem pomůže, když známe chování celého systému. V našem případě by se jednalo o to, kdybychom věděli, jak se zachová náš kolega. Pomohlo by nám to ale opravdu i v této situaci?

Uvažujme, že jsme "1. vězeň" a víme, že nás kolega zradil. Potom nám nezbývá, než jej zradit také a jít sedět na 25 let místo na doživotí. Strategie kterou jsme zvolili je tedy D. Na druhou stranu, když náš kolega spolupracuje, opět se nám vyplatí jej zradit, protože namísto na 2 roky půjdeme sedět jen na rok. Vidíme, že bez ohledu na to, jak se chová náš oponent, jediná strategie maximalizující osobní zisk je strategie D. Proč by se tedy měl kterýkoli z vězňů rozhodovat jinak, než pro zradu? Důvod k tomu není. Pokud budou hrát oba vězňové na sebe a budou uvažovat racionálně, potom se vzájemně zradí a půjdou sedět oba na 25 let...

Poznámka: Předpoklad maximalizace vlastního zisku není pro vězňovo dilema tolik limitující, jak by se mohlo zdát a jak se i často prezentuje. V případě, že by vězni byli například dobří přátelé, stačilo by tuto skutečnost kvantifikovat a zohlednit to v pay-off matici, čili neuvažovat jako benefit jen co nejnižší dobu pobytu, ale jakousi funkci doby pobytu a ostatních faktorů. V takovém případě by se ale jednak mohlo jednat o jiný typ hry než je vězňovo dilema, neplatil by tedy předpoklad že uvažujeme hráče vězňova dilematu, a také by bylo nutno otestovat, jestli je zvolená kvantifikace často subjektivních veličin vhodná/reálná - nápomocno budiž, že se stačí zabývat jen uspořádáním, nikoliv absolutními hodnotami. Méně realistický se v praxi ale jeví předpoklad racionality agentů a jejich dostatečně komplexního uvažování.

John Nash
John Nash

Stavu, do kterého se systém dostal poté, co se oba vězni rozhodli pro zradu, se říká Nashovo ekvilibrium (pojmenováno po Johnu Nashovi).

1.vězeň/2.vězeň C D
C 2/2 inf./1
D 1/inf. 25/25

V čem je problém? Opravdu je jediná racionální volba ve vězňovu dilematu volba strategie D - zrada? A to přesto, že existuje lepší (více optimální) řešení? Kdyby oba vězni spolupracovali, sedí oba jen na 2 roky namísto na 25, tak proč je jediné racionální řešení zrazovat? Je opravdu svět tak zkažený?

Stíny budoucnosti

V případě naší hry tomu tak opravdu je. Důvodem je fakt, že druhý vězeň nás buďto zradí taky, nebo se již jeho odvety nemusíme obávat. Není zde tedy již možnost, že bychom za zradu spolupracujícího komplice v budoucnosti pykali. V případě, že však hrajeme vězňovo dilema opakovaně (potom říkáme, že hrajeme iterované vězňovo dilema), situace je odlišná. Laureát Nobelovy ceny Robert Aumann ukázal, že agenti, kteří hrají nekonečně (!!!) mnohokrát vězňovo dilema, mohou hrát kooperativně a přesto se chovat racionálně.

Robert Aumann
Robert Aumann

Pozn.: To, co obecně při opakovaných hrách udržuje ekvilibrium v kooperativním stavu je "hrozba odplaty", neboli literárně řečeno - na agenta dopadá stín budoucnosti. V extrémně tvrdém pojetí odplaty už agent neobnoví spolupráci se svým oponentem nikdy. To však nemusí být vhodné - o tom viz dále... Ze života můžeme uvést například "studenou válku". To, co udržovalo "kooperativní stav", byla hrozba vzájemného zničení obou velmocí ve chvíli, kdy by jedna ze stran porušila ekvilibrium a zaútočila...

Pay-off matice, kterou použil Robert Aumann ve své "nobelovské" přednášce "War and Peace" pro demonstraci toho, jak je možno hrozbou trestu docílit vynucení kooperace, vypadala následovně:

1.hráč/2.hráč Spolupracuj Potrestej
Spolupracuj 10/10 0/0
Zaútoč 100/1 0/0

Vidíme, že pokud 2. hráč pohrozí při nekonečném počtu her odplatou za provedení akce "Zaútoč" 1. hráči, ten si případný útok dobře rozmyslí. Jeho celkový zisk totiž bude nižší, než kdyby spolupracoval... Aneb - jak Aumann řekl - obchodník, který podvede svého zákazníka sice získá krátkodobě vyšší zisk, v byznysu se ale dlouho neudrží...


V případě, že by se hrálo jen konečně mnohokrát, vyplácí se při hře vězňova dilematu zrazovat. Důkaz lze provést indukcí, naznačme jej:

V posledním kole může agent zradit, neboť oponent již nebude mít příležitost mu oplácet. Maximalizace zisku v posledním kole se tedy dosáhne zradou - jako by se hrálo jen jedno vězňovo dilema. Oba agenti tedy - jsou-li racionální - v posledním kroce zradí. Je tedy jasné, že bez ohledu na to, co tedy bude agent dělat v předposledním kole, jeho oponent ho v dalším kole zradí. Agentovi se proto vyplatí zradit i v předposledním kole, protože to, jak agenti budou hrát v dalším kole je dáno. Oba agenti tedy - po racionální volbě - zradí i v předposledním kole. A tak dále... až do prvního kola...

Uvažujme pro začátek, že máme populaci 100 agentů. Předpokládejme napřed, že 99 z nich jsou "naivní dobráci" - vždy jen kooperují, jeden je "ďábelský prevít" a tedy vždy zrazuje. Necháme teď agenty spolu hrát vězňovo dilema stylem každý s každým 100 krát. Zajisté, 100 sice není nekonečno, ale tady nám to vadit nebude - předpokládejme třeba, že agenti nevědí, že se hraje jen 100x, nebudou tedy nějak zohledňovat faktickou konečnost hry. Pro potřeby hry můžeme použít následující jednoduchou pay-off matici:

1.hráč/2.hráč C D
C 2/2 0/3
D 3/0 1/1

Podívejme se nyní, jak na konci turnaje dopadne libovolný dobrák. Ten odehraje 98 her proti dobrákům, jednu proti prevítovi, získá tak 2x98x100 + 0x1x100 = 19 600 bodů (ve výpočtu píšeme vždy "#bodů"x"#sou­peřů"x"#her"). Jak dopadne prevít? Odehraje 99 her proti dobrákům, čili získá 3x99x100 = 29 700 bodů. Vidíme, že i v takovéto populaci je optimální (a neméně racionální), být prevít.

Zkusíme ale uvažovat nějakou jinou populaci, kde jsou agenti dobráci méně naivní. Co to ale znamená méně naivní?

Pravděpodobně největší pokrok v oblasti zkoumání strategií řešících iterovaně vězňovo dilema nám přinesl výzkum Roberta Axelroda. Robert Axelrod je profesorem politických studií na Michiganské univerzitě. Axelrod sezval své kolegy z akademické sféry, aby přihlásili do turnaje strategií - dnes zvaného Axelrodova turnaje - svoje agenty. Strategií se sešlo hned několik, byly různě složité, různě přátelské či podlé, vycházely z různých úvah. Vyhrála však ta asi nejjednodušší z nich (údajně měla 4 řádky BASICu) - strategie "Oko za oko, zub za zub" ("tit for tat"). Tato strategie v prvním kole spolupracuje, v každém dalším dělá to, co o kolo dříve udělal její oponent. Dnes je považována za nejlepší deterministickou strategii.

Robert Axelrod
Robert Axelrod

Na základě pozorování úspěšnosti jednotlivých agentů zformuloval Axelrod 4 podmínky pro úspěšnou strategii:

  • Buď hodný, aneb nezrazuj, dokud k tomu nemáš důvod
  • Odplácej zradu - nehraj naivně
  • Zradu odpouštěj
  • Snaž se nebýt závistivý - nesnaž se skórovat více, než tví oponenti

Axelrod tudíž došel k závěru (možná utopicky znějícímu), že agent žijící v dostatečně členité populaci musí pro své vlastní dobro být hodný, nezávistivý a musí sice oplácet zradu, ale také musí umět odpouštět. Racionální je snažit se o to, co nejvíce spolupracovat (volit strategii C), být hodný...

Pozn.: Poznatky plynoucí ze zkoumání strategií agentů hrajících hry opakovaně našly cenné uplatnění v genetice (zmiňme Richarda Dawkinse), sociologii, politologii (zde například při studiu válečných konfliktů) a třeba ekonomice.

Richard Dawkins
Richard Dawkins

Vraťme se k minulému příkladu. Znovu mějme populaci 100 agentů - tentokrát ale 51 z nich hrajících "racionálně přátelskou" strategii "tit for tat" a 49 "ďábelských prevítů" (tedy máme populaci s mnohem větším poměrem padouchů, než minule). Opět je spolu necháme hrát každý s každým 100x vězňovo dilema s výše zmíněnou maticí. Jak si jednotlivé strategie budou vést nyní? Pokud se spolu utkají dvě strategie "tit for tat", budou spolu vždy spolupracovat. Pokud se proti sobě utká "tit for tat" a "prevít", první kolo bude "tit for tat" spolupracovat, dále však - vidíce prevítovu zradu - bude tuto zradu oplácet. Výsledné skóre agenta hrajícího strategii "tit for tat" tedy bude 2x51x100 + (0x49x1 + 1x49x99) = 15 051 bodů. Výsledné skóre prevíta bude (3x51x1 + 1x51x99) + (2x49x100) = 15 002.

Je tedy vidět, že ve společnosti, kde je většina agentů přednostně kooperativních, ale zároveň schopných odplaty, prevíti nemají šanci (uvažujeme-li výše danou pay-off matici)...

Poznámka: V klasickém Axelrodově turnaji není podle pravidel možné, aby dva jedinci hráli stejnou strategii. Pokud by toto možné bylo, pravděpodobně nejlepší strategií je strategie navržená týmem ze Southamptonské univerzity. Ta je založená na tom, že je schopna v prvních pár (5-10) krocích rozpoznat agenta, který hraje tutéž strategii a poté jeden agent vždy zrazuje - ždíme svého kolegu, druhý vždy kooperuje - obětuje se ve prospěch oponenta. Takto sice část agentů hrající southamptonskou strategii obsadí přední místa v turnaji, druhá část však skončí beznadějně na hvozdu... Důležitým přínosem této strategie je to, že ukazuje, že komunikace (zde úvodních pár kol, během kterých se agenti rozpoznají a "domluví se" na tom, kdo bude zrazovat a kdo kooperovat) může mít vliv na výsledek hry.

Axelrodův turnaj v 3APL

Nyní můžeme přejít k praktické ukázce - napíšeme si agenty, kteří hrají různé strategie Axelrodova turnaje. Implementovali jsme následující strategie:

  • "naivní dobrák" (cooperating) - naivní strategie, která vždy spolupracuje
  • "ďábelský prevít" (defecting) - podlá strategie, vždy zrazuje
  • "náhoda" (random) - náhodné rozhodnutí pro spolupráci/zradu
  • "oko za oko..." (tit for tat) - první kolo spolupracuje, každé n. kolo hraje to, co hrál oponent v n-1. kole
  • "pozitivní testovač" (positive tester) - zkusí zradit v prvím kole, v druhém spolupracuje. Pokud oponent zareagoval na první zradu, hraje "oko za oko", jinak hraje strategii "náhoda"
  • "negativní testovač" (negative tester) - zkusí zradit v prvím kole, v druhém opět zrazuje. Pokud oponent zareagoval na první zradu, hraje "oko za oko", jinak hraje strategii "náhoda"
  • "náhodný šprýmař" (joss random) - hraje "oko za oko", ale s jistou pravděpodobností náhodně vynuceně zrazuje
  • "pořádný šprýmař" (joss periodic) - hraje "oko za oko", pravidelně po n krocích ale vynuceně zradí

Do populace si umístíme tyto agenty:

  • 1x naivní dobrák
  • 1x ďábelský prevít
  • 5x náhoda - agenti zrazující s pravděpodobností 5%, 15%, 30%, 50% a 75%
  • 1x oko za oko
  • 1x pozitivní testovač
  • 1x negativní testovač
  • 5x náhodný šprýmař - agenti zrazující s pravděpodobností 5%, 10%, 15%, 20% a 25%
  • 4x pořádný šprýmař - agenti zrazující vždy po 2, 3, 4 a 5 krocích

Máme tedy populaci s 19ti agenty, necháme je hrát každý s každým 10 kol hry. Výsledky mohou vypadat třeba takto (hry obsahují náhodný prvek, výsledek se tudíž může hru od hry lišit, zaškrtnuté pole znamená hru strategie C, nezaškrtuté označuje strategii D):

Simulace: Axelrodův turnaj (10 her)
... vyberte strategii... defecting cooperating tit for tat positive tester negative tester random 5% defect random 15% defect random 30% defect random 50% defect random 75% defect joss periodic 2 joss periodic 3 joss periodic 4 joss periodic 5 joss random 5% defect joss random 10% defect joss random 15% defect joss random 20% defect joss random 25% defect ... vyberte strategii... defecting cooperating tit for tat positive tester negative tester random 5% defect random 15% defect random 30% defect random 50% defect random 75% defect joss periodic 2 joss periodic 3 joss periodic 4 joss periodic 5 joss random 5% defect joss random 10% defect joss random 15% defect joss random 20% defect joss random 25% defect
Hraj vybrané strategie
0 0

Následující kód implementuje naše strategie. Začneme opět prologovským souborem s důležitými predikáty:

# exc.pl
 
bombAt(X,Y,[[X,Y]|T]).
bombAt(X,Y,[[X1,Y1]|T]):-bombAt(X,Y,T).
 
agentAt(X,Y,Z,[[Z,X,Y]|T]).
agentAt(X,Y,Z,[[Z,X1,Y1]|T]):-agentAt(X,Y,Z,T).
firstAgent(A,[[A,B,C]|T]).
 
random(From, To, Rand) :-
  Rand is int(From + random(To - From)).
 
isTrue(X):-X = true.
 
streq(X,X).
 
trueVal(X, true):-X>0.
trueVal(X, false).

A nyní již samotný 3APL program (tento soubor potřebujeme 2x pro dva agenty, musíme v každém z nich změnit název agenta - viz PROGRAM - a také umístit agenta na správné místo v prostředí - viz PLANBASE):

PROGRAM "axelrods_Agent_01"
// PROGRAM "axelrods_Agent_02"
 
LOAD "exc.pl"
 
CAPABILITIES {
// Strategy independent rules
  {true}   FoundBombsOnRight() { bombsOnRight() },
  {true}   Complete()          {endTheGame()},
  {true}   Forget()            {NOT lastOpponentsMove()},
  {true}   SetKnowCooperate()  {NOT tester(), randomPlay(3,6)},
  {true}   SetKnowDefect()     {NOT tester(), tit_for_tat(), lastOpponentsMove()},
 
// Adopting a strategy
  {true}   PlayCooperating() {cooperating()},
  {true}   PlayDefecting()   {defecting()},
  {true}   PlayTitForTat()   {tit_for_tat()},
  {true}   PlayJossPer(X,Y)  {jossPer(X,Y)},
  {true}   PlayJossRand(X,Y) {jossRand(X,Y)},
  {true}   PlayTester(X)     {tester(X)},
  {true}   PlayRandom(X,Y)   {randomPlay(X,Y)},
 
// Rules for enering the world and sensing agent
  {pos(A,B)}                 SetPos(X,Y)             {NOT pos(A,B), pos(X,Y)}
  {true}                     SetPos(X,Y)             {pos(X,Y)}
  {firstAgent(A, Opponents)} SeeOpponent(Opponents)  {agent(A)}
  {true}                     Wait()                  {waiting(), waited()}
  {true}                     CanGo()                 {NOT waiting()}
 
// RANDOM_PLAY strategy
  {randomPlay(A,B)} Strategize() {randomPlay(A,B)}
 
// ALWAYS DEFECT strategy
  {defecting()}  Strategize()  {defect()},
 
// ALWAYS COOPERATE strategy
  {cooperating()}  Strategize()  {cooperate()},
 
// TIT FOR TAT strategy
  {tit_for_tat() AND (NOT cooperate() AND NOT defect())}  Strategize() {cooperate()},
  {tit_for_tat() AND (cooperate() OR defect())}           Strategize() {NOT cooperate(), NOT defect(), lastOpponentsMove()},
 
// TESTER strategy
  {tester(X) AND first_defect() AND knowDefect()}        Strategize()  { tit_for_tat(), NOT tester(X), NOT cooperate(), NOT defect(), lastOpponentsMove()  }
  {tester(X) AND first_defect() AND knowCooperate()}     Strategize()  { randomPlay(3,6), NOT tester(X)}
  {tester(X)}                                            Strategize()  { tester(X) }
  {tester(X)}                                            FirstDefect() { first_defect() }
  {tester(X)}                                            SecondRound() { listened_to_action(), NOT first_defect() }
 
// JOSS strategy - random defect
  {jossRand(A,B) AND (NOT cooperate() AND NOT defect())}  Strategize() {cooperate()},
  {jossRand(A,B) AND (cooperate() OR defect())}           Strategize() {NOT cooperate(), NOT defect(), lastOpponentsMove()},
 
// JOSS strategy - periodical defect
  {jossPer(A,B) AND (NOT cooperate() AND NOT defect())}  Strategize()    {cooperate()},
  {jossPer(A,B) AND (cooperate() OR defect())}           Strategize()    {NOT cooperate(), NOT defect(), lastOpponentsMove()},
  {jossPer(A,B)}                                         UpdateJossPer() {NOT jossPer(A,B), jossPer(B,B)},
  {jossPer(A,B)}                                         DecJossPer()    {NOT jossPer(A,B), jossPer(A - 1,B)},
 
// Next round ...
  {pos(X,Y)}                              MoveNextRound()     {pos(X, Y + 1), NOT pos(X,Y)}
}
 
BELIEFBASE {
}
 
GOALBASE {
}
 
PLANBASE {
  EnterWorld(1, 0, tit_for_tat, 0, 0)
  // EnterWorld(4, 0, tit_for_tat, 0, 0)
}
 
PG-RULES {
  endTheGame() <- true | { OneRound(); }
}
 
 
PR-RULES {
 
  SenseBombsPosition() <- pos(X,Y) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF (bombAt(X + 1, Y, BOMBS)) THEN {
      FoundBombsOnRight();
    }
  }
 
  OneRound() <- NOT endTheGame() |
  {
    Strategize();
    WaitForOpponent();
    Step();
  }
 
  WaitForOpponent() <- agent(A) AND pos(_,Y) |
  {
    Java("BlockWorld", senseAgents(), Opponent);
    IF (agentAt(_,Yopponent,A,Opponent) AND Y > Yopponent) THEN {
      Wait();
      WaitForOpponent();
    } ELSE {
      CanGo();
    }
  }
 
  Step()  <- pos(X,Y) AND agent(A) AND NOT waiting() AND randomPlay(R1, R2) AND random(0,R2, R) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (R > R1) THEN {
        Cooperate();
      } ELSE {
        Defect();
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (lastOpponentsMove() AND tit_for_tat()) AND pos(X, Y) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (bombsOnRight() AND bombAt(X + 2, Y - 1, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 2, Y - 1, BOMBS)) THEN {
        Defect();
      } ELSE {
        Cooperate();
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (tester(Def)) AND pos(X, Y) AND NOT first_defect() AND NOT listened_to_action() |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      Defect();
      FirstDefect();
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (tester(Def)) AND pos(X, Y) AND first_defect() AND NOT listened_to_action() |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF isTrue(Def) THEN { Defect(); } ELSE { Cooperate(); };
      SecondRound();
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (tester(Def)) AND pos(X, Y) AND random(3, 6, R) AND listened_to_action() |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (bombsOnRight() AND bombAt(X + 2, Y - 1, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 2, Y - 1, BOMBS)) THEN {
        Cooperate();
        SetKnowDefect();
      } ELSE {
        IF (bombsOnRight() AND bombAt(X + 4, Y - 1, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 4, Y - 1, BOMBS)) THEN {
          IF (R < 4) THEN {
            Cooperate();
          } ELSE {
            Defect();
          };
          SetKnowCooperate();
        } ELSE {
          Defect();
        };
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (lastOpponentsMove() AND jossRand(R1,R2)) AND pos(X, Y) AND random(0,R2,R) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (bombsOnRight() AND bombAt(X + 2, Y - 1, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 2, Y - 1, BOMBS)) OR R > R1 THEN {
        Defect();
      } ELSE {
        Cooperate();
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (lastOpponentsMove() AND jossPer(R1,R2)) AND pos(X, Y) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (bombsOnRight() AND bombAt(X + 2, Y - 1, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 2, Y - 1, BOMBS)) OR (R1 < 1) THEN {
        Defect();
      } ELSE {
        Cooperate();
      };
      IF (R1 < 1) THEN {
        UpdateJossPer();
      } ELSE {
        DecJossPer();
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  Step()  <- agent(A) AND NOT waiting() AND (defect() OR cooperate()) AND pos(X, Y) |
  {
    Java("BlockWorld", senseBombs(), BOMBS);
    IF ((bombsOnRight() AND bombAt(X + 1, Y, BOMBS)) OR (NOT bombsOnRight() AND bombAt(X - 1, Y, BOMBS))) THEN {
      IF (cooperate()) THEN {
        Cooperate();
      } ELSE {
        Defect();
      };
      NextRound();
    } ELSE {
      Complete();
    }
  }
 
  NextRound() <- true |
  {
      MoveNextRound();
      Java("BlockWorld", south(), L);
  }
 
  Cooperate() <- true |
  {
    Java("BlockWorld", pickup(), L);
    IF (bombsOnRight()) THEN {
      Java("BlockWorld", east(), L);
      Java("BlockWorld", pickup(), L);
      Java("BlockWorld", west(), L);
      Java("BlockWorld", west(), L);
      Java("BlockWorld", drop(), L);
      Java("BlockWorld", east(), L);
    } ELSE {
      Java("BlockWorld", west(), L);
      Java("BlockWorld", pickup(), L);
      Java("BlockWorld", east(), L);
      Java("BlockWorld", east(), L);
      Java("BlockWorld", drop(), L);
      Java("BlockWorld", west(), L);
    };
  }
  Defect() <- true |
  {
    Java("BlockWorld", pickup(), L);
    IF (bombsOnRight()) THEN {
      Java("BlockWorld", east(), L);
      Java("BlockWorld", west(), L);
    } ELSE {
      Java("BlockWorld", west(), L);
      Java("BlockWorld", east(), L);
    };
  }
 
  EnterWorld(X, Y, Strategy, Par1, Par2) <- true |
  {
    SetPos(X,Y);
    Java("BlockWorld", enter(X,Y,-1), L);
    SenseBombsPosition();
    Java("BlockWorld", senseAgents(), Opponent);
    SeeOpponent(Opponent);
    IF (streq(Strategy,cooperate)) THEN {
      PlayCooperating();
    } ELSE {
      IF (streq(Strategy,random)) THEN {
        PlayRandom(Par1, Par2);
      } ELSE {
        IF (streq(Strategy,tit_for_tat)) THEN {
          PlayTitForTat();
        } ELSE {
          IF (streq(Strategy, always_defect)) THEN {
            PlayDefecting();
          } ELSE {
            IF (streq(Strategy, joss_periodic)) THEN {
              PlayJossPer(Par1 - 1, Par1 - 1);
            } ELSE {
              IF (streq(Strategy, joss_random)) THEN {
                PlayJossRand(Par1, Par2);
              } ELSE {
                IF (streq(Strategy, tester) AND trueVal(Par1, BOOL)) THEN {
                  PlayTester(BOOL);
                } ELSE {
                  PlayRandom(2,4);
                };
              };
            };
          };
        };
      };
    };
    AdoptGoal(endTheGame());
  }
 
}

Související články:

  • Programování inteligentních agentů - 1. díl
  • Programování inteligentních agentů - 2. díl
  • Programování inteligentních agentů - 3. díl
  • Programování inteligentních agentů - 4. díl

Komentáře čtenářů

Wu (2011-01-24 13:33:12)

Super!