Merge branch 'c-agents'
authorDaniel Axtens <[email protected]>
Tue, 14 Sep 2010 16:26:55 +0000 (00:26 +0800)
committerDaniel Axtens <[email protected]>
Tue, 14 Sep 2010 16:26:55 +0000 (00:26 +0800)
* c-agents:
  C++ documentation
  C documentation
  documentation to support uuid passing
  Implemented UUID passing in externAgent and C. Enabled externAgents to print debug messages to stderr
  Fixed UUID string length (curse you python)
  Added support for HI command (C can now see UUID)
  changed externAgent so as to never permit more than MAX_TOTAL_AGENTS to exist
  applied TPG's patch, fixed wash

13 files changed:
doc/UNSUPPORTED.txt
src/link/C/PLUSPLUS.txt [new file with mode: 0644]
src/link/C/README [deleted file]
src/link/C/README.txt [new file with mode: 0644]
src/link/C/WINDOWS.txt [new file with mode: 0644]
src/link/C/agents/c_angel.c [changed mode: 0644->0755]
src/link/C/agents/c_lucifer.c [changed mode: 0644->0755]
src/link/C/agents/c_streetfighter.c [changed mode: 0644->0755]
src/link/C/agents/c_wash.c [new file with mode: 0644]
src/link/C/c_agents.py
src/link/C/c_link.c [changed mode: 0644->0755]
src/link/C/c_link.h [changed mode: 0644->0755]
src/link/externAgent.py

index 7d665b0..64991c5 100644 (file)
@@ -7,10 +7,13 @@ If you are interested in using an unsupported language, consult the website for
 The syntax for input and output is as follows. Every line of input given by the supervisor must be replied with the correct response.
 Segmentation fault is never the correct response :-). Rumour has it that if you just use Python, this won't happen. 
 
-The angle brackets (<>) indicate whether the line is output from the agent or input to it respectively, and are not part of the actual formatting.
+The angle brackets (<>) indicate whether the line is output from the agent or input to it respectively, and are not part of the actual formatting
+
+Canonical lengths of the following strings are in src/link/C/c_link.[ch]
 
 Syntax for when your agent is spawned:
 >HI uuid
+{no response}
 
 Syntax for an attacking agent:
 >ATTACK foeName
