Net als een aantal anderen ben ik bezig met het maken van een botje voor de GoTBotContest. Voor degenen die niet op de hoogte zijn: er draaien servers waarop bots kunnen connecten en middels verschillende commando's elkaar kunnen beschieten. Ik programmeer m'n bot in PHP en heb em object georienteerd gemaakt. In dit geval betekent het dat de Bot een Brein en een Parser object bezit. De Bot houdt z'n eigen status bij: hoe lang hij al leeft, hoeveel energie er in z'n batterij zit en in welke beurt hij nu zit, verder kan de bot commando's versturen naar de server en houdt hij de logs bij.
De Parser leest de berichten die van de server binnenkomen en roept op basis daarvan functies in het brein aan, of update waarden in de bot. Het brein ten slotte reageert op berichten die binnenkomen van de server, neemt beslissingen en instrueert de bot welke commando's te versturen naar de server.
Het probleem zit hem in het opslaan van de gegevens die in de Parser binnenkomen in de bot. Beide opbjecten kennen elkaar: eerst wordt het brein aangemaakt, dan de bot, die een reference van dat brein binnenkrijgt en zelf een nieuwe Parser maakt. Daarna wordt het brein wordt opgestart met een reference naar de bot; het testscript ziet er dan als volgt uit:
Nog wat meer stukjes interessante code:
Variabelen en constructor van ToiletBot:
Dan hetzelfde voor GotBotParser:
Welnu, op naar de code waar het fout gaat:
Let op de uitgecommente probeersels, daar kom ik later nog even op terug
Dit levert de volgende output op:
Dat ziet er prima uit toch, wat is er dan mis... nou als we gaan kijken in de bot zelf:
Dan zou je denken dat het statusstukje nu zou moeten weergeven dat de batterij vol, is we in turn 22950 zitten en dat m'n lifeTime 7 is.
Echter:
0... hoe kan dat nou? We hadden die variabelen toch net veranderd? Om de lifetime te updaten gebruiken we zelfs een functie binnen de bot zelf, die ons eerder nog vertelde dat de lifeTime toch echt 7 is....
Dit is de functie:
Als ik de functie updateLifeTime() iedere loop aanroep vanuit de bot zelf, gaat het wel goed, dan gaat de lifeTime teller wel lopen. Het is toch compleet belachelijk dat hij het dus niet doet als de functie wordt aangeroepen vanuit een ander object?
Verder heb ik geprobeerd om hem te veranderen als ik hem als reference meegeef aan het processTurn commando van GotBotParser, ook dit werkt.
Ten slotte heb ik nog een testscript gemaakt waarin ik dezelfde situatie namaak in een simpele setting (2 classes en wat simpele functies) ook daar werkt het allemaal gewoon.
Ik heb dagen naar mijn code zitten staren om uit te vissen wat er nou mis is, maar ik zie geen rare dingen in m'n code. Mijn vraag is dus: zien jullie die wel, of doet PHP gewoon ontzettend vaag
.
Ik heb de code maar geupload, zodat mensen niet afhankelijk zijn van de hier geposte snippets:
testscript en de complete code van de bot(excuse the filename).
De Parser leest de berichten die van de server binnenkomen en roept op basis daarvan functies in het brein aan, of update waarden in de bot. Het brein ten slotte reageert op berichten die binnenkomen van de server, neemt beslissingen en instrueert de bot welke commando's te versturen naar de server.
Het probleem zit hem in het opslaan van de gegevens die in de Parser binnenkomen in de bot. Beide opbjecten kennen elkaar: eerst wordt het brein aangemaakt, dan de bot, die een reference van dat brein binnenkrijgt en zelf een nieuwe Parser maakt. Daarna wordt het brein wordt opgestart met een reference naar de bot; het testscript ziet er dan als volgt uit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
| $hermanBrein = new GotBotBrains; $herman = new ToiletBot("Quitter","herman",& $hermanBrein); $hermanBrein->startup(& $herman); if(!$herman->startConnections()){ // doe niets } else if(!$herman->startBot()){ // doe niets } else if(!$herman->runBot()){ // doe niets } echo "klaar!"; |
Nog wat meer stukjes interessante code:
Variabelen en constructor van ToiletBot:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| // Eigen variabelen/objecten /***************************/ var $displev; var $name; var $pass; var $fp; //verbinding naar de server var $ears; // eigen object dat de stream uitleest en afhankelijk van de daar gekregen info messages dispatched naar Brains var $battery; //var $mySQLDB; // eigen object dat de verbinding met de mySQLDB onderhoudt en waar dus ook alle mysql functies zijn ondergebracht var $brains; // eigen object dat de beslissingen neemt, z'n eigen geheugen beheert en de waarden van het object vaststelt var $startTime; // tijd waarop het script aangeroepen wordt var $receivedTurnTime; // tijd waarop het script nieuwe turns binnenkrijgt (en het spel dus eigenlijk is begonnen) var $sentTurnTime; // tijd waarop een beurt aan deze kant is doorlopen var $endOfLoopTime; // tijd waarop het script totaal klaar is met zijn beurt (inclusief wegschrijven naar DB enzo) var $lifeTime; // levenstijd van de bot (in turns) var $turnID; var $out; //outputbuffer var $quit; // logs var $comLog; // logt de communicatie & timestamps. var $brainLog; // geeft AI-gegevens weer. // Stap 0 // Constructor function Toiletbot($name,$pass="onzin", & $brains){ $this->displev=MSGTYPE_STATUS+MSGTYPE_ERROR+MSGTYPE_AI+MSGTYPE_INC+MSGTYPE_OUT;//+MSGTYPE_DEBUG; $this->log("In Toiletbot Constructor",MSGTYPE_DEBUG); $this->startTime=microtime_float(); //$this->mySQLDB=new MySQLDB; // CONSTRUCTOR MOET NOG GEMAAKT $this->name=$name; //WAAROM IS NAME ROOD??? geen idee, stomme highlighting?! $this->pass=$pass; $this->ears=new GotBotParser($this); $this->brains=& $brains; $this->lifeTime=0; $this->turnID=0; $this->battery=0; $this->out=""; $this->quit=false; $this->log("I was born at $this->startTime",MSGTYPE_STATUS); } /**** [SNIP]****/ |
Dan hetzelfde voor GotBotParser:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| var $fp; var $bot; var $newcommand; var $input; var $receiveTime; var $expectScanRes; var $expectFireRes; var $numMessages; var $newCommand; function GotBotParser(&$bot){ $this->bot=&$bot; $this->bot->log("In GotBotParser Constructor",MSGTYPE_DEBUG); $this->fp=&$bot->fp; $this->input=""; $this->expectScanRes=false; $this->expectFireRes=false; $this->numMessages=0; $this->newCommand=false; } /**** [SNIP]****/ |
Welnu, op naar de code waar het fout gaat:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| function processTURN(&$errstr, & $lifeTime){ $this->bot->log("In GotBotParser processTURN(), myBot: ".$this->bot->name,MSGTYPE_DEBUG); $startOfTurn=true; do{ if(!$this->isERROR()) { // isERROR() heeft hier net een nieuwe regel opgehaald if($startOfTurn && strpos($this->input, "NEWTURN")===0 ){ $this->bot->log("In GotBotParser processTURN(): NEWTURN",MSGTYPE_DEBUG); $this->newCommand=false; $tempArray=split(' ',$this->input); $this->bot->turnID=$tempArray[1]; $this->bot->log("#### turnID: $tempArray[1], in de bot: ".$this->bot->turnID." ### ",MSGTYPE_STATUS); $this->numMessages=$tempArray[2]; $this->bot->battery=$tempArray[3]; $this->bot->log("#### battery: $tempArray[3], in de bot: ".$this->bot->battery." ### ",MSGTYPE_STATUS); //$lifeTime=$lifeTime+1; dit werkt wel als & $lifeTime als parameter wordt meegegeven $this->bot->updateLifeTime(); // dit werkt niet... zo ontzettend vaag! Als hij van binnenin de bot wordt aangeroepen doet hij het wel... $this->bot->log("### lifeTime: ".$this->bot->lifeTime." ### ",MSGTYPE_STATUS); $startOfTurn=false; continue; // het aantal nog te komen berichten is vastgelegd, we komen hier nu niet meer terug, meteen door naar de conditie } /**** [SNIP] ****/ |
Let op de uitgecommente probeersels, daar kom ik later nog even op terug
Dit levert de volgende output op:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| DEBUG 1123109601.04 : In GotBotParser processTURN(), myBot: Quitter DEBUG 1123109601.04 : In GotBotParser isERROR() DEBUG 1123109601.04 : In GotBotParser getCommand() DEBUG 1123109601.04 : In GotBotParser getCommand(), streamlees gedeelte DEBUG 1123109601.04 : In GotBotParser getCommand(): start do-while-loop DEBUG 1123109603.04 : In GotBotParser getCommand(): na fgets: NEWTURN 22950 0 100 DEBUG 1123109603.04 : In GotBotParser getCommand(): na do-while-loop: NEWTURN 22950 0 100 SERVER <<< 1123109603.04 NEWTURN 22950 0 100 DEBUG 1123109603.04 : In GotBotParser isERROR(), returning false DEBUG 1123109603.04 : In GotBotParser processTURN(): NEWTURN STATUS: #### turnID: 22950, in de bot: 22950 ### STATUS: #### battery: 100 , in de bot: 100 ### DEBUG 1123109603.04 : in Toiletbot updateLifeTime(), lifeTime: 7 STATUS: ### lifeTime: 8 ### DEBUG 1123109603.04 : In GotBotParser processTURN(): einde functie |
Dat ziet er prima uit toch, wat is er dan mis... nou als we gaan kijken in de bot zelf:
PHP:
1
2
3
4
5
6
7
8
9
10
11
| function runBot(){ $this->log("In Toiletbot runBot",MSGTYPE_DEBUG); while(!feof($this->fp)&&!$this->quit){ //$this->updateLifeTime(); dit werkt wel $this->log("In GotBotParser runBot(), binnen main loop",MSGTYPE_DEBUG); $this->log("Lifetime: ".$this->lifeTime.", Battery: ".$this->battery.", turnID: ".$this->turnID,MSGTYPE_STATUS); if(!$this->ears->processTURN($errstr,& $this->lifeTime)){ $this->log("There's something wrong with the NEWTURN: $errstr",MSGTYPE_ERROR); return false; } /**** [SNIP ****/ |
Dan zou je denken dat het statusstukje nu zou moeten weergeven dat de batterij vol, is we in turn 22950 zitten en dat m'n lifeTime 7 is.
Echter:
code:
1
2
3
4
5
| DEBUG 1123109603.04 : In ToiletBot runBot, hierna zou brains aan de slag moeten DEBUG 1123109603.04 : In GotBotBrains work(), myBot: Quitter DEBUG 1123109603.04 : In Toiletbot flushOut() DEBUG 1123109603.04 : In GotBotParser runBot(), binnen main loop STATUS: Lifetime: 0, Battery: 0, turnID: 0 |
0... hoe kan dat nou? We hadden die variabelen toch net veranderd? Om de lifetime te updaten gebruiken we zelfs een functie binnen de bot zelf, die ons eerder nog vertelde dat de lifeTime toch echt 7 is....
Dit is de functie:
PHP:
1
2
3
4
| function updateLifeTime(){ $this->log("in Toiletbot updateLifeTime(), lifeTime: ".$this->lifeTime,MSGTYPE_DEBUG); $this->lifeTime++; } |
Als ik de functie updateLifeTime() iedere loop aanroep vanuit de bot zelf, gaat het wel goed, dan gaat de lifeTime teller wel lopen. Het is toch compleet belachelijk dat hij het dus niet doet als de functie wordt aangeroepen vanuit een ander object?
Verder heb ik geprobeerd om hem te veranderen als ik hem als reference meegeef aan het processTurn commando van GotBotParser, ook dit werkt.
Ten slotte heb ik nog een testscript gemaakt waarin ik dezelfde situatie namaak in een simpele setting (2 classes en wat simpele functies) ook daar werkt het allemaal gewoon.
Ik heb dagen naar mijn code zitten staren om uit te vissen wat er nou mis is, maar ik zie geen rare dingen in m'n code. Mijn vraag is dus: zien jullie die wel, of doet PHP gewoon ontzettend vaag
Ik heb de code maar geupload, zodat mensen niet afhankelijk zijn van de hier geposte snippets:
testscript en de complete code van de bot(excuse the filename).
Only dead fish go with the flow