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
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
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"#soupeřů"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
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
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