diff --git a/src/link/C/PLUSPLUS.txt b/src/link/C/PLUSPLUS.txt
new file mode 100644 (file)
index 0000000..9df2929
--- /dev/null
@@ -0,0 +1,12 @@
+PLUSPLUS.txt: A guide to using C++
+
+C++ is officially supported, but (much like Windows) entirely untested 
+at present. In theory, using it should simply require you to develop 
+your agent in C++, compile it, and link it with c_link - just as for a C 
+agent.
+
+However, the makefile will *not* build your agent if it does not end in 
+".c". This is a bug, and hopefully we'll get around to fixing it soon. 
+In the mean time, you will have to either fix the makefile (please send 
+me a copy at [email protected] if you do) or simply manually 
+compile your agent.
diff --git a/src/link/C/README b/src/link/C/README
deleted file mode 100644 (file)
index ad894a7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Welcome to the C SDK and link library.
-
-If you want to enter in C, you've come to the right place.
-
-== Compiling and testing the sample bots ==
-
-Run "make" in this directory. To include them in the 
-
-== Making your own agent ==
-See wiki page.
-
-Also, use the link/bundle-agent.sh shell script - it will take your agent file
-and make a python module that you can include.
-
-= Testing your own agent =
-Edit src/simulate.py.
-Your agents live in link.C.c_agents
-Add them to Agents to get them to do battle.
-
-For example, this code imports c_angel, c_lucifer, c_streetfighter and
-c_wash, as well as the python sample agents, and then battles c_lucifer, 
-python Wash, c_streetfighter and c_angel. It goes at the top of simulate.py.
-
-# Import and add your agents here:
-from link.C.c_agents import c_angel, c_lucifer, c_streetfighter, c_wash
-
-from SampleAgents import Angel, Lucifer, Dummy, Wash, Streetfighter
-Agents = [c_lucifer, Wash, c_streetfighter, c_angel]
-
diff --git a/src/link/C/README.txt b/src/link/C/README.txt
new file mode 100644 (file)
index 0000000..e93d251
--- /dev/null
@@ -0,0 +1,82 @@
+Welcome to the C SDK and link library.
+
+If you want to enter in C, you've come to the right place.
+
+== Compiling and watching the sample bots in 2 easy steps ==
+
+Run "make" in this directory. [NB: this document assumes you use Linux 
+or Mac OS X. If you use Windows, see WINDOWS.txt for instructions.]
+
+Go to the src/ directory and run "./simulate.py -v -a CSampleAgents".
+
+== Making your own agent with C in 11 easy steps ==
+
+0. Flick through the documentation.
+
+1. Pick a name for your agent. Make sure the name is a valid identifier 
+in both C and Python. Be original. Names do *not* have to be prefixed 
+with "c_"
+
+2. Flick through the sample agents in the agents directory.  Pick a 
+sample agent to copy-paste (so you don't have to type out the function 
+definitions).
+
+3. Copy the sample agent code into a new file in the "agents" directory. 
+Make sure the file name matches the new agent name. The makefile will 
+automatically compile your new agent when you run "make".
+
+4. Create a python wrapper for your agent, by copying one of the sample 
+agent definitions in c_agents.py and using the name of your agent.
+
+5. Create an arena in which your agent can battle:
+
+   5.1. open arenas/MyArena.py
+
+   5.2. add "from link.C.c_agents import <youragentname>"
+
+   5.3. modify the "Agents =" line to include your agent, and take out 
+any agents you don't want to battle.
+
+   5.4. to see how to import the C sample agents, see CSampleAgents.py.
+
+6. Watch your agent in action: ./simulate -v -a MyArena
+
+7. Oh no, my agent dies very quickly: what's going on?
+
+   7.1 insert debugmsg() statements in your C program.
+        
+        7.1.1 debugmsg() is like printf - see c_link.h for an example.
+
+        7.1.2 in Initialise(), save the name that's passed to you so 
+that you can uniquely identify your agent when you're printing debug 
+statements.
+
+   7.2 Run "./simulate -v -n 1 -a MyArena" to start with only 1 of each 
+agent.
+
+   7.3 Change the agents against which you're battling in MyArena.py so 
+that you have a predictable opponent.
+
+   7.4 Edit conf.py, and set DEBUG=True. Don't forget to reset it when 
+you're done.
+
+   7.5 Read doc/UNSUPPORTED.txt to see how to interact directly with 
+your agent. You can then invoke your agent from the command line 
+(for example "./link/C/agents/c_angel") and see how it responds.
+
+8. Once your agent works to your satisfaction, try it both on short and 
+long durations (100 and 1000 rounds: see MAX_ITERATIONS in conf.py)
+
+9. If the rolling scoreboard has been opened on progcomp.ucc.asn.au/, 
+submit it there! Otherwise, sit tight.
+
+10. Watch its progress on the scoreboard and adjust your strategy 
+accordingly.
+
+=== OTHER IMPORTANT NOTES ===
+
+ * Static storage *is* *considered* *cheating*. You must *not* attempt 
+to communicate between instances of your agent in any way other than by 
+sequences of moves.
+
+ * Obfuscated code is bad. Don't do it.
diff --git a/src/link/C/WINDOWS.txt b/src/link/C/WINDOWS.txt
new file mode 100644 (file)
index 0000000..d167e2b
--- /dev/null
@@ -0,0 +1,38 @@
+WINDOWS.txt: Notes towards using C under Microsoft Windows.\r
+\r
+Whilst we are committed to supporting Windows, unfortunately Windows \r
+support is not complete at this point. Whilst there is nothing in the \r
+code that is specifically incompatible with Windows, it is entirely \r
+untested, and there may be a number of tweaks that Windows users will \r
+have to make in order to compete.\r
+\r
+ = Options for Windows Users =\r
+\r
+ - Install a *nix compatibility layer, such as Cygwin or MinGW, which \r
+will allow you to develop as if on Linux. This is *by* *far* the \r
+simplest route: everything should, in theory, just work. However, it's \r
+untested.\r
+\r
+ - Attempt to use native Windows tools. If you choose to go down this \r
+path, note the following:\r
+    - agents are compiled by linking c_link together with the agent \r
+source.\r
+    - c_agents would need to be modified to use windows style paths \r
+instead of POSIX paths.\r
+    - The externAgent wrapper may need to be tweaked.\r
+\r
+Either way, be aware that the supervisor will spawn a *lot* of processes \r
+- up to 255 child processes. How Windows will cope with that, is, as \r
+mentioned before, totally untested.\r
+\r
+ = Alternatives =\r
+\r
+There are some alternatives to development in Windows that may be open \r
+to you:\r
+ - If you are a CS or Engineering student at UWA, use Mac or Linux \r
+machines in the CS labs.\r
+ - If you are a UCC member, use either our Mac or one of the Linux \r
+machines.\r
+\r
+These environments, if available to you, are preferable to development \r
+on Windows.\r
old mode 100644 (file)
new mode 100755 (executable)
index 62e2147..d11b551
@@ -1,41 +1,45 @@
-/*
- *  c_angel.c
- *  c-link-lib
- *
- *  Created by Daniel Axtens on 20/04/10.
- *  Licensed under an MIT-style license: see the LICENSE file for details.
- *
- */
-
-#include <c_link.h>
-
-/* Implement the angel bot, which always tells the truth
-   and expects others to do the same */
-
-ATTACKTYPE Attack( char * foe_name ) {
-       ATTACKTYPE attack;
-       
-       attack.realAttack =  RandomAttack();            /* Chooses randomly from Rock, Paper, Scissors */ 
-       attack.promisedAttack = attack.realAttack;      /* Tells the truth for its bluff */
-
-       return attack;
-}
-
-ITEMTYPE Defend( char * foeName, ITEMTYPE foePromisedAttack ) {
-       return foePromisedAttack;       /* Trusts them to be going for a tie */
-}
-
-/* You need to define a results function, even if it isn't used
-   (otherwise the linker will complain) */
-void Results( char * foeName, int isInstigatedByYou, RESULTTYPE winner,
-             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,
-             int pointDelta ) {
-       
-       return; /* Ignore whatever just happened. */
-}
-
-/* same for Cleanup() */
-
-void Cleanup() {
-       return;
-}
\ No newline at end of file
+/*\r
+ *  c_angel.c\r
+ *  c-link-lib\r
+ *\r
+ *  Created by Daniel Axtens on 20/04/10.\r
+ *  Licensed under an MIT-style license: see the LICENSE file for details.\r
+ *\r
+ */\r
+\r
+#include <c_link.h>\r
+\r
+void * Initialise( char * me ) {\r
+       return NULL;\r
+}\r
+\r
+/* Implement the angel bot, which always tells the truth\r
+   and expects others to do the same */\r
+\r
+ATTACKTYPE Attack( void * this, char * foe_name ) {\r
+       ATTACKTYPE attack;\r
+       \r
+       attack.realAttack =  RandomAttack();            /* Chooses randomly from Rock, Paper, Scissors */ \r
+       attack.promisedAttack = attack.realAttack;      /* Tells the truth for its bluff */\r
+\r
+       return attack;\r
+}\r
+\r
+ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack ) {\r
+       return foePromisedAttack;       /* Trusts them to be going for a tie */\r
+}\r
+\r
+/* You need to define a results function, even if it isn't used\r
+   (otherwise the linker will complain) */\r
+void Results( void * this, char * foeName, int isInstigatedByYou, RESULTTYPE winner,\r
+             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,\r
+             int pointDelta ) {\r
+       \r
+       return; /* Ignore whatever just happened. */\r
+}\r
+\r
+/* same for Cleanup() */\r
+\r
+void Cleanup( void * this ) {\r
+       return;\r
+}\r
old mode 100644 (file)
new mode 100755 (executable)
index f497366..8325840
@@ -1,67 +1,71 @@
-/*
- *  c_lucifer.c
- *  c-link-lib
- *
- *  Created by Daniel Axtens on 20/04/10.
- *  Licensed under an MIT-style license: see the LICENSE file for details.
- *
- */
-
-
-#include <c_link.h>
-
-/* Implement the lucifer bot, which always lies expecting people to be good
-   and always goes for the kill */
-
-ATTACKTYPE Attack( char * foe_name ) {
-       ATTACKTYPE attack;
-       
-       attack.realAttack =  RandomAttack();
-       
-       /* Here we choose the thing that will hurt them if they go for a tie */
-       switch (attack.realAttack) {
-               case rock:
-                       attack.promisedAttack = scissors;
-                       break;
-               case paper:
-                       attack.promisedAttack = rock;
-                       break;
-               default: /* attack = scissors */
-                       attack.promisedAttack = paper;
-                       break;
-       }
-       
-       return attack;
-}
-
-/* Here we trust that they are telling the truth. And we try to kill them. */
-ITEMTYPE Defend( char * foeName, ITEMTYPE foePromisedAttack ) {
-       ITEMTYPE defence;
-       switch (foePromisedAttack) {
-               case rock:
-                       defence = paper;
-                       break;
-               case paper:
-                       defence = scissors;
-                       break;
-               default:
-                       defence = rock;
-                       break;
-       }
-    return defence;
-}
-
-/* You need to define a results function, even if it isn't used
- (otherwise the linker will complain) */
-void Results( char * foeName, int isInstigatedByYou, RESULTTYPE winner,
-             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,
-             int pointDelta ) {
-       
-       return; /* Ignore whatever just happened. */
-}
-
-/* same for Cleanup() */
-
-void Cleanup() {
-       return;
-}
\ No newline at end of file
+/*\r
+ *  c_lucifer.c\r
+ *  c-link-lib\r
+ *\r
+ *  Created by Daniel Axtens on 20/04/10.\r
+ *  Licensed under an MIT-style license: see the LICENSE file for details.\r
+ *\r
+ */\r
+\r
+\r
+#include <c_link.h>\r
+\r
+/* Implement the lucifer bot, which always lies expecting people to be good\r
+   and always goes for the kill */\r
+\r
+void * Initialise( char * myName ) {\r
+       return NULL;\r
+}\r
+\r
+ATTACKTYPE Attack( void * this, char * foe_name ) {\r
+       ATTACKTYPE attack;\r
+       \r
+       attack.realAttack =  RandomAttack();\r
+       \r
+       /* Here we choose the thing that will hurt them if they go for a tie */\r
+       switch (attack.realAttack) {\r
+               case rock:\r
+                       attack.promisedAttack = scissors;\r
+                       break;\r
+               case paper:\r
+                       attack.promisedAttack = rock;\r
+                       break;\r
+               default: /* attack = scissors */\r
+                       attack.promisedAttack = paper;\r
+                       break;\r
+       }\r
+       \r
+       return attack;\r
+}\r
+\r
+/* Here we trust that they are telling the truth. And we try to kill them. */\r
+ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack ) {\r
+       ITEMTYPE defence;\r
+       switch (foePromisedAttack) {\r
+               case rock:\r
+                       defence = paper;\r
+                       break;\r
+               case paper:\r
+                       defence = scissors;\r
+                       break;\r
+               default:\r
+                       defence = rock;\r
+                       break;\r
+       }\r
+    return defence;\r
+}\r
+\r
+/* You need to define a results function, even if it isn't used\r
+ (otherwise the linker will complain) */\r
+void Results( void * this, char * foeName, int isInstigatedByYou, RESULTTYPE winner,\r
+             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,\r
+             int pointDelta ) {\r
+       \r
+       return; /* Ignore whatever just happened. */\r
+}\r
+\r
+/* same for Cleanup() */\r
+\r
+void Cleanup( void * this ) {\r
+       return;\r
+}\r
old mode 100644 (file)
new mode 100755 (executable)
index 39a8cda..3ddf697
@@ -1,65 +1,69 @@
-/*
- *  c_streetfighter.c
- *  c-link-lib
- *
- *  Created by Daniel Axtens on 20/04/10.
- *  Licensed under an MIT-style license: see the LICENSE file for details.
- *
- */
-
-
-#include <c_link.h>
-
-/* Implement the streetfighter bot, which thinks everyone has it in for him. */
-
-ATTACKTYPE Attack( char * foe_name ) {
-       ATTACKTYPE attack;
-       
-       attack.realAttack =  RandomAttack();
-       
-       /* Here we choose the thing that will hurt them if they go for the kill */
-       switch (attack.realAttack) {
-               case rock:
-                       attack.promisedAttack = paper;
-                       break;
-               case paper:
-                       attack.promisedAttack = scissors;
-                       break;
-               default: /* attack = scissors */
-                       attack.promisedAttack = rock;
-                       break;
-       }
-       return attack;
-}
-
-/* Here we assume they are lying, trying to kill us. And we try to kill them. */
-ITEMTYPE Defend( char * foeName, ITEMTYPE foePromisedAttack ) {
-       ITEMTYPE defence;
-       switch (foePromisedAttack) {
-               case rock:
-                       defence = scissors;
-                       break;
-               case paper:
-                       defence = rock;
-                       break;
-               default:
-                       defence = paper;
-                       break;
-       }
-    return defence;
-}
-
-/* You need to define a results function, even if it isn't used
- (otherwise the linker will complain) */
-void Results( char * foeName, int isInstigatedByYou, RESULTTYPE winner,
-             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,
-             int pointDelta ) {
-       
-       return; /* Ignore whatever just happened. */
-}
-
-/* same for Cleanup() */
-
-void Cleanup() {
-       return;
-}
+/*\r
+ *  c_streetfighter.c\r
+ *  c-link-lib\r
+ *\r
+ *  Created by Daniel Axtens on 20/04/10.\r
+ *  Licensed under an MIT-style license: see the LICENSE file for details.\r
+ *\r
+ */\r
+\r
+\r
+#include <c_link.h>\r
+\r
+/* Implement the streetfighter bot, which thinks everyone has it in for him. */\r
+\r
+void * Initialise( char * myName ) {\r
+       return NULL;\r
+}\r
+\r
+ATTACKTYPE Attack( void * this, char * foe_name ) {\r
+       ATTACKTYPE attack;\r
+       \r
+       attack.realAttack =  RandomAttack();\r
+       \r
+       /* Here we choose the thing that will hurt them if they go for the kill */\r
+       switch (attack.realAttack) {\r
+               case rock:\r
+                       attack.promisedAttack = paper;\r
+                       break;\r
+               case paper:\r
+                       attack.promisedAttack = scissors;\r
+                       break;\r
+               default: /* attack = scissors */\r
+                       attack.promisedAttack = rock;\r
+                       break;\r
+       }\r
+       return attack;\r
+}\r
+\r
+/* Here we assume they are lying, trying to kill us. And we try to kill them. */\r
+ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack ) {\r
+       ITEMTYPE defence;\r
+       switch (foePromisedAttack) {\r
+               case rock:\r
+                       defence = scissors;\r
+                       break;\r
+               case paper:\r
+                       defence = rock;\r
+                       break;\r
+               default:\r
+                       defence = paper;\r
+                       break;\r
+       }\r
+    return defence;\r
+}\r
+\r
+/* You need to define a results function, even if it isn't used\r
+ (otherwise the linker will complain) */\r
+void Results( void * this, char * foeName, int isInstigatedByYou, RESULTTYPE winner,\r
+             ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,\r
+             int pointDelta ) {\r
+       \r
+       return; /* Ignore whatever just happened. */\r
+}\r
+\r
+/* same for Cleanup() */\r
+\r
+void Cleanup( void * this ) {\r
+       return;\r
+}\r
diff --git a/src/link/C/agents/c_wash.c b/src/link/C/agents/c_wash.c
new file mode 100644 (file)
index 0000000..a5ab716
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  c_frechie.c
+ *  c-link-lib
+ *
+ *  Created by Daniel Axtens on 22/04/10.
+ *  Licensed under an MIT-style license: see the LICENSE file for details.
+ *
+ */
+
+#include <c_link.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Implement the wash agent, that is by default nice but will 
+   permanently turn against any agent that betrays it.
+   This is trickier in C than in any other language, for a number of reasons:
+     - there's no classes in C, so we can't just write a generic learning agent
+       and subclass it.
+     - your agent has no idea how many agents it's going to battle, or how many
+       battles it is going to fight, so you've got to do dynamic memory allocation.
+        (anyone who tries to read the source of the supervisor to find out is liable
+         to have their program break unexpectedly)
+ */
+
+/* To simplify things, we just look at whether we have lost to a particular agent.
+   Unlike in the Python version, we don't keep a generic list
+   This is also done in a inefficient (O(bot-cout)) way.
+   Implementing a faster version is left as an exercise to the DSA student. */
+
+/* Our guess at the number of agents I'm going to fight in my lifetime
+   (note that this is only a guess, not an upper limit. Do *not* take it as 
+   gospel on the number of agents you're going to see. */
+#define NUMBEROFAGENTSGUESS 100
+
+/* data for each instance of my agent */
+typedef struct {
+       /* The name of the n-th foe who has beaten us */
+       char (*defeatingFoes)[MAXAGENTNAMELEN];
+
+       /* The length of the array, and how far we are along it */
+       size_t foesLen;
+       unsigned int foesCount;
+} wash_data;
+
+
+/* an internal function - have I lost to a given foe? */
+int haveLostTo( wash_data * me, char * foeName ) {
+    
+       int foe;
+    
+    /* check every foe we know to have defeated us */
+    for (foe=0; foe<me->foesCount; foe++) {
+        if (strncmp( me->defeatingFoes[foe], foeName, MAXAGENTNAMELEN) == 0) {
+            //debugmsg( "%d\thaveLostTo( %s ) -> Yes\n", me, foeName );
+            return 1;
+        }
+    }
+    
+    /* this foe not found */
+    return 0;
+}
+
+/* set up myself */
+void * Initialise( char * myName ) {
+       wash_data * me = malloc( sizeof( wash_data ) );
+       
+       me->defeatingFoes = calloc( NUMBEROFAGENTSGUESS, sizeof( MAXAGENTNAMELEN*sizeof(char) ) );
+       me->foesLen = NUMBEROFAGENTSGUESS;
+    me->foesCount = 0;
+       
+       return (void *) me;
+}
+
+/* Attack */
+ATTACKTYPE Attack( void * this, char * foeName ) {
+       wash_data * me = (wash_data *)this;
+    
+       ATTACKTYPE attack;
+       
+       attack.realAttack =  RandomAttack();
+       
+    /* have I lost to this foe? */
+    if ( haveLostTo(me, foeName) ) {
+        /* Assume they are lying  */
+        switch (attack.realAttack) {
+            case rock:
+                attack.promisedAttack = scissors;
+                break;
+            case paper:
+                attack.promisedAttack = rock;
+                break;
+            default: /* attack = scissors */
+                attack.promisedAttack = paper;
+                break;
+        }
+    } else {
+        /* be nice! */
+        attack.promisedAttack = attack.realAttack;
+    }
+
+       
+       return attack;
+}
+
+/* defend */
+ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack ) {
+       wash_data * me = (wash_data *)this;
+       
+       ITEMTYPE defence;
+       
+    if (haveLostTo(me, foeName)) {
+        /* They've screwed us in the past, assume they're lying and go for the
+           kill. */
+        switch (foePromisedAttack) {
+            case rock:
+                defence = scissors;
+                break;
+            case paper:
+                defence = rock;
+                break;
+            default:
+                defence = paper;
+                break;
+        }
+    } else {
+        /* be nice! */
+        defence = foePromisedAttack;
+    }
+
+    return defence;
+}
+
+/* This is so much less fun in C */
+void Results( void * this, char * foeName, int isInstigatedByYou, 
+                        RESULTTYPE winner, ITEMTYPE attItem, ITEMTYPE defItem, 
+                        ITEMTYPE bluffItem, int pointDelta ) {
+       
+    wash_data * me = (wash_data *)this;
+       
+       int foe;
+    
+    /* figure out if we lost, which is the only thing we care about
+       if we didn't, move on. */
+    if ((winner == tie) || 
+        (winner==attacker && isInstigatedByYou) ||
+        (winner==defender && !isInstigatedByYou) ) return;
+    
+    //fprintf( stderr, "%d\tsaving loss from %s\n", me, foeName );
+    
+    /* if we've already lost the foe, don't store again */
+    for (foe=0; foe<me->foesCount; foe++) {
+        if (strncmp( me->defeatingFoes[foe], foeName, MAXAGENTNAMELEN ) == 0) {
+            /* we've found it! */
+            return;
+        }
+    }
+    
+    /* we haven't found the foe. add it, expanding the array if needed */
+    if (me->foesCount==me->foesLen) {
+        /* double the array size. This should error check, but doesn't */
+        me->defeatingFoes = realloc( me->defeatingFoes, 
+                                            me->foesLen*2*sizeof( MAXAGENTNAMELEN*sizeof(char) ) );
+        me->foesLen *= 2;
+    }
+    
+    strncpy( me->defeatingFoes[me->foesCount], foeName, MAXAGENTNAMELEN );
+    me->foesCount++;
+    
+    return;
+}
+
+/* Cleanup */
+void Cleanup( void * this ) {
+       wash_data * me = (wash_data *) this;
+       free(me->defeatingFoes);
+       free(me);
+}
\ No newline at end of file
index aabdc23..ed461b5 100644 (file)
@@ -1,5 +1,5 @@
 # add your agents to this file by copying the definition and adjusting
-# you then need to modify simulate.py
+# you then need to make sure there's an arena that imports your agent
 
 from link.cAgent import cAgent
 
old mode 100644 (file)
new mode 100755 (executable)
index fdb1ffc..524697d
-/*
- *  c_link.c
- *  c-link-lib
- *
- *  Created by Daniel Axtens on 19/04/10.
- *  Licensed under an MIT-style license: see the LICENSE file for details.
- *
- */
-
-#include "c_link.h"
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-
-/* You don't need to read this file.
-   All you have to do is implement the bot functions defined in <c_link.h>
-   This file sets up the I/O for you, as well as some utility functions and tables. 
- */
-
-char ITEMNAMES[3][MAXITEMLEN] = {"Rock", "Paper", "Scissors"};
-
-/* rock-rock     rock-paper     rock-scissors 
-   paper-rock    paper-paper    paper-scissors
-   scissors-rock scissors-paper scissors-scissors */  
-   
-RESULTTYPE RESULTOF[3][3] = { { tie, defender, attacker },
-                              { attacker, tie, defender },
-                              { defender, attacker, tie } };
-
-
-ITEMTYPE RandomAttack() {
-       return (ITEMTYPE)rand()%3;
-}
-
-ITEMTYPE stringToItem( char * str ) {
-       if (strcasecmp( str, "Rock" ) == 0) return rock;
-       if (strcasecmp( str, "Paper" ) == 0) return paper;
-       if (strcasecmp( str, "Scissors" ) == 0) return scissors;
-       /* If we reach this point, we've got real problems. */
-       fprintf( stderr, "Attempt to convert invalid string \"%s\" into an ITEMTYPE! Aborting.\n", str );
-       exit(EXIT_FAILURE);
-       return -1;
-}
-       
-
-RESULTTYPE stringToResult( char * str ) {
-    if (strcasecmp( str, "Attacker" ) == 0) return attacker;
-    if (strcasecmp( str, "Defender" ) == 0) return defender;
-    if (strcasecmp( str, "Tie" ) == 0) return tie;
-    /* If we reach this point, we've got real problems. */
-       fprintf( stderr, "Attempt to convert invalid string \"%s\" into an ITEMTYPE! Aborting.\n", str );
-       exit(EXIT_FAILURE);
-       return -1;
-}
-
-int main( int argc, char * argv[] ) {
-       srand( time( NULL ) );
-       
-       char command[MAXCOMMANDLEN];
-       char foeName[MAXFOENAMELEN];
-       char attItem[MAXITEMLEN], defItem[MAXITEMLEN], bluffItem[MAXITEMLEN];
-       char didYouInstigate[MAXBOOLLEN];
-    char winner[MAXRESULTLEN];
-       int pointChange;
-       
-       ATTACKTYPE attack;
-       ITEMTYPE defence;
-       
-    /* generate a random id for this bot. Hopefully it's unique
-       I can't use the UUID, because python doesn't pass it to me! */
-    me = rand();
-    
-    
-       scanf( "%s", command );
-       
-       while (strcasecmp("BYE",command) != 0) {
-               
-               if (strcasecmp("ATTACK", command) == 0) {
-                       scanf( "%s", foeName );
-                       attack = Attack( foeName );
-                       printf("ATTACKING %s %s\n", ITEMNAMES[attack.realAttack], ITEMNAMES[attack.promisedAttack]);
-               
-               } else if (strcasecmp("DEFEND", command) == 0) {
-                       scanf( "%s %s", foeName, bluffItem );
-                       defence = Defend(foeName, stringToItem(bluffItem));
-                       printf("DEFENDING %s\n", ITEMNAMES[defence]);
-               
-               } else if (strcasecmp("RESULTS", command) == 0) {
-            /* (foeName, isInstigatedByYou, winner, attItem, defItem, bluffItem, pointDelta) */
-                       scanf( "%s %s %s %s %s %s %d", foeName, didYouInstigate, winner, attItem, defItem, bluffItem, &pointChange );
-                       Results(foeName, (strcasecmp("True",didYouInstigate)==0), stringToResult(winner),
-                                       stringToItem(attItem), stringToItem(defItem), stringToItem(bluffItem), pointChange);
-                       printf("OK\n");
-               }
-       
-        fflush(stdout);
-        fflush(stderr);
-        
-               // read the next command!
-               scanf( "%s", command );
-       }
-       
-       Cleanup();
-       
-       return 0;
-}
\ No newline at end of file
+/*\r
+ *  c_link.c\r
+ *  c-link-lib\r
+ *\r
+ *  Created by Daniel Axtens on 19/04/10.\r
+ *  Licensed under an MIT-style license: see the LICENSE file for details.\r
+ *\r
+ */\r
+\r
+#include "c_link.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <time.h>\r
+\r
+/* You don't need to read this file.\r
+   All you have to do is implement the bot functions defined in <c_link.h>\r
+   This file sets up the I/O for you, as well as some utility functions and tables. \r
+ */\r
+\r
+char ITEMNAMES[3][MAXITEMLEN] = {"Rock", "Paper", "Scissors"};\r
+\r
+/* rock-rock     rock-paper     rock-scissors \r
+   paper-rock    paper-paper    paper-scissors\r
+   scissors-rock scissors-paper scissors-scissors */  \r
+   \r
+RESULTTYPE RESULTOF[3][3] = { { tie, defender, attacker },\r
+                              { attacker, tie, defender },\r
+                              { defender, attacker, tie } };\r
+\r
+ITEMTYPE RandomAttack() {\r
+       return (ITEMTYPE)rand()%3;\r
+}\r
+\r
+ITEMTYPE stringToItem( char * str ) {\r
+       if (strcasecmp( str, "Rock" ) == 0) return rock;\r
+       if (strcasecmp( str, "Paper" ) == 0) return paper;\r
+       if (strcasecmp( str, "Scissors" ) == 0) return scissors;\r
+       /* If we reach this point, we've got real problems. */\r
+       fprintf( stderr, "Attempt to convert invalid string \"%s\" into an ITEMTYPE! Aborting.\n", str );\r
+       exit(EXIT_FAILURE);\r
+       return -1;\r
+}\r
+       \r
+\r
+RESULTTYPE stringToResult( char * str ) {\r
+       if (strcasecmp( str, "Attacker" ) == 0) return attacker;\r
+       if (strcasecmp( str, "Defender" ) == 0) return defender;\r
+       if (strcasecmp( str, "Tie" ) == 0) return tie;\r
+       /* If we reach this point, we've got real problems. */\r
+       fprintf( stderr, "Attempt to convert invalid string \"%s\" into an ITEMTYPE! Aborting.\n", str );\r
+       exit(EXIT_FAILURE);\r
+       return -1;\r
+}\r
+\r
+int main( int argc, char * argv[] ) {\r
+       srand( time( NULL ) );\r
+       \r
+       char command[MAXCOMMANDLEN];\r
+       char foeName[MAXAGENTNAMELEN];\r
+       char attItem[MAXITEMLEN], defItem[MAXITEMLEN], bluffItem[MAXITEMLEN];\r
+       char didYouInstigate[MAXBOOLLEN];\r
+       char winner[MAXRESULTLEN];\r
+       char uuid[MAXAGENTNAMELEN];  \r
+       int pointChange;\r
+       void *thisInstance = NULL;\r
+\r
+       ATTACKTYPE attack;\r
+       ITEMTYPE defence;\r
+       \r
+       scanf( "%s", command );\r
+       \r
+       while (strcasecmp("BYE",command) != 0) {\r
+               \r
+               if (strcasecmp("HI", command) == 0) {\r
+                       scanf( "%s", uuid );\r
+                       thisInstance = Initialise( uuid );\r
+                       \r
+               } else if (strcasecmp("ATTACK", command) == 0) {\r
+                       scanf( "%s", foeName );\r
+                       attack = Attack( thisInstance, foeName );\r
+                       printf("ATTACKING %s %s\n", ITEMNAMES[attack.realAttack], ITEMNAMES[attack.promisedAttack]);\r
+               \r
+               } else if (strcasecmp("DEFEND", command) == 0) {\r
+                       scanf( "%s %s", foeName, bluffItem );\r
+                       defence = Defend(thisInstance, foeName, stringToItem(bluffItem));\r
+                       printf("DEFENDING %s\n", ITEMNAMES[defence]);\r
+               \r
+               } else if (strcasecmp("RESULTS", command) == 0) {\r
+                       /* (foeName, isInstigatedByYou, winner, attItem, defItem, bluffItem, pointDelta) */\r
+                       scanf( "%s %s %s %s %s %s %d", foeName, didYouInstigate, winner, attItem, defItem, bluffItem, &pointChange );\r
+                       Results(thisInstance, foeName, (strcasecmp("True",didYouInstigate)==0), stringToResult(winner),\r
+                                       stringToItem(attItem), stringToItem(defItem), stringToItem(bluffItem), pointChange);\r
+                       printf("OK\n");\r
+               }\r
+       \r
+               fflush(stdout);\r
+               fflush(stderr);\r
+        \r
+               // read the next command!\r
+               scanf( "%s", command );\r
+       }\r
+       \r
+       if( thisInstance )\r
+               Cleanup(thisInstance);\r
+       \r
+       return 0;\r
+}\r
old mode 100644 (file)
new mode 100755 (executable)
index c3bd87c..0e34644
-/*
- *  c_link.h
- *  c-link-lib
- *
- *  Created by Daniel Axtens on 19/04/10.
- *  Licensed under an MIT-style license: see the LICENSE file for details.
- *
- */
-
-#include <stdio.h>
-
-#define MAXCOMMANDLEN  15
-#define MAXFOENAMELEN  50
-#define MAXITEMLEN             10
-#define MAXRESULTLEN    10
-#define MAXBOOLLEN             6
-
-/********** Type definitions **********/
-
-/* The type of item used in an attack or defence */
-typedef enum {rock, paper, scissors} ITEMTYPE;
-
-/* A result of a battle, in terms of who won */
-typedef enum {attacker, defender, tie} RESULTTYPE;
-
-
-/* An attack, consisting of the real attack and the attack promised */
-typedef struct {
-       ITEMTYPE realAttack;
-       ITEMTYPE promisedAttack;
-} ATTACKTYPE;
-
-
-/********** Utility Function definitions **********/
-/* These are implemented in c-link.c, and automagically linked in */
-
-/* prints a debug message. Same arguments as printf().
-   (you can't use printf because it is used to talk between
-    the agent and supervisor) 
- */
-
-#define debugmsg(x...) fprintf(stderr, x)
-
-/* A (hopefully) unique identifier for this particular instance of your agent,
-   to help with debugging */
-int me;
-
-
-/* Returns a random item */
-
-ITEMTYPE RandomAttack();
-
-/* A useful translation table
-   eg debugmsg( "I use %s.\n", ITEMNAMES[rock] ); */
-
-extern char ITEMNAMES[3][MAXITEMLEN];
-
-/* Another useful table - who's the victor given an 
-   attacker with first item vs defender with the second item? */
-extern RESULTTYPE RESULTOF[3][3];
-
-/********** Bot Function definitions **********/
-/* You need to provide implementations for these to create a bot */
-
-/* Defend( foeName : string - the name of your foe;
-           foePromisedAttack : ITEMTYPE - the item your foe promised to use
-         ) : ITEMTYPE - the item you wish to use to defend;
- Called when your agent needs to defend itself.
- */
-ITEMTYPE Defend( char * foeName, ITEMTYPE foePromisedAttack );
-
-
-/* Attack( foeName : string - the name of your foe
-                ) : ATTACKTYPE - the real and promised attack you wish to use
-
- Called when your agent needs to attack another agent.
- */
-ATTACKTYPE Attack( char * foeName );
-
-
-/* Results( foeName : string - the name of your foe;
-            isInstigatedByYou : 0=you defended/1=you attacked;
-            winner : RESULTTYPE - who won
-                       attItem : ITEMTYPE - the item used to attack;
-            defItem : ITEMTYPE - the item used to defend;
-            bluffItem : ITEMTYPE - the item that was promised
-            pointDelta : integer - how your points were affected.
-          );
-
- Called after your agent battles another agent, to tell you how the battle goes.
- */
-void Results( char * foeName, int isInstigatedByYou, RESULTTYPE winner,
-              ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,
-              int pointDelta );
-
-/* Cleanup();
-
-   Called when your agent is no longer needed, either due to the round ending
-   or due to your agent being eliminated.
-
- */
-void Cleanup();
\ No newline at end of file
+/*\r
+ *  c_link.h\r
+ *  c-link-lib\r
+ *\r
+ *  Created by Daniel Axtens on 19/04/10.\r
+ *  Licensed under an MIT-style license: see the LICENSE file for details.\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+\r
+#define MAXCOMMANDLEN  15\r
+#define MAXAGENTNAMELEN        42 /* 40 digits, 'L', and NULL */\r
+#define MAXITEMLEN             10\r
+#define MAXRESULTLEN    10\r
+#define MAXBOOLLEN             6\r
+\r
+/********** Type definitions **********/\r
+\r
+/* The type of item used in an attack or defence */\r
+typedef enum {rock, paper, scissors} ITEMTYPE;\r
+\r
+/* A result of a battle, in terms of who won */\r
+typedef enum {attacker, defender, tie} RESULTTYPE;\r
+\r
+\r
+/* An attack, consisting of the real attack and the attack promised */\r
+typedef struct {\r
+       ITEMTYPE realAttack;\r
+       ITEMTYPE promisedAttack;\r
+} ATTACKTYPE;\r
+\r
+\r
+/********** Utility Function definitions **********/\r
+/* These are implemented in c-link.c, and automagically linked in */\r
+\r
+/* prints a debug message. Same arguments as printf().\r
+   (you can't use printf because it is used to talk between\r
+    the agent and supervisor)\r
+       \r
+       Hint: store the name passed to you in Initalise and use it to uniquely\r
+       identify the agent sending the message.\r
+ */\r
+\r
+#define debugmsg(x...) fprintf(stderr, x)\r
+\r
+\r
+/* Returns a random item */\r
+\r
+ITEMTYPE RandomAttack();\r
+\r
+/* A useful translation table\r
+   eg debugmsg( "I use %s.\n", ITEMNAMES[rock] ); */\r
+\r
+extern char ITEMNAMES[3][MAXITEMLEN];\r
+\r
+/* Another useful table - who's the victor given an \r
+   attacker with first item vs defender with the second item? */\r
+extern RESULTTYPE RESULTOF[3][3];\r
+\r
+/********** Bot Function definitions **********/\r
+/* You need to provide implementations for these to create a bot */\r
+\r
+/* Initialise( yourName : string - name of this instance (you)\r
+             ) : void * - A data pointer to represent this instance\r
\r
+ Called to create a new instance of this agent\r
+\r
+ */\r
+void *Initialise( char * yourName );\r
+\r
+/* Defend( this : pointer - value returned from Initialise();\r
+           foeName : string - the name of your foe;\r
+           foePromisedAttack : ITEMTYPE - the item your foe promised to use\r
+         ) : ITEMTYPE - the item you wish to use to defend;\r
\r
+ Called when your agent needs to defend itself.\r
\r
+ */\r
+ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack );\r
+\r
+\r
+/* Attack( this: pointer - value returned from Initialise();\r
+           foeName : string - the name of your foe\r
+                ) : ATTACKTYPE - the real and promised attack you wish to use\r
+\r
+ Called when your agent needs to attack another agent.\r
\r
+ */\r
+ATTACKTYPE Attack( void * this, char * foeName );\r
+\r
+\r
+/* Results( this : pointer - value returned from Initialise();\r
+            foeName : string - the name of your foe;\r
+            isInstigatedByYou : 0=you defended/1=you attacked;\r
+            winner : RESULTTYPE - who won\r
+                       attItem : ITEMTYPE - the item used to attack;\r
+            defItem : ITEMTYPE - the item used to defend;\r
+            bluffItem : ITEMTYPE - the item that was promised\r
+            pointDelta : integer - how your points were affected.\r
+          );\r
+\r
+ Called after your agent battles another agent, to tell you how the battle goes.\r
\r
+ */\r
+void Results( void * this, char * foeName, int isInstigatedByYou, RESULTTYPE winner,\r
+              ITEMTYPE attItem, ITEMTYPE defItem, ITEMTYPE bluffItem,\r
+              int pointDelta );\r
+\r
+/* Cleanup( this: pointer - value returned from Initialise()\r
+          );\r
+\r
+   Called when your agent is no longer needed, either due to the round ending\r
+   or due to your agent being eliminated.\r
+\r
+ */\r
+void Cleanup( void * this );\r
index 6112482..0680f33 100644 (file)
@@ -16,11 +16,13 @@ class externAgent (BaseAgent):
         BaseAgent.__init__(self)
         try:
             self.process = subprocess.Popen(externName, stdin=subprocess.PIPE, 
-                                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                                            stdout=subprocess.PIPE,
                                             universal_newlines=True)
         except Exception, e:
             print ("Error spawning \"%s\": " % externName), e
-            
+           
+        self.process.stdin.write ( ' '.join( ["HI", repr(self.GetID()), "\r\n"] ) )
+
     def stringToItem( self, str ):
         if str == "Rock":
             return Rock
@@ -73,7 +75,7 @@ class externAgent (BaseAgent):
             return attack, bluff
         except:
             #agent is insane
-            print "Agent is insane:", self
+            print "Agent is insane:", self, self.GetID()
             pass
         
     def Defend (self, foe, bluff ):
@@ -85,7 +87,7 @@ class externAgent (BaseAgent):
             return defence
         except:
             #agent is insane
-            print "Agent is insane:", self
+            print "Agent is insane:", self, self.GetID()
             pass
 
     def Results (self, foe, isInstigatedByYou, winner, attItem, defItem, bluffItem, pointDelta):
@@ -110,13 +112,30 @@ class externAgent (BaseAgent):
         self.process.stdin.write ( string )
         self.process.stdout.readline() # read and discard (should be "OK")
         
+        # we kill off the process here because otherwise the class doesn't get
+        # destroyed until the end of the iteration. This causes us to hold more
+        # than MAX_TOTAL_AGENTS open for a period of time, which is a bad thing.
+        if self.IsDead():
+            try:
+                self.process.communicate( "BYE\r\n" )
+            except Exception, e:
+                print "Error in BYE:", self, ":", e
+            
+            try:
+                self.process.kill()
+            except:
+                None
+
+
     def __del__(self):
-        try:
-            self.process.communicate( "BYE\r\n" )
-        except Exception, e:
-            print "Error in BYE:", self, ":", e
+        #unless we're being deleted unexpectedly, this is a no-op.
+        if self.process.poll() == None:
+            try:
+                self.process.communicate( "BYE\r\n" )
+            except Exception, e:
+                print "Error in BYE:", self, ":", e
             
-        try:
-            self.process.kill()
-        except:
-            None
\ No newline at end of file
+            try:
+                self.process.kill()
+            except:
+                None

UCC git Repository :: git.ucc.asn.au