From: Daniel Axtens Date: Mon, 3 May 2010 02:23:26 +0000 (+0800) Subject: cleanup X-Git-Tag: v01~27 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=e9a8105a8f22404f4ac550d79954eaa6b7f5d8ff;p=progcomp10.git cleanup --- diff --git a/issues b/issues deleted file mode 100644 index 393bd1a..0000000 --- a/issues +++ /dev/null @@ -1,6 +0,0 @@ - - number of agents can spiral out of control very quickly, e.g. if Frenchie and Angel start duking it out. - - points table doesn't agree with technicalities doc - - agents die after MAX_AGE fights, not MAX_AGE rounds - - code seems to trust y ou not to mnokey around with your stats...? - - no way to tell an external agent that their services are no longer required. - * amend to provide a BYE command diff --git a/issues.txt b/issues.txt new file mode 100644 index 0000000..d6a2c4e --- /dev/null +++ b/issues.txt @@ -0,0 +1,7 @@ + - number of agents can spiral out of control very quickly, e.g. if Frenchie and Angel start duking it out. + * Need to make supervisor smart enough to kill montonically increasing sequences. + - points table doesn't agree with technicalities doc + - agents die after MAX_AGE fights, not MAX_AGE rounds + - code seems to trust you not to monkey around with your stats...? + - coding styles are inconsistent throughout + - layout still needs some work diff --git a/link/C/c-link-lib/.gitignore b/link/C/c-link-lib/.gitignore deleted file mode 100644 index fbde527..0000000 --- a/link/C/c-link-lib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -agents/ -!agents/*.c diff --git a/link/C/c-link-lib/Makefile b/link/C/c-link-lib/Makefile deleted file mode 100644 index 10e306b..0000000 --- a/link/C/c-link-lib/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -CC=gcc -AR=ar - -CFLAGS=-Wall -I. -LDFLAGS=-lc_link -L. - -LINKSRCS=c_link.c -LINKOBJS=$(LINKSRCS:.c=.o) -LINKLIB=libc_link.a - -AGENTSRCS=$(wildcard agents/*.c) -AGENTS=$(AGENTSRCS:.c=) - -all: $(LINKSRCS) $(LINKLIB) $(AGENTS) - -$(LINKLIB): $(LINKOBJS) - $(AR) rcs $(LINKLIB) $(LINKOBJS) - -$(AGENTS): $(AGENTSRCS) - @echo Building $< - $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ - -.c.o: c_link.h - $(CC) -c $(CFLAGS) $< -o $@ - -.PHONY : clean -clean: - rm $(LINKOBJS) $(LINKLIB) $(AGENTS) diff --git a/link/C/c-link-lib/agents/c-angel.c b/link/C/c-link-lib/agents/c-angel.c deleted file mode 100644 index c6c8687..0000000 --- a/link/C/c-link-lib/agents/c-angel.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 - -/* 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, ITEMTYPE yourItem, - ITEMTYPE theirItem, ITEMTYPE promisedItem) { - - return; /* Ignore whatever just happened. */ -} - -/* same for Cleanup() */ - -void Cleanup() { - return; -} \ No newline at end of file diff --git a/link/C/c-link-lib/agents/c-frechie.c b/link/C/c-link-lib/agents/c-frechie.c deleted file mode 100644 index ed2ba09..0000000 --- a/link/C/c-link-lib/agents/c-frechie.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 -#include - -/* Implement the frenchie bot, 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 */ -#define NUMBEROFAGENTSGUESS 100 - -/* The name of the n-th foe we've seen, as well as a 0/1 have we lost to them */ -char foesNames[][MAXFOENAMELEN] = NULL; -int haveLostToFoe[] = NULL; - -/* The length of the array, and how far we are along it */ -size_t foesLen = 0; -unsigned int foesCount = 0; - - -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: - result.promisedAttack = paper; - break; - case paper: - result.promisedAttack = scissors; - break; - default: /* attack = scissors */ - result.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; - } -} - -/* This is so much less fun in C */ -void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, - ITEMTYPE theirItem, ITEMTYPE promisedItem) { - - int foe; - - /* check to see if we've initialised our arrays */ - if (foesNames == NULL) { - foesNames = calloc( NUMBEROFAGENTSGUESS, sizeof( foesNames[0] ) ); - haveLostToFoe = calloc( NUMBEROFAGENTSGUESS, sizeof( haveLostToFoe[0] ) ); - foesLen = NUMBEROFAGENTSGUESS; - } - - /* figure out if we lost, which is the only thing we care about - if we didn't, move on. */ - if (RESULTOF[yourItem][theirItem] != lose) return; - - /* try and find existing foe */ - - return; -} - -/* same for Cleanup() */ - -void Cleanup() { - free(foesNames); - free(haveLostToFoe); -} \ No newline at end of file diff --git a/link/C/c-link-lib/agents/c-lucifer.c b/link/C/c-link-lib/agents/c-lucifer.c deleted file mode 100644 index 1dabc34..0000000 --- a/link/C/c-link-lib/agents/c-lucifer.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 - -/* 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: - result.promisedAttack = scissors; - break; - case paper: - result.promisedAttack = rock; - break; - default: /* attack = scissors */ - result.promisedAttack = paper; - break; - } - attack.promisedAttack = result.realAttack; /* Tells the truth for its bluff */ - - 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; - } -} - -/* You need to define a results function, even if it isn't used - (otherwise the linker will complain) */ -void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, - ITEMTYPE theirItem, ITEMTYPE promisedItem) { - - return; /* Ignore whatever just happened. */ -} - -/* same for Cleanup() */ - -void Cleanup() { - return; -} \ No newline at end of file diff --git a/link/C/c-link-lib/agents/c-streetfighter.c b/link/C/c-link-lib/agents/c-streetfighter.c deleted file mode 100644 index c63939d..0000000 --- a/link/C/c-link-lib/agents/c-streetfighter.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 - -/* 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: - result.promisedAttack = paper; - break; - case paper: - result.promisedAttack = scissors; - break; - default: /* attack = scissors */ - result.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; - } -} - -/* You need to define a results function, even if it isn't used - (otherwise the linker will complain) */ -void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, - ITEMTYPE theirItem, ITEMTYPE promisedItem) { - - return; /* Ignore whatever just happened. */ -} - -/* same for Cleanup() */ - -void Cleanup() { - return; -} diff --git a/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj b/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj deleted file mode 100644 index 80d9803..0000000 --- a/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj +++ /dev/null @@ -1,150 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 45; - objects = { - -/* Begin PBXFileReference section */ - 2291A1BB117EDB9600854CBE /* c_link.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = c_link.c; sourceTree = ""; }; - 2291A1BD117EE3FD00854CBE /* c-angel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-angel.c"; sourceTree = ""; }; - 2291A1BE117EE3FD00854CBE /* c-lucifer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-lucifer.c"; sourceTree = ""; }; - 2291A1BF117EE3FD00854CBE /* c-streetfighter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-streetfighter.c"; sourceTree = ""; }; - 2291A1EC117FF85D00854CBE /* c-frechie.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-frechie.c"; sourceTree = ""; }; - 22F652F5117C679300A3793D /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - 22F652F6117C6C9500A3793D /* c_link.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = c_link.h; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* c-link-lib */ = { - isa = PBXGroup; - children = ( - 2291A1BC117EE3FD00854CBE /* agents */, - 22F652F6117C6C9500A3793D /* c_link.h */, - 2291A1BB117EDB9600854CBE /* c_link.c */, - 22F652F5117C679300A3793D /* Makefile */, - ); - name = "c-link-lib"; - sourceTree = ""; - }; - 2291A1BC117EE3FD00854CBE /* agents */ = { - isa = PBXGroup; - children = ( - 2291A1BD117EE3FD00854CBE /* c-angel.c */, - 2291A1BE117EE3FD00854CBE /* c-lucifer.c */, - 2291A1BF117EE3FD00854CBE /* c-streetfighter.c */, - 2291A1EC117FF85D00854CBE /* c-frechie.c */, - ); - path = agents; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXLegacyTarget section */ - D28A88AD04BDD90700651E21 /* c-link-lib */ = { - isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION)"; - buildConfigurationList = 1DEB918F08733D9F0010E9CD /* Build configuration list for PBXLegacyTarget "c-link-lib" */; - buildPhases = ( - ); - buildToolPath = /usr/bin/make; - buildWorkingDirectory = ""; - dependencies = ( - ); - name = "c-link-lib"; - passBuildSettingsInEnvironment = 1; - productName = "c-link-lib"; - }; -/* End PBXLegacyTarget section */ - -/* Begin PBXProject section */ - 08FB7793FE84155DC02AAC07 /* Project object */ = { - isa = PBXProject; - buildConfigurationList = 1DEB919308733D9F0010E9CD /* Build configuration list for PBXProject "c-link-lib" */; - compatibilityVersion = "Xcode 3.1"; - hasScannedForEncodings = 1; - mainGroup = 08FB7794FE84155DC02AAC07 /* c-link-lib */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - D28A88AD04BDD90700651E21 /* c-link-lib */, - ); - }; -/* End PBXProject section */ - -/* Begin XCBuildConfiguration section */ - 1DEB919008733D9F0010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = NO; - DEBUGGING_SYMBOLS = YES; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "c-link-lib"; - }; - name = Debug; - }; - 1DEB919108733D9F0010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "c-link-lib"; - }; - name = Release; - }; - 1DEB919408733D9F0010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; - SDKROOT = macosx10.6; - }; - name = Debug; - }; - 1DEB919508733D9F0010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - SDKROOT = macosx10.6; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB918F08733D9F0010E9CD /* Build configuration list for PBXLegacyTarget "c-link-lib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB919008733D9F0010E9CD /* Debug */, - 1DEB919108733D9F0010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1DEB919308733D9F0010E9CD /* Build configuration list for PBXProject "c-link-lib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB919408733D9F0010E9CD /* Debug */, - 1DEB919508733D9F0010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} diff --git a/link/C/c-link-lib/c_link.c b/link/C/c-link-lib/c_link.c deleted file mode 100644 index 680450e..0000000 --- a/link/C/c-link-lib/c_link.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 -#include -#include -#include - -/* You don't need to read this file. - All you have to do is implement the bot functions defined in - 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, lose, win }, - { win, tie, lose }, - { lose, win, 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; -} - - -int main( int argc, char * argv[] ) { - srand( time( NULL ) ); - - char command[MAXCOMMANDLEN]; - char foeName[MAXFOENAMELEN]; - char yourItem[MAXITEMLEN], theirItem[MAXITEMLEN], promisedItem[MAXITEMLEN]; - char didYouInstigate[MAXBOOLLEN], childSpawned[MAXBOOLLEN]; - int pointChange; - - ATTACKTYPE attack; - ITEMTYPE defence; - - 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, promisedItem ); - defence = Defend(foeName, stringToItem(promisedItem)); - printf("DEFENDING %s\n", ITEMNAMES[defence]); - - } else if (strcasecmp("RESULTS", command) == 0) { - scanf( "%s %s %s %s %s %d %s", foeName, didYouInstigate, yourItem, theirItem, promisedItem, &pointChange, childSpawned ); - Results(foeName, (strcasecmp("False",didYouInstigate)==0), - stringToItem(yourItem), stringToItem(theirItem), stringToItem(promisedItem)); - printf("OK\n"); - } - - // read the next command! - scanf( "%s", command ); - } - - Cleanup(); - - return 0; -} \ No newline at end of file diff --git a/link/C/c-link-lib/c_link.h b/link/C/c-link-lib/c_link.h deleted file mode 100644 index 84e9bce..0000000 --- a/link/C/c-link-lib/c_link.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 - -#define MAXCOMMANDLEN 15 -#define MAXFOENAMELEN 50 -#define MAXITEMLEN 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 */ -typedef enum {win, lose, 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...) sprintf(stderr, x) - -/* Returns a random item */ - -ITEMTYPE RandomAttack(); - -/* A useful translation table - eg printf( "I use %s.\n", ITEMNAMES[rock] ); */ - -extern char ITEMNAMES[3][MAXITEMLEN]; - -/* Another useful table - what's the result of the - first item vs 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; - yourItem : ITEMTYPE - the item you used; - theirItem : ITEMTYPE - the item they used; - promisedItem : ITEMTYPE - the item that was promised - ); - - Called after your agent battles another agent, to tell you how the battle goes. - - */ -void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, - ITEMTYPE theirItem, ITEMTYPE promisedItem); - -/* 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 diff --git a/link/Mathematica/pyml.tar.gz b/link/Mathematica/pyml.tar.gz deleted file mode 100644 index 498748f..0000000 Binary files a/link/Mathematica/pyml.tar.gz and /dev/null differ diff --git a/link/Mathematica/pythonika-1.0.tar.gz b/link/Mathematica/pythonika-1.0.tar.gz deleted file mode 100644 index 6611f5d..0000000 Binary files a/link/Mathematica/pythonika-1.0.tar.gz and /dev/null differ diff --git a/rps/trunk/LICENSE b/rps/trunk/LICENSE deleted file mode 100644 index e25c106..0000000 --- a/rps/trunk/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2008 Luke Williams - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/rps/trunk/README b/rps/trunk/README deleted file mode 100644 index 8587cf5..0000000 --- a/rps/trunk/README +++ /dev/null @@ -1,66 +0,0 @@ -Hi there, - -Thanks for taking interest in the UCC Programming Competition 2008. If you -don't already know what it's all about, check out the information provided in -the docs directory, which contains a full and authoritative* description for -the running of the competition. - -This file is by no means complete, and not ready for circulation. - -The first thing you'll probably want to do is see it work. Try running: - -./simulate -v - -to see the sample agents duke it out for up to 150 rounds (the current sample -agents suck - rounds either go for seconds or for ages). After that, take a -look at sampleAgents.py to see how agents are implemented on top of the -BaseAgent and LearningAgent classes. When you're ready to try out your own, -edit the first few lines of simulate.py to include your agent. - -...and if all you're interested in is participating, that's it! You can stop -reading, and start work on the agent that will outsmart them all! - -Contributor instructions: - -BaseAgent, LearningAgent and Supervisor are all implemented in uccProgComp.py. -The 'select' algorithm, responsible for choosing agents for battle and -determining when a round is finished, is the hottest part of the code and the -most open to discussion and change. - -Unfortunately, it is not an easy bit of code to understand. Once upon a time, -in builds long past, it used friendly O(n) operations and conveniently wasted -memory on simple tasks. After hours of profiling, it is a little more complex, -but with a bit of background to how the supervisor operates you shouldn't have -much trouble working out the rest: - -1.) A copy of the current population list is made at the beginning of the round -representing the agents who can still fight. This reduces finding valid agents -from O(n) to O(1). I call it the 'remaining' list. -2.) Agents must remember their index in the population list. This is because it -would be O(n) to determine their index in the population list (to remove them -when they die) from their index in the 'remaining' list. Agents have this value -stored at the beginning of the round - O(n) at the beginning of the round is -far preferable to O(n) for every death. -3.) The actual removal of agents from the population list must happen all at -once in reverse numeric index order at the end of the round so that the stored -index that agents have does not become stale. - -There are problems. It's not perfect, but it's relatively fast and powerful and -quite easy to adjust or reimplement once you get your head around it. I'm very -much open to suggestion for improvement (especially in the form of patches) and -welcome all help, constructive criticism, derisive criticism and death threats. - -Things to be done: - -1.) Pretty graphs! Iterate () returns a collection of statistics about each of -the classes, which can be seen used in simulate.py. There are plenty of -plotting packages out there that can turn this information into impressive -charts. -2.) More built-in functionality for BaseAgent and LearningAgent. They could -both do with a few more utility functions for competitors to use. -3.) A more succint set of rules and documentation. - -Thanks for reading! -Luke - -* Or rather, it wil by the time this package is ready for distribution. diff --git a/rps/trunk/SampleAgents.py b/rps/trunk/SampleAgents.py deleted file mode 100644 index 6da30ba..0000000 --- a/rps/trunk/SampleAgents.py +++ /dev/null @@ -1,89 +0,0 @@ -'''SampleAgents.py - A collection of sample agents for playing Rock Paper Scissors. -Written by Luke Williams for the UCC Programming Competition in 2008. -Requires Python 2.5. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - -from uccProgComp import BaseAgent, LearningAgent, RandomAttack -from rpsconst import * - -# Angel is a very simple bot that always tells the truth and expects others to do the same. -class Dummy (BaseAgent): - def Attack (self, foe): - return Paper, Paper - def Defend (self, foe, bluff): - return bluff - -class Angel (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () # Chooses randomly from Rock, Paper, Scissors - return attack, attack # Tells the truth for its bluff. - def Defend (self, foe, bluff): - return bluff # Trusts them to be going for a tie. - -# Lucifer here is the opposite. He always lies expecting people to be good and always goes for the kill. -class Lucifer (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () - if attack == Rock: bluff = Scissors # Here we choose the thing - elif attack == Paper: bluff = Rock # that will hurt them - else: bluff = Paper # if they go for a tie. - return attack, bluff - def Defend (self, foe, bluff): - if bluff == Rock: attack = Paper # Here we trust that they - elif bluff == Paper: attack = Scissors # are telling the truth. - else: attack = Rock # And we try to kill them. - return attack -# def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): -# BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) -# print "I just scored " + str(pointDelta) + " points!" - - -# Streetfighter assumes everyone has it in for him. -class Streetfighter (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () - if attack == Rock: bluff = Paper # Here we choose the thing - elif attack == Paper: bluff = Scissors # that will hurt them - else: bluff = Rock # if they try to kill us. - return attack, bluff - def Defend (self, foe, bluff): - if bluff == Rock: attack = Scissors # Here we assume that they - elif bluff == Paper: attack = Rock # are lying, trying to kill us. - else: attack = Paper # And we try to kill them. - return attack - -# This is our first bot with any sort of learning capability, based on the LearningAgent base. -# Experienced programmers might opt to write their own learning code based on BaseAgent, but it's up to you. -# Frenchie is a simple bot that is by default nice but will permanently turn against any agent that betrays it. -class Frenchie (LearningAgent): - def Attack (self, foe): - attack = RandomAttack () - if Loss in LearningAgent.GetWinHistory (self, foe): - if attack == Rock: bluff = Scissors - elif attack == Paper: bluff = Rock - else: bluff = Paper - else: - bluff = attack - return attack, bluff - def Defend (self, foe, bluff): - if Loss in LearningAgent.GetWinHistory (self, foe): - if bluff == Rock: attack = Scissors # They've fucked us in the past, - elif bluff == Paper: attack = Rock # so we assume they're lying and - else: attack = Paper # hoping we go for a kill. - else: - attack = bluff - return attack - - -# If you want to implement your own Results () callback, you have to call the parent class's first: -class Blank (BaseAgent): - def Attack (self, foe): - return Paper, Paper - def Defend (self, foe, bluff): - return bluff - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) - # Now you can do your own thing - diff --git a/rps/trunk/SampleAgents.py.old b/rps/trunk/SampleAgents.py.old deleted file mode 100644 index d307214..0000000 --- a/rps/trunk/SampleAgents.py.old +++ /dev/null @@ -1,89 +0,0 @@ -'''SampleAgents.py - A collection of sample agents for playing Rock Paper Scissors. -Written by Luke Williams for the UCC Programming Competition in 2008. -Requires Python 2.5. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - -from uccProgComp import BaseAgent, LearningAgent, RandomAttack -from rpsconst import * - -# Angel is a very simple bot that always tells the truth and expects others to do the same. -class Dummy (BaseAgent): - def Attack (self, foe): - return Paper, Paper - def Defend (self, foe, bluff): - return bluff - -class Angel (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () # Chooses randomly from Rock, Paper, Scissors - return attack, attack # Tells the truth for its bluff. - def Defend (self, foe, bluff): - return bluff # Trusts them to be going for a tie. - -# Lucifer here is the opposite. He always lies expecting people to be good and always goes for the kill. -class Lucifer (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () - if attack == Rock: bluff = Scissors # Here we choose the thing - elif attack == Paper: bluff = Rock # that will hurt them - else: bluff = Paper # if they go for a tie. - return attack, bluff - def Defend (self, foe, bluff): - if bluff == Rock: attack = Paper # Here we trust that they - elif bluff == Paper: attack = Scissors # are telling the truth. - else: attack = Rock # And we try to kill them. - return attack -# def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): -# BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) -# print "I just scored " + str(pointDelta) + " points!" - - -# Streetfighter assumes everyone has it in for him. -class Streetfighter (BaseAgent): - def Attack (self, foe): - attack = RandomAttack () - if attack == Rock: bluff = Paper # Here we choose the thing - elif attack == Paper: bluff = Scissors # that will hurt them - else: bluff = Rock # if they go for a tie. - return attack, bluff - def Defend (self, foe, bluff): - if bluff == Rock: attack = Paper # Here we trust that they - elif bluff == Paper: attack = Scissors # are telling the truth. - else: attack = Rock # And we try to kill them. - return attack - -# This is our first bot with any sort of learning capability, based on the LearningAgent base. -# Experienced programmers might opt to write their own learning code based on BaseAgent, but it's up to you. -# Frenchie is a simple bot that is by default nice but will permanently turn against any agent that betrays it. -class Frenchie (LearningAgent): - def Attack (self, foe): - attack = RandomAttack () - if Loss in LearningAgent.GetWinHistory (self, foe): - if attack == Rock: bluff = Scissors - elif attack == Paper: bluff = Rock - else: bluff = Paper - else: - bluff = attack - return attack, bluff - def Defend (self, foe, bluff): - if Loss in LearningAgent.GetWinHistory (self, foe): - if bluff == Rock: attack = Scissors # They've fucked us in the past, - elif bluff == Paper: attack = Rock # so we assume they're lying and - else: attack = Paper # hoping we go for a kill. - else: - attack = bluff - return attack - - -# If you want to implement your own Results () callback, you have to call the parent class's first: -class Blank (BaseAgent): - def Attack (self, foe): - return Paper, Paper - def Defend (self, foe, bluff): - return bluff - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) - # Now you can do your own thing - diff --git a/rps/trunk/SampleAgents.pyc b/rps/trunk/SampleAgents.pyc deleted file mode 100644 index 7b91932..0000000 Binary files a/rps/trunk/SampleAgents.pyc and /dev/null differ diff --git a/rps/trunk/djaAgents.py b/rps/trunk/djaAgents.py deleted file mode 100644 index 6912c7f..0000000 --- a/rps/trunk/djaAgents.py +++ /dev/null @@ -1,77 +0,0 @@ -from uccProgComp import BaseAgent, LearningAgent, RandomAttack -from rpsconst import * - -# BOFH is something of a cross between Frechie and Lucifer - -class BOFH (LearningAgent): - def Attack (self, foe): - attack = RandomAttack () - - return attack, bluff - def Defend (self, foe, bluff): - if bluff == Rock: attack = Scissors # Here we assume that they - elif bluff == Paper: attack = Rock # are lying, trying to kill us. - else: attack = Paper # And we try to kill them. - return attack - - def Attack (self, foe): - attack = RandomAttack () - if len(LearningAgent.GetWinHistory (self, foe)) > 0: - if attack == Rock: bluff = Paper # Here we choose the thing - elif attack == Paper: bluff = Scissors # that will hurt them - else: bluff = Rock # if they try to kill us. - else: - if attack == Rock: bluff = Scissors # Here we choose the thing - elif attack == Paper: bluff = Rock # that will hurt them - else: bluff = Paper # if they go for a tie. - return attack, bluff - - def Defend (self, foe, bluff): - if len(LearningAgent.GetWinHistory (self, foe)) > 0: - if bluff == Rock: attack = Scissors # They've fucked us in the past, - elif bluff == Paper: attack = Rock # so we assume they're lying and - else: attack = Paper # hoping we go for a kill. - else: - if bluff == Rock: attack = Paper # Here we trust that they - elif bluff == Paper: attack = Scissors # are telling the truth. - else: attack = Rock # And we try to kill them. - return attack - -#Fish is somewhat intelligent; it builds up trust and then stabs you in the back. -# If Fish detects that a bot is being predictably nice (tie 2+ times in a row), it will attack. -# If Fish detects that a bot has betrayed it (Loss), it will attack. -# Otherwise, Fish is nice. - -class Fish (LearningAgent): - def Attack (self, foe): - #print "Attacking" , foe - #print LearningAgent.GetWinHistory (self, foe) - attack = RandomAttack () - - history = LearningAgent.GetWinHistory (self, foe) - - #no history; be nice - if len(history) == 0: - bluff = attack - - #if we just lost to them, try to destroy them. - elif Loss == history[-1] or (len(history)>1 and [Tie,Tie] == history[-2:-1]): - if attack == Rock: bluff = Scissors - elif attack == Paper: bluff = Rock - else: bluff = Paper - else: - bluff = attack - return attack, bluff - - - def Defend (self, foe, bluff): - - history = LearningAgent.GetWinHistory (self, foe) - - if len(history) > 0 and Loss == history[-1]: - if bluff == Rock: attack = Scissors # They've fucked us in the past, - elif bluff == Paper: attack = Rock # so we assume they're lying and - else: attack = Paper # hoping we go for a kill. - else: - attack = bluff - return attack \ No newline at end of file diff --git a/rps/trunk/djaAgents.pyc b/rps/trunk/djaAgents.pyc deleted file mode 100644 index 9d72619..0000000 Binary files a/rps/trunk/djaAgents.pyc and /dev/null differ diff --git a/rps/trunk/rpsconst.py b/rps/trunk/rpsconst.py deleted file mode 100644 index 5bf1ea5..0000000 --- a/rps/trunk/rpsconst.py +++ /dev/null @@ -1,19 +0,0 @@ -'''rpsconst.py - A precarious collection of constants for RPS simulation. -Written by Luke Williams for the UCC Programming Competition in 2008. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - -Rock = 0 -Paper = 1 -Scissors = 2 -Attacker = 0 -Defender = 1 -Tie = 2 -Bluff = 0 -Truth = 1 -Win = 3 -Loss = 4 -# EOF. Stop reading now, kid, you'll only hurt yourself. -resultTable = [[Tie,Defender,Attacker],[Attacker,Tie,Defender],[Defender, Attacker, Tie]] -pointsTable = [[0,0],[0,0],[0,0]] diff --git a/rps/trunk/rpsconst.pyc b/rps/trunk/rpsconst.pyc deleted file mode 100644 index 6feecaf..0000000 Binary files a/rps/trunk/rpsconst.pyc and /dev/null differ diff --git a/rps/trunk/selectAlgorithms.py b/rps/trunk/selectAlgorithms.py deleted file mode 100644 index 41be346..0000000 --- a/rps/trunk/selectAlgorithms.py +++ /dev/null @@ -1,23 +0,0 @@ -# Alternative (obsolete) algorithms for selecting agents for battle. -# They're all a bit crap and only here for comparison purposes. - - -# Selects an opponent and removes it from the list of remaining potential opponents. - # This is just an example, but the fact that the first agent will miss out on having - # a fight picked with it it, and that the last agent won't get to pick a fight, seems - # to not matter very much. Can probably be left as-is. - def ChoosePair (self): - # This approach forces each agent to defend once and attack once per round. - # Keep track of the remaining population. - remaining = self.population[:] - agentID = random.randint (0,len(remaining)-1) - defender = remaining.pop (agentID) # Not really a defender (try to work it out)! - while len (remaining) > 1: - if defender.GetPoints () < 1: # If the agent died before it got a chance to attack - attackerID = random.randint (0,len(remaining)-1) - attacker = remaining.pop (attackerID) - else: attacker = defender - defenderID = random.randint (0,len(remaining)-1) - defender = remaining.pop (defenderID) - yield attacker, defender - diff --git a/rps/trunk/simulate.py b/rps/trunk/simulate.py deleted file mode 100755 index 13a20fa..0000000 --- a/rps/trunk/simulate.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/python2.5 -'''simulate.py - Runs a full simulation of the UCC Programming Competition with the provided agents. -Written by Luke Williams for the UCC Programming Competition in 2008. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - -# Import and add your agents here: -from djaAgents import BOFH -from SampleAgents import Angel, Lucifer, Dummy, Frenchie, Streetfighter -Agents = [Angel, Lucifer, Frenchie, Streetfighter, BOFH] - -#################################### -# Developers only past this point! # -#################################### - -import sys -from uccProgComp import Supervisor - -maxIterations = 150 -startingPopulations = 10 -verbose = False -trials = 1 -usage = "Usage: rps [-v] [-i iterations=150] [-n starting_populations=10] [-t trials=1]" -for i in range (1,len(sys.argv)): - if sys.argv[i] == "-i": - try: - maxIterations = int(sys.argv[i+1]) - i += 1 - continue - except: - print usage - sys.exit(1) - elif sys.argv[i] == "-n": - try: - startingPopulations = int(sys.argv[i+1]) - i += 1 - continue - except: - print usage - sys.exit(1) - elif sys.argv[i] == "-t": - try: - trials = int(sys.argv[i+1]) - i += 1 - continue - except: - print usage - sys.exit(1) - - elif sys.argv[i] == "-v": - verbose = True - - -iteration = 0 -trial = 0 -winners = {} -while trial < trials: - sup = Supervisor () - for Agent in Agents: sup.RegisterAgent (Agent) - sup.GeneratePopulation (startingPopulations) - - trial += 1 - iteration = 0 - while iteration < maxIterations and not sup.IsGameOver (): - iteration += 1 - sup.Iterate () - if not verbose: continue - print "Iteration %d:" % iteration - for key, value in sup.GetStats ().iteritems(): - print "%s: Population=%d, Newborns=%d, Deaths=%d" % (key, value[0], value[1], value[2]) - winner = ("Error", -1) - for key, value in sup.GetStats ().iteritems (): - #print key, value - if value[0] > winner[1]: - winner = (key, value[0]) - if winner[0] in winners: winners[winner[0]] += 1 - else: winners[winner[0]] = 1 - #print "Winner: %s" % winner[0] - -print "SCOREBOARD OVER %d TRIALS OF %d ROUNDS EACH" % (trials, maxIterations) -rawscoreboard = sorted ( [(score,player) for (player,score) in winners.items ()] , reverse=True ) -scoreboard = [] -for score, player in rawscoreboard: - print "%s: %s" % (player, score) - diff --git a/rps/trunk/uccProgComp.py b/rps/trunk/uccProgComp.py deleted file mode 100644 index 0eee563..0000000 --- a/rps/trunk/uccProgComp.py +++ /dev/null @@ -1,211 +0,0 @@ -'''uccProgComp.py - A supervisor candidate for Rock Paper Scissors. -Written by Luke Williams for the UCC Programming Competition in 2008. -Requires Python 2.5. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - - -import random, uuid -random.seed () - -from rpsconst import * - -DEFAULT_HEALTH = 50 -REPRODUCE_HEALTH = 100 -DIE_HEALTH = 0 -MAX_AGE = 100 - -DEBUG_MODE = False - -# Game dynamics - these are not final: -# WINNER TRUTH ATTPoints, DEFPoints -pointsTable [Attacker] [False] = (2, -2) -pointsTable [Attacker] [True] = (2, -2) -pointsTable [Defender] [False] = (-2, 2) -pointsTable [Defender] [True] = (-2, 2) -pointsTable [Tie] [False] = (0, 0) -pointsTable [Tie] [True] = (1, 1) - -def Debug (f): - def g (*args): - if DEBUG_MODE: - print f.__name__, args[1].__class__.__name__, args[1].GetID () - return f (*args) - return g - -class BaseAgent: - def __init__ (self): - self.id = uuid.uuid4().int - self.__points = DEFAULT_HEALTH - # The index will be changing all the time. It can go stale as soon as something dies. - # So use it cautiously. - self.__currentIndex = 0 - self.__reproduced = False - self.__age = 0 - - def GetCurrentIndex (self): - return self.__currentIndex - - def SetCurrentIndex (self, index): - self.__currentIndex = index - - def GetID (self): - return self.id - - def GetPoints (self): - return self.__points - - def SetPoints (self, points): - self.__points = points - - def Defend (self, foe, bluff): - return Rock - - def Attack (self, foe): - return Rock - - def IsDead (self): - return self.__points <= DIE_HEALTH - - def Reproduced (self): - self.__points = DEFAULT_HEALTH - self.__reproduced = True - - def HasReproduced (self): - return self.__reproduced - - def SetReproduced (self, repro): - self.__reproduced = repro - - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - self.__points += pointDelta - self.__age += 1 - if self.__age > MAX_AGE: self.__points = DIE_HEALTH - -class LearningAgent (BaseAgent): - def __init__ (self): - BaseAgent.__init__ (self) - self.winHistory = {} - - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) - if wasAttacker: - if winner == Attacker: result = Win - elif winner == Tie: result = Tie - else: result = Loss - else: - if winner == Attacker: result = Loss - elif winner == Tie: result = Tie - else: result = Win - - if foeName in self.winHistory: self.winHistory [foeName].append (result) - else: self.winHistory [foeName] = [result] - - def GetWinHistory (self, foeName): - if foeName in self.winHistory: return self.winHistory [foeName] - else: return [] - -class Supervisor: - def __init__ (self): - # The full list of living agents - self.population = [] - # A list of classes for each agent type - self.agentTypes = [] - # The current iteration - self.iteration = 0 - self.agentStats = {} - self.pendingDeaths = [] - - def RegisterAgent (self, agent): - self.agentTypes.append (agent) - - def GeneratePopulation (self, nAgentsPerClass): - for Agent in self.agentTypes: - for i in range (0,nAgentsPerClass): self.population.append (Agent ()) - self.agentStats [str(Agent)] = [nAgentsPerClass,0,0] - - def Iterate (self): - self.ClearStats () - self.UpdateIndexes () - self.iteration += 1 - for attacker, defender in self.Select (): - attack, bluff = attacker.Attack (defender.GetID ()) - defense = defender.Defend (attacker.GetID (), bluff) - winner = resultTable [attack] [defense] - attPoints, defPoints = pointsTable [winner][attack == bluff] - attacker.Results (defender.GetID (), True, winner, attack, defense, bluff, attPoints) - defender.Results (attacker.GetID (), False, winner, attack, defense, bluff, defPoints) - if attacker.IsDead (): self.KillAgent (attacker) - elif attacker.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (attacker) - if defender.IsDead (): self.KillAgent (defender) - elif defender.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (defender) - - def IsGameOver (self): - if self.population == []: return True - liveAgents = [id for id,stats in self.agentStats.iteritems () if stats[0] > 0] - print liveAgents - if len(liveAgents) < 2: return True - return False - - # This is needed because when we pick the players we also need a way of identifying them in the - # population list without manually searching each time. O(n) each iteration is better than O(n) - # each death. It also resets the check for if the agent has reproduced this round. - def UpdateIndexes (self): - for agentID in reversed(sorted(self.pendingDeaths)): del self.population [agentID] - for index, agent in enumerate(self.population): - agent.SetCurrentIndex (index) - agent.SetReproduced (False) - self.pendingDeaths = [] - - @Debug - def KillAgent (self, agent): - self.pendingDeaths.append (agent.GetCurrentIndex ()) - stat = self.agentStats [str(agent.__class__)] - stat [0] -= 1 - stat [2] += 1 - - @Debug - def SpawnAgent (self, agent): - child = agent.__class__ () - self.population.append (child) - agent.Reproduced () - stat = self.agentStats [str(agent.__class__)] - stat [0] += 1 - stat [1] += 1 - - def Select (self): - # This approach causes agents to keep fighting until they've either died or reproduced. - remaining = self.population[:] - attackerID = defenderID = random.randint (0,len(remaining)-1) - attacker = defender = remaining [attackerID] - while len (remaining) >= 2: - # Check to see if the attacker from last round needs to be dropped. - if attacker.IsDead () or attacker.HasReproduced (): - remaining.pop (attackerID) - if not len(remaining) >= 2: continue - if defenderID > attackerID: defenderID -= 1 - # Check to see if the defender from last round is up for some attacking. - if defender.IsDead () or defender.HasReproduced (): - remaining.pop (defenderID) - if not len(remaining) >= 2: continue - attackerID = random.randint (0,len(remaining)-1) - attacker = remaining [attackerID] - else: - attacker = defender - attackerID = defenderID - defender = None - defenderID = random.randint (0,len(remaining)-2) - if defenderID >= attackerID: defenderID += 1 - defender = remaining [defenderID] - - yield attacker, defender - - def GetStats (self): - return self.agentStats - - def ClearStats (self): - for agent in self.agentTypes: self.agentStats [str(agent)] = self.agentStats [str(agent)] [:1] + [0,0] - -def RandomAttack (): - return random.randint (0,2) diff --git a/rps/trunk/uccProgComp.py.old b/rps/trunk/uccProgComp.py.old deleted file mode 100644 index 17ffa2a..0000000 --- a/rps/trunk/uccProgComp.py.old +++ /dev/null @@ -1,211 +0,0 @@ -'''uccProgComp.py - A supervisor candidate for Rock Paper Scissors. -Written by Luke Williams for the UCC Programming Competition in 2008. -Requires Python 2.5. - -Licensed under an MIT-style license: see the LICENSE file for details. -''' - - -import random, uuid -random.seed () - -from rpsconst import * - -DEFAULT_HEALTH = 50 -REPRODUCE_HEALTH = 100 -DIE_HEALTH = 0 -MAX_AGE = 100 - -DEBUG_MODE = False - -# Game dynamics - these are not final: -# WINNER TRUTH WINNER, LOSER -pointsTable [Attacker] [False] = (2, -2) -pointsTable [Attacker] [True] = (2, -2) -pointsTable [Defender] [False] = (-2, 2) -pointsTable [Defender] [True] = (-2, 2) -pointsTable [Tie] [False] = (-1, -1) -pointsTable [Tie] [True] = (1, 1) - -def Debug (f): - def g (*args): - if DEBUG_MODE: - print f.__name__, args[1].__class__.__name__, args[1].GetID () - return f (*args) - return g - -class BaseAgent: - def __init__ (self): - self.id = uuid.uuid4().int - self.__points = DEFAULT_HEALTH - # The index will be changing all the time. It can go stale as soon as something dies. - # So use it cautiously. - self.__currentIndex = 0 - self.__reproduced = False - self.__age = 0 - - def GetCurrentIndex (self): - return self.__currentIndex - - def SetCurrentIndex (self, index): - self.__currentIndex = index - - def GetID (self): - return self.id - - def GetPoints (self): - return self.__points - - def SetPoints (self, points): - self.__points = points - - def Defend (self, foe, bluff): - return Rock - - def Attack (self, foe): - return Rock - - def IsDead (self): - return self.__points <= DIE_HEALTH - - def Reproduced (self): - self.__points = DEFAULT_HEALTH - self.__reproduced = True - - def HasReproduced (self): - return self.__reproduced - - def SetReproduced (self, repro): - self.__reproduced = repro - - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - self.__points += pointDelta - self.__age += 1 - if self.__age > MAX_AGE: self.__points = DIE_HEALTH - -class LearningAgent (BaseAgent): - def __init__ (self): - BaseAgent.__init__ (self) - self.winHistory = {} - - def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): - BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) - if wasAttacker: - if winner == Attacker: result = Win - elif winner == Tie: result = Tie - else: result = Loss - else: - if winner == Attacker: result = Loss - elif winner == Tie: result = Tie - else: result = Win - - if foeName in self.winHistory: self.winHistory [foeName].append (result) - else: self.winHistory [foeName] = [result] - - def GetWinHistory (self, foeName): - if foeName in self.winHistory: return self.winHistory [foeName] - else: return [] - -class Supervisor: - def __init__ (self): - # The full list of living agents - self.population = [] - # A list of classes for each agent type - self.agentTypes = [] - # The current iteration - self.iteration = 0 - self.agentStats = {} - self.pendingDeaths = [] - - def RegisterAgent (self, agent): - self.agentTypes.append (agent) - - def GeneratePopulation (self, nAgentsPerClass): - for Agent in self.agentTypes: - for i in range (0,nAgentsPerClass): self.population.append (Agent ()) - self.agentStats [str(Agent)] = [nAgentsPerClass,0,0] - - def Iterate (self): - self.ClearStats () - self.UpdateIndexes () - self.iteration += 1 - for attacker, defender in self.Select (): - attack, bluff = attacker.Attack (defender.GetID ()) - defense = defender.Defend (attacker.GetID (), bluff) - winner = resultTable [attack] [defense] - attPoints, defPoints = pointsTable [winner][attack == bluff] - attacker.Results (defender.GetID (), True, winner, attack, defense, bluff, attPoints) - defender.Results (attacker.GetID (), False, winner, attack, defense, bluff, defPoints) - if attacker.IsDead (): self.KillAgent (attacker) - elif attacker.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (attacker) - if defender.IsDead (): self.KillAgent (defender) - elif defender.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (defender) - - def IsGameOver (self): - if self.population == []: return True - liveAgents = [id for id,stats in self.agentStats.iteritems () if stats[0] > 0] - print liveAgents - if len(liveAgents) < 2: return True - return False - - # This is needed because when we pick the players we also need a way of identifying them in the - # population list without manually searching each time. O(n) each iteration is better than O(n) - # each death. It also resets the check for if the agent has reproduced this round. - def UpdateIndexes (self): - for agentID in reversed(sorted(self.pendingDeaths)): del self.population [agentID] - for index, agent in enumerate(self.population): - agent.SetCurrentIndex (index) - agent.SetReproduced (False) - self.pendingDeaths = [] - - @Debug - def KillAgent (self, agent): - self.pendingDeaths.append (agent.GetCurrentIndex ()) - stat = self.agentStats [str(agent.__class__)] - stat [0] -= 1 - stat [2] += 1 - - @Debug - def SpawnAgent (self, agent): - child = agent.__class__ () - self.population.append (child) - agent.Reproduced () - stat = self.agentStats [str(agent.__class__)] - stat [0] += 1 - stat [1] += 1 - - def Select (self): - # This approach causes agents to keep fighting until they've either died or reproduced. - remaining = self.population[:] - attackerID = defenderID = random.randint (0,len(remaining)-1) - attacker = defender = remaining [attackerID] - while len (remaining) >= 2: - # Check to see if the attacker from last round needs to be dropped. - if attacker.IsDead () or attacker.HasReproduced (): - remaining.pop (attackerID) - if not len(remaining) >= 2: continue - if defenderID > attackerID: defenderID -= 1 - # Check to see if the defender from last round is up for some attacking. - if defender.IsDead () or defender.HasReproduced (): - remaining.pop (defenderID) - if not len(remaining) >= 2: continue - attackerID = random.randint (0,len(remaining)-1) - attacker = remaining [attackerID] - else: - attacker = defender - attackerID = defenderID - defender = None - defenderID = random.randint (0,len(remaining)-2) - if defenderID >= attackerID: defenderID += 1 - defender = remaining [defenderID] - - yield attacker, defender - - def GetStats (self): - return self.agentStats - - def ClearStats (self): - for agent in self.agentTypes: self.agentStats [str(agent)] = self.agentStats [str(agent)] [:1] + [0,0] - -def RandomAttack (): - return random.randint (0,2) diff --git a/rps/trunk/uccProgComp.pyc b/rps/trunk/uccProgComp.pyc deleted file mode 100644 index 77283f4..0000000 Binary files a/rps/trunk/uccProgComp.pyc and /dev/null differ diff --git a/src/LICENSE b/src/LICENSE new file mode 100644 index 0000000..e25c106 --- /dev/null +++ b/src/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008 Luke Williams + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/README b/src/README new file mode 100644 index 0000000..8587cf5 --- /dev/null +++ b/src/README @@ -0,0 +1,66 @@ +Hi there, + +Thanks for taking interest in the UCC Programming Competition 2008. If you +don't already know what it's all about, check out the information provided in +the docs directory, which contains a full and authoritative* description for +the running of the competition. + +This file is by no means complete, and not ready for circulation. + +The first thing you'll probably want to do is see it work. Try running: + +./simulate -v + +to see the sample agents duke it out for up to 150 rounds (the current sample +agents suck - rounds either go for seconds or for ages). After that, take a +look at sampleAgents.py to see how agents are implemented on top of the +BaseAgent and LearningAgent classes. When you're ready to try out your own, +edit the first few lines of simulate.py to include your agent. + +...and if all you're interested in is participating, that's it! You can stop +reading, and start work on the agent that will outsmart them all! + +Contributor instructions: + +BaseAgent, LearningAgent and Supervisor are all implemented in uccProgComp.py. +The 'select' algorithm, responsible for choosing agents for battle and +determining when a round is finished, is the hottest part of the code and the +most open to discussion and change. + +Unfortunately, it is not an easy bit of code to understand. Once upon a time, +in builds long past, it used friendly O(n) operations and conveniently wasted +memory on simple tasks. After hours of profiling, it is a little more complex, +but with a bit of background to how the supervisor operates you shouldn't have +much trouble working out the rest: + +1.) A copy of the current population list is made at the beginning of the round +representing the agents who can still fight. This reduces finding valid agents +from O(n) to O(1). I call it the 'remaining' list. +2.) Agents must remember their index in the population list. This is because it +would be O(n) to determine their index in the population list (to remove them +when they die) from their index in the 'remaining' list. Agents have this value +stored at the beginning of the round - O(n) at the beginning of the round is +far preferable to O(n) for every death. +3.) The actual removal of agents from the population list must happen all at +once in reverse numeric index order at the end of the round so that the stored +index that agents have does not become stale. + +There are problems. It's not perfect, but it's relatively fast and powerful and +quite easy to adjust or reimplement once you get your head around it. I'm very +much open to suggestion for improvement (especially in the form of patches) and +welcome all help, constructive criticism, derisive criticism and death threats. + +Things to be done: + +1.) Pretty graphs! Iterate () returns a collection of statistics about each of +the classes, which can be seen used in simulate.py. There are plenty of +plotting packages out there that can turn this information into impressive +charts. +2.) More built-in functionality for BaseAgent and LearningAgent. They could +both do with a few more utility functions for competitors to use. +3.) A more succint set of rules and documentation. + +Thanks for reading! +Luke + +* Or rather, it wil by the time this package is ready for distribution. diff --git a/src/SampleAgents.py b/src/SampleAgents.py new file mode 100644 index 0000000..6da30ba --- /dev/null +++ b/src/SampleAgents.py @@ -0,0 +1,89 @@ +'''SampleAgents.py - A collection of sample agents for playing Rock Paper Scissors. +Written by Luke Williams for the UCC Programming Competition in 2008. +Requires Python 2.5. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + +from uccProgComp import BaseAgent, LearningAgent, RandomAttack +from rpsconst import * + +# Angel is a very simple bot that always tells the truth and expects others to do the same. +class Dummy (BaseAgent): + def Attack (self, foe): + return Paper, Paper + def Defend (self, foe, bluff): + return bluff + +class Angel (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () # Chooses randomly from Rock, Paper, Scissors + return attack, attack # Tells the truth for its bluff. + def Defend (self, foe, bluff): + return bluff # Trusts them to be going for a tie. + +# Lucifer here is the opposite. He always lies expecting people to be good and always goes for the kill. +class Lucifer (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () + if attack == Rock: bluff = Scissors # Here we choose the thing + elif attack == Paper: bluff = Rock # that will hurt them + else: bluff = Paper # if they go for a tie. + return attack, bluff + def Defend (self, foe, bluff): + if bluff == Rock: attack = Paper # Here we trust that they + elif bluff == Paper: attack = Scissors # are telling the truth. + else: attack = Rock # And we try to kill them. + return attack +# def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): +# BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) +# print "I just scored " + str(pointDelta) + " points!" + + +# Streetfighter assumes everyone has it in for him. +class Streetfighter (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () + if attack == Rock: bluff = Paper # Here we choose the thing + elif attack == Paper: bluff = Scissors # that will hurt them + else: bluff = Rock # if they try to kill us. + return attack, bluff + def Defend (self, foe, bluff): + if bluff == Rock: attack = Scissors # Here we assume that they + elif bluff == Paper: attack = Rock # are lying, trying to kill us. + else: attack = Paper # And we try to kill them. + return attack + +# This is our first bot with any sort of learning capability, based on the LearningAgent base. +# Experienced programmers might opt to write their own learning code based on BaseAgent, but it's up to you. +# Frenchie is a simple bot that is by default nice but will permanently turn against any agent that betrays it. +class Frenchie (LearningAgent): + def Attack (self, foe): + attack = RandomAttack () + if Loss in LearningAgent.GetWinHistory (self, foe): + if attack == Rock: bluff = Scissors + elif attack == Paper: bluff = Rock + else: bluff = Paper + else: + bluff = attack + return attack, bluff + def Defend (self, foe, bluff): + if Loss in LearningAgent.GetWinHistory (self, foe): + if bluff == Rock: attack = Scissors # They've fucked us in the past, + elif bluff == Paper: attack = Rock # so we assume they're lying and + else: attack = Paper # hoping we go for a kill. + else: + attack = bluff + return attack + + +# If you want to implement your own Results () callback, you have to call the parent class's first: +class Blank (BaseAgent): + def Attack (self, foe): + return Paper, Paper + def Defend (self, foe, bluff): + return bluff + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) + # Now you can do your own thing + diff --git a/src/SampleAgents.py.old b/src/SampleAgents.py.old new file mode 100644 index 0000000..d307214 --- /dev/null +++ b/src/SampleAgents.py.old @@ -0,0 +1,89 @@ +'''SampleAgents.py - A collection of sample agents for playing Rock Paper Scissors. +Written by Luke Williams for the UCC Programming Competition in 2008. +Requires Python 2.5. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + +from uccProgComp import BaseAgent, LearningAgent, RandomAttack +from rpsconst import * + +# Angel is a very simple bot that always tells the truth and expects others to do the same. +class Dummy (BaseAgent): + def Attack (self, foe): + return Paper, Paper + def Defend (self, foe, bluff): + return bluff + +class Angel (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () # Chooses randomly from Rock, Paper, Scissors + return attack, attack # Tells the truth for its bluff. + def Defend (self, foe, bluff): + return bluff # Trusts them to be going for a tie. + +# Lucifer here is the opposite. He always lies expecting people to be good and always goes for the kill. +class Lucifer (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () + if attack == Rock: bluff = Scissors # Here we choose the thing + elif attack == Paper: bluff = Rock # that will hurt them + else: bluff = Paper # if they go for a tie. + return attack, bluff + def Defend (self, foe, bluff): + if bluff == Rock: attack = Paper # Here we trust that they + elif bluff == Paper: attack = Scissors # are telling the truth. + else: attack = Rock # And we try to kill them. + return attack +# def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): +# BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) +# print "I just scored " + str(pointDelta) + " points!" + + +# Streetfighter assumes everyone has it in for him. +class Streetfighter (BaseAgent): + def Attack (self, foe): + attack = RandomAttack () + if attack == Rock: bluff = Paper # Here we choose the thing + elif attack == Paper: bluff = Scissors # that will hurt them + else: bluff = Rock # if they go for a tie. + return attack, bluff + def Defend (self, foe, bluff): + if bluff == Rock: attack = Paper # Here we trust that they + elif bluff == Paper: attack = Scissors # are telling the truth. + else: attack = Rock # And we try to kill them. + return attack + +# This is our first bot with any sort of learning capability, based on the LearningAgent base. +# Experienced programmers might opt to write their own learning code based on BaseAgent, but it's up to you. +# Frenchie is a simple bot that is by default nice but will permanently turn against any agent that betrays it. +class Frenchie (LearningAgent): + def Attack (self, foe): + attack = RandomAttack () + if Loss in LearningAgent.GetWinHistory (self, foe): + if attack == Rock: bluff = Scissors + elif attack == Paper: bluff = Rock + else: bluff = Paper + else: + bluff = attack + return attack, bluff + def Defend (self, foe, bluff): + if Loss in LearningAgent.GetWinHistory (self, foe): + if bluff == Rock: attack = Scissors # They've fucked us in the past, + elif bluff == Paper: attack = Rock # so we assume they're lying and + else: attack = Paper # hoping we go for a kill. + else: + attack = bluff + return attack + + +# If you want to implement your own Results () callback, you have to call the parent class's first: +class Blank (BaseAgent): + def Attack (self, foe): + return Paper, Paper + def Defend (self, foe, bluff): + return bluff + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) + # Now you can do your own thing + diff --git a/src/SampleAgents.pyc b/src/SampleAgents.pyc new file mode 100644 index 0000000..7b91932 Binary files /dev/null and b/src/SampleAgents.pyc differ diff --git a/src/djaAgents.py b/src/djaAgents.py new file mode 100644 index 0000000..6912c7f --- /dev/null +++ b/src/djaAgents.py @@ -0,0 +1,77 @@ +from uccProgComp import BaseAgent, LearningAgent, RandomAttack +from rpsconst import * + +# BOFH is something of a cross between Frechie and Lucifer + +class BOFH (LearningAgent): + def Attack (self, foe): + attack = RandomAttack () + + return attack, bluff + def Defend (self, foe, bluff): + if bluff == Rock: attack = Scissors # Here we assume that they + elif bluff == Paper: attack = Rock # are lying, trying to kill us. + else: attack = Paper # And we try to kill them. + return attack + + def Attack (self, foe): + attack = RandomAttack () + if len(LearningAgent.GetWinHistory (self, foe)) > 0: + if attack == Rock: bluff = Paper # Here we choose the thing + elif attack == Paper: bluff = Scissors # that will hurt them + else: bluff = Rock # if they try to kill us. + else: + if attack == Rock: bluff = Scissors # Here we choose the thing + elif attack == Paper: bluff = Rock # that will hurt them + else: bluff = Paper # if they go for a tie. + return attack, bluff + + def Defend (self, foe, bluff): + if len(LearningAgent.GetWinHistory (self, foe)) > 0: + if bluff == Rock: attack = Scissors # They've fucked us in the past, + elif bluff == Paper: attack = Rock # so we assume they're lying and + else: attack = Paper # hoping we go for a kill. + else: + if bluff == Rock: attack = Paper # Here we trust that they + elif bluff == Paper: attack = Scissors # are telling the truth. + else: attack = Rock # And we try to kill them. + return attack + +#Fish is somewhat intelligent; it builds up trust and then stabs you in the back. +# If Fish detects that a bot is being predictably nice (tie 2+ times in a row), it will attack. +# If Fish detects that a bot has betrayed it (Loss), it will attack. +# Otherwise, Fish is nice. + +class Fish (LearningAgent): + def Attack (self, foe): + #print "Attacking" , foe + #print LearningAgent.GetWinHistory (self, foe) + attack = RandomAttack () + + history = LearningAgent.GetWinHistory (self, foe) + + #no history; be nice + if len(history) == 0: + bluff = attack + + #if we just lost to them, try to destroy them. + elif Loss == history[-1] or (len(history)>1 and [Tie,Tie] == history[-2:-1]): + if attack == Rock: bluff = Scissors + elif attack == Paper: bluff = Rock + else: bluff = Paper + else: + bluff = attack + return attack, bluff + + + def Defend (self, foe, bluff): + + history = LearningAgent.GetWinHistory (self, foe) + + if len(history) > 0 and Loss == history[-1]: + if bluff == Rock: attack = Scissors # They've fucked us in the past, + elif bluff == Paper: attack = Rock # so we assume they're lying and + else: attack = Paper # hoping we go for a kill. + else: + attack = bluff + return attack \ No newline at end of file diff --git a/src/djaAgents.pyc b/src/djaAgents.pyc new file mode 100644 index 0000000..9d72619 Binary files /dev/null and b/src/djaAgents.pyc differ diff --git a/src/link/C/c-link-lib/.gitignore b/src/link/C/c-link-lib/.gitignore new file mode 100644 index 0000000..fbde527 --- /dev/null +++ b/src/link/C/c-link-lib/.gitignore @@ -0,0 +1,2 @@ +agents/ +!agents/*.c diff --git a/src/link/C/c-link-lib/Makefile b/src/link/C/c-link-lib/Makefile new file mode 100644 index 0000000..10e306b --- /dev/null +++ b/src/link/C/c-link-lib/Makefile @@ -0,0 +1,28 @@ +CC=gcc +AR=ar + +CFLAGS=-Wall -I. +LDFLAGS=-lc_link -L. + +LINKSRCS=c_link.c +LINKOBJS=$(LINKSRCS:.c=.o) +LINKLIB=libc_link.a + +AGENTSRCS=$(wildcard agents/*.c) +AGENTS=$(AGENTSRCS:.c=) + +all: $(LINKSRCS) $(LINKLIB) $(AGENTS) + +$(LINKLIB): $(LINKOBJS) + $(AR) rcs $(LINKLIB) $(LINKOBJS) + +$(AGENTS): $(AGENTSRCS) + @echo Building $< + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +.c.o: c_link.h + $(CC) -c $(CFLAGS) $< -o $@ + +.PHONY : clean +clean: + rm $(LINKOBJS) $(LINKLIB) $(AGENTS) diff --git a/src/link/C/c-link-lib/agents/c-angel.c b/src/link/C/c-link-lib/agents/c-angel.c new file mode 100644 index 0000000..c6c8687 --- /dev/null +++ b/src/link/C/c-link-lib/agents/c-angel.c @@ -0,0 +1,40 @@ +/* + * 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 + +/* 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, ITEMTYPE yourItem, + ITEMTYPE theirItem, ITEMTYPE promisedItem) { + + return; /* Ignore whatever just happened. */ +} + +/* same for Cleanup() */ + +void Cleanup() { + return; +} \ No newline at end of file diff --git a/src/link/C/c-link-lib/agents/c-frechie.c b/src/link/C/c-link-lib/agents/c-frechie.c new file mode 100644 index 0000000..ed2ba09 --- /dev/null +++ b/src/link/C/c-link-lib/agents/c-frechie.c @@ -0,0 +1,104 @@ +/* + * 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 +#include + +/* Implement the frenchie bot, 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 */ +#define NUMBEROFAGENTSGUESS 100 + +/* The name of the n-th foe we've seen, as well as a 0/1 have we lost to them */ +char foesNames[][MAXFOENAMELEN] = NULL; +int haveLostToFoe[] = NULL; + +/* The length of the array, and how far we are along it */ +size_t foesLen = 0; +unsigned int foesCount = 0; + + +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: + result.promisedAttack = paper; + break; + case paper: + result.promisedAttack = scissors; + break; + default: /* attack = scissors */ + result.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; + } +} + +/* This is so much less fun in C */ +void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, + ITEMTYPE theirItem, ITEMTYPE promisedItem) { + + int foe; + + /* check to see if we've initialised our arrays */ + if (foesNames == NULL) { + foesNames = calloc( NUMBEROFAGENTSGUESS, sizeof( foesNames[0] ) ); + haveLostToFoe = calloc( NUMBEROFAGENTSGUESS, sizeof( haveLostToFoe[0] ) ); + foesLen = NUMBEROFAGENTSGUESS; + } + + /* figure out if we lost, which is the only thing we care about + if we didn't, move on. */ + if (RESULTOF[yourItem][theirItem] != lose) return; + + /* try and find existing foe */ + + return; +} + +/* same for Cleanup() */ + +void Cleanup() { + free(foesNames); + free(haveLostToFoe); +} \ No newline at end of file diff --git a/src/link/C/c-link-lib/agents/c-lucifer.c b/src/link/C/c-link-lib/agents/c-lucifer.c new file mode 100644 index 0000000..1dabc34 --- /dev/null +++ b/src/link/C/c-link-lib/agents/c-lucifer.c @@ -0,0 +1,66 @@ +/* + * 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 + +/* 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: + result.promisedAttack = scissors; + break; + case paper: + result.promisedAttack = rock; + break; + default: /* attack = scissors */ + result.promisedAttack = paper; + break; + } + attack.promisedAttack = result.realAttack; /* Tells the truth for its bluff */ + + 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; + } +} + +/* You need to define a results function, even if it isn't used + (otherwise the linker will complain) */ +void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, + ITEMTYPE theirItem, ITEMTYPE promisedItem) { + + return; /* Ignore whatever just happened. */ +} + +/* same for Cleanup() */ + +void Cleanup() { + return; +} \ No newline at end of file diff --git a/src/link/C/c-link-lib/agents/c-streetfighter.c b/src/link/C/c-link-lib/agents/c-streetfighter.c new file mode 100644 index 0000000..c63939d --- /dev/null +++ b/src/link/C/c-link-lib/agents/c-streetfighter.c @@ -0,0 +1,63 @@ +/* + * 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 + +/* 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: + result.promisedAttack = paper; + break; + case paper: + result.promisedAttack = scissors; + break; + default: /* attack = scissors */ + result.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; + } +} + +/* You need to define a results function, even if it isn't used + (otherwise the linker will complain) */ +void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, + ITEMTYPE theirItem, ITEMTYPE promisedItem) { + + return; /* Ignore whatever just happened. */ +} + +/* same for Cleanup() */ + +void Cleanup() { + return; +} diff --git a/src/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj b/src/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj new file mode 100644 index 0000000..80d9803 --- /dev/null +++ b/src/link/C/c-link-lib/c-link-lib.xcodeproj/project.pbxproj @@ -0,0 +1,150 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXFileReference section */ + 2291A1BB117EDB9600854CBE /* c_link.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = c_link.c; sourceTree = ""; }; + 2291A1BD117EE3FD00854CBE /* c-angel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-angel.c"; sourceTree = ""; }; + 2291A1BE117EE3FD00854CBE /* c-lucifer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-lucifer.c"; sourceTree = ""; }; + 2291A1BF117EE3FD00854CBE /* c-streetfighter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-streetfighter.c"; sourceTree = ""; }; + 2291A1EC117FF85D00854CBE /* c-frechie.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c-frechie.c"; sourceTree = ""; }; + 22F652F5117C679300A3793D /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + 22F652F6117C6C9500A3793D /* c_link.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = c_link.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* c-link-lib */ = { + isa = PBXGroup; + children = ( + 2291A1BC117EE3FD00854CBE /* agents */, + 22F652F6117C6C9500A3793D /* c_link.h */, + 2291A1BB117EDB9600854CBE /* c_link.c */, + 22F652F5117C679300A3793D /* Makefile */, + ); + name = "c-link-lib"; + sourceTree = ""; + }; + 2291A1BC117EE3FD00854CBE /* agents */ = { + isa = PBXGroup; + children = ( + 2291A1BD117EE3FD00854CBE /* c-angel.c */, + 2291A1BE117EE3FD00854CBE /* c-lucifer.c */, + 2291A1BF117EE3FD00854CBE /* c-streetfighter.c */, + 2291A1EC117FF85D00854CBE /* c-frechie.c */, + ); + path = agents; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + D28A88AD04BDD90700651E21 /* c-link-lib */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION)"; + buildConfigurationList = 1DEB918F08733D9F0010E9CD /* Build configuration list for PBXLegacyTarget "c-link-lib" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ""; + dependencies = ( + ); + name = "c-link-lib"; + passBuildSettingsInEnvironment = 1; + productName = "c-link-lib"; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB919308733D9F0010E9CD /* Build configuration list for PBXProject "c-link-lib" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* c-link-lib */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D28A88AD04BDD90700651E21 /* c-link-lib */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + 1DEB919008733D9F0010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "c-link-lib"; + }; + name = Debug; + }; + 1DEB919108733D9F0010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "c-link-lib"; + }; + name = Release; + }; + 1DEB919408733D9F0010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB919508733D9F0010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB918F08733D9F0010E9CD /* Build configuration list for PBXLegacyTarget "c-link-lib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB919008733D9F0010E9CD /* Debug */, + 1DEB919108733D9F0010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB919308733D9F0010E9CD /* Build configuration list for PBXProject "c-link-lib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB919408733D9F0010E9CD /* Debug */, + 1DEB919508733D9F0010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/src/link/C/c-link-lib/c_link.c b/src/link/C/c-link-lib/c_link.c new file mode 100644 index 0000000..680450e --- /dev/null +++ b/src/link/C/c-link-lib/c_link.c @@ -0,0 +1,87 @@ +/* + * 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 +#include +#include +#include + +/* You don't need to read this file. + All you have to do is implement the bot functions defined in + 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, lose, win }, + { win, tie, lose }, + { lose, win, 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; +} + + +int main( int argc, char * argv[] ) { + srand( time( NULL ) ); + + char command[MAXCOMMANDLEN]; + char foeName[MAXFOENAMELEN]; + char yourItem[MAXITEMLEN], theirItem[MAXITEMLEN], promisedItem[MAXITEMLEN]; + char didYouInstigate[MAXBOOLLEN], childSpawned[MAXBOOLLEN]; + int pointChange; + + ATTACKTYPE attack; + ITEMTYPE defence; + + 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, promisedItem ); + defence = Defend(foeName, stringToItem(promisedItem)); + printf("DEFENDING %s\n", ITEMNAMES[defence]); + + } else if (strcasecmp("RESULTS", command) == 0) { + scanf( "%s %s %s %s %s %d %s", foeName, didYouInstigate, yourItem, theirItem, promisedItem, &pointChange, childSpawned ); + Results(foeName, (strcasecmp("False",didYouInstigate)==0), + stringToItem(yourItem), stringToItem(theirItem), stringToItem(promisedItem)); + printf("OK\n"); + } + + // read the next command! + scanf( "%s", command ); + } + + Cleanup(); + + return 0; +} \ No newline at end of file diff --git a/src/link/C/c-link-lib/c_link.h b/src/link/C/c-link-lib/c_link.h new file mode 100644 index 0000000..84e9bce --- /dev/null +++ b/src/link/C/c-link-lib/c_link.h @@ -0,0 +1,97 @@ +/* + * 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 + +#define MAXCOMMANDLEN 15 +#define MAXFOENAMELEN 50 +#define MAXITEMLEN 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 */ +typedef enum {win, lose, 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...) sprintf(stderr, x) + +/* Returns a random item */ + +ITEMTYPE RandomAttack(); + +/* A useful translation table + eg printf( "I use %s.\n", ITEMNAMES[rock] ); */ + +extern char ITEMNAMES[3][MAXITEMLEN]; + +/* Another useful table - what's the result of the + first item vs 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; + yourItem : ITEMTYPE - the item you used; + theirItem : ITEMTYPE - the item they used; + promisedItem : ITEMTYPE - the item that was promised + ); + + Called after your agent battles another agent, to tell you how the battle goes. + + */ +void Results( char * foeName, int isInstigatedByYou, ITEMTYPE yourItem, + ITEMTYPE theirItem, ITEMTYPE promisedItem); + +/* 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 diff --git a/src/link/Mathematica/pyml.tar.gz b/src/link/Mathematica/pyml.tar.gz new file mode 100644 index 0000000..498748f Binary files /dev/null and b/src/link/Mathematica/pyml.tar.gz differ diff --git a/src/link/Mathematica/pythonika-1.0.tar.gz b/src/link/Mathematica/pythonika-1.0.tar.gz new file mode 100644 index 0000000..6611f5d Binary files /dev/null and b/src/link/Mathematica/pythonika-1.0.tar.gz differ diff --git a/src/rpsconst.py b/src/rpsconst.py new file mode 100644 index 0000000..5bf1ea5 --- /dev/null +++ b/src/rpsconst.py @@ -0,0 +1,19 @@ +'''rpsconst.py - A precarious collection of constants for RPS simulation. +Written by Luke Williams for the UCC Programming Competition in 2008. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + +Rock = 0 +Paper = 1 +Scissors = 2 +Attacker = 0 +Defender = 1 +Tie = 2 +Bluff = 0 +Truth = 1 +Win = 3 +Loss = 4 +# EOF. Stop reading now, kid, you'll only hurt yourself. +resultTable = [[Tie,Defender,Attacker],[Attacker,Tie,Defender],[Defender, Attacker, Tie]] +pointsTable = [[0,0],[0,0],[0,0]] diff --git a/src/rpsconst.pyc b/src/rpsconst.pyc new file mode 100644 index 0000000..6feecaf Binary files /dev/null and b/src/rpsconst.pyc differ diff --git a/src/selectAlgorithms.py b/src/selectAlgorithms.py new file mode 100644 index 0000000..41be346 --- /dev/null +++ b/src/selectAlgorithms.py @@ -0,0 +1,23 @@ +# Alternative (obsolete) algorithms for selecting agents for battle. +# They're all a bit crap and only here for comparison purposes. + + +# Selects an opponent and removes it from the list of remaining potential opponents. + # This is just an example, but the fact that the first agent will miss out on having + # a fight picked with it it, and that the last agent won't get to pick a fight, seems + # to not matter very much. Can probably be left as-is. + def ChoosePair (self): + # This approach forces each agent to defend once and attack once per round. + # Keep track of the remaining population. + remaining = self.population[:] + agentID = random.randint (0,len(remaining)-1) + defender = remaining.pop (agentID) # Not really a defender (try to work it out)! + while len (remaining) > 1: + if defender.GetPoints () < 1: # If the agent died before it got a chance to attack + attackerID = random.randint (0,len(remaining)-1) + attacker = remaining.pop (attackerID) + else: attacker = defender + defenderID = random.randint (0,len(remaining)-1) + defender = remaining.pop (defenderID) + yield attacker, defender + diff --git a/src/simulate.py b/src/simulate.py new file mode 100755 index 0000000..13a20fa --- /dev/null +++ b/src/simulate.py @@ -0,0 +1,86 @@ +#!/usr/bin/python2.5 +'''simulate.py - Runs a full simulation of the UCC Programming Competition with the provided agents. +Written by Luke Williams for the UCC Programming Competition in 2008. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + +# Import and add your agents here: +from djaAgents import BOFH +from SampleAgents import Angel, Lucifer, Dummy, Frenchie, Streetfighter +Agents = [Angel, Lucifer, Frenchie, Streetfighter, BOFH] + +#################################### +# Developers only past this point! # +#################################### + +import sys +from uccProgComp import Supervisor + +maxIterations = 150 +startingPopulations = 10 +verbose = False +trials = 1 +usage = "Usage: rps [-v] [-i iterations=150] [-n starting_populations=10] [-t trials=1]" +for i in range (1,len(sys.argv)): + if sys.argv[i] == "-i": + try: + maxIterations = int(sys.argv[i+1]) + i += 1 + continue + except: + print usage + sys.exit(1) + elif sys.argv[i] == "-n": + try: + startingPopulations = int(sys.argv[i+1]) + i += 1 + continue + except: + print usage + sys.exit(1) + elif sys.argv[i] == "-t": + try: + trials = int(sys.argv[i+1]) + i += 1 + continue + except: + print usage + sys.exit(1) + + elif sys.argv[i] == "-v": + verbose = True + + +iteration = 0 +trial = 0 +winners = {} +while trial < trials: + sup = Supervisor () + for Agent in Agents: sup.RegisterAgent (Agent) + sup.GeneratePopulation (startingPopulations) + + trial += 1 + iteration = 0 + while iteration < maxIterations and not sup.IsGameOver (): + iteration += 1 + sup.Iterate () + if not verbose: continue + print "Iteration %d:" % iteration + for key, value in sup.GetStats ().iteritems(): + print "%s: Population=%d, Newborns=%d, Deaths=%d" % (key, value[0], value[1], value[2]) + winner = ("Error", -1) + for key, value in sup.GetStats ().iteritems (): + #print key, value + if value[0] > winner[1]: + winner = (key, value[0]) + if winner[0] in winners: winners[winner[0]] += 1 + else: winners[winner[0]] = 1 + #print "Winner: %s" % winner[0] + +print "SCOREBOARD OVER %d TRIALS OF %d ROUNDS EACH" % (trials, maxIterations) +rawscoreboard = sorted ( [(score,player) for (player,score) in winners.items ()] , reverse=True ) +scoreboard = [] +for score, player in rawscoreboard: + print "%s: %s" % (player, score) + diff --git a/src/uccProgComp.py b/src/uccProgComp.py new file mode 100644 index 0000000..0eee563 --- /dev/null +++ b/src/uccProgComp.py @@ -0,0 +1,211 @@ +'''uccProgComp.py - A supervisor candidate for Rock Paper Scissors. +Written by Luke Williams for the UCC Programming Competition in 2008. +Requires Python 2.5. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + + +import random, uuid +random.seed () + +from rpsconst import * + +DEFAULT_HEALTH = 50 +REPRODUCE_HEALTH = 100 +DIE_HEALTH = 0 +MAX_AGE = 100 + +DEBUG_MODE = False + +# Game dynamics - these are not final: +# WINNER TRUTH ATTPoints, DEFPoints +pointsTable [Attacker] [False] = (2, -2) +pointsTable [Attacker] [True] = (2, -2) +pointsTable [Defender] [False] = (-2, 2) +pointsTable [Defender] [True] = (-2, 2) +pointsTable [Tie] [False] = (0, 0) +pointsTable [Tie] [True] = (1, 1) + +def Debug (f): + def g (*args): + if DEBUG_MODE: + print f.__name__, args[1].__class__.__name__, args[1].GetID () + return f (*args) + return g + +class BaseAgent: + def __init__ (self): + self.id = uuid.uuid4().int + self.__points = DEFAULT_HEALTH + # The index will be changing all the time. It can go stale as soon as something dies. + # So use it cautiously. + self.__currentIndex = 0 + self.__reproduced = False + self.__age = 0 + + def GetCurrentIndex (self): + return self.__currentIndex + + def SetCurrentIndex (self, index): + self.__currentIndex = index + + def GetID (self): + return self.id + + def GetPoints (self): + return self.__points + + def SetPoints (self, points): + self.__points = points + + def Defend (self, foe, bluff): + return Rock + + def Attack (self, foe): + return Rock + + def IsDead (self): + return self.__points <= DIE_HEALTH + + def Reproduced (self): + self.__points = DEFAULT_HEALTH + self.__reproduced = True + + def HasReproduced (self): + return self.__reproduced + + def SetReproduced (self, repro): + self.__reproduced = repro + + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + self.__points += pointDelta + self.__age += 1 + if self.__age > MAX_AGE: self.__points = DIE_HEALTH + +class LearningAgent (BaseAgent): + def __init__ (self): + BaseAgent.__init__ (self) + self.winHistory = {} + + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) + if wasAttacker: + if winner == Attacker: result = Win + elif winner == Tie: result = Tie + else: result = Loss + else: + if winner == Attacker: result = Loss + elif winner == Tie: result = Tie + else: result = Win + + if foeName in self.winHistory: self.winHistory [foeName].append (result) + else: self.winHistory [foeName] = [result] + + def GetWinHistory (self, foeName): + if foeName in self.winHistory: return self.winHistory [foeName] + else: return [] + +class Supervisor: + def __init__ (self): + # The full list of living agents + self.population = [] + # A list of classes for each agent type + self.agentTypes = [] + # The current iteration + self.iteration = 0 + self.agentStats = {} + self.pendingDeaths = [] + + def RegisterAgent (self, agent): + self.agentTypes.append (agent) + + def GeneratePopulation (self, nAgentsPerClass): + for Agent in self.agentTypes: + for i in range (0,nAgentsPerClass): self.population.append (Agent ()) + self.agentStats [str(Agent)] = [nAgentsPerClass,0,0] + + def Iterate (self): + self.ClearStats () + self.UpdateIndexes () + self.iteration += 1 + for attacker, defender in self.Select (): + attack, bluff = attacker.Attack (defender.GetID ()) + defense = defender.Defend (attacker.GetID (), bluff) + winner = resultTable [attack] [defense] + attPoints, defPoints = pointsTable [winner][attack == bluff] + attacker.Results (defender.GetID (), True, winner, attack, defense, bluff, attPoints) + defender.Results (attacker.GetID (), False, winner, attack, defense, bluff, defPoints) + if attacker.IsDead (): self.KillAgent (attacker) + elif attacker.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (attacker) + if defender.IsDead (): self.KillAgent (defender) + elif defender.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (defender) + + def IsGameOver (self): + if self.population == []: return True + liveAgents = [id for id,stats in self.agentStats.iteritems () if stats[0] > 0] + print liveAgents + if len(liveAgents) < 2: return True + return False + + # This is needed because when we pick the players we also need a way of identifying them in the + # population list without manually searching each time. O(n) each iteration is better than O(n) + # each death. It also resets the check for if the agent has reproduced this round. + def UpdateIndexes (self): + for agentID in reversed(sorted(self.pendingDeaths)): del self.population [agentID] + for index, agent in enumerate(self.population): + agent.SetCurrentIndex (index) + agent.SetReproduced (False) + self.pendingDeaths = [] + + @Debug + def KillAgent (self, agent): + self.pendingDeaths.append (agent.GetCurrentIndex ()) + stat = self.agentStats [str(agent.__class__)] + stat [0] -= 1 + stat [2] += 1 + + @Debug + def SpawnAgent (self, agent): + child = agent.__class__ () + self.population.append (child) + agent.Reproduced () + stat = self.agentStats [str(agent.__class__)] + stat [0] += 1 + stat [1] += 1 + + def Select (self): + # This approach causes agents to keep fighting until they've either died or reproduced. + remaining = self.population[:] + attackerID = defenderID = random.randint (0,len(remaining)-1) + attacker = defender = remaining [attackerID] + while len (remaining) >= 2: + # Check to see if the attacker from last round needs to be dropped. + if attacker.IsDead () or attacker.HasReproduced (): + remaining.pop (attackerID) + if not len(remaining) >= 2: continue + if defenderID > attackerID: defenderID -= 1 + # Check to see if the defender from last round is up for some attacking. + if defender.IsDead () or defender.HasReproduced (): + remaining.pop (defenderID) + if not len(remaining) >= 2: continue + attackerID = random.randint (0,len(remaining)-1) + attacker = remaining [attackerID] + else: + attacker = defender + attackerID = defenderID + defender = None + defenderID = random.randint (0,len(remaining)-2) + if defenderID >= attackerID: defenderID += 1 + defender = remaining [defenderID] + + yield attacker, defender + + def GetStats (self): + return self.agentStats + + def ClearStats (self): + for agent in self.agentTypes: self.agentStats [str(agent)] = self.agentStats [str(agent)] [:1] + [0,0] + +def RandomAttack (): + return random.randint (0,2) diff --git a/src/uccProgComp.py.old b/src/uccProgComp.py.old new file mode 100644 index 0000000..17ffa2a --- /dev/null +++ b/src/uccProgComp.py.old @@ -0,0 +1,211 @@ +'''uccProgComp.py - A supervisor candidate for Rock Paper Scissors. +Written by Luke Williams for the UCC Programming Competition in 2008. +Requires Python 2.5. + +Licensed under an MIT-style license: see the LICENSE file for details. +''' + + +import random, uuid +random.seed () + +from rpsconst import * + +DEFAULT_HEALTH = 50 +REPRODUCE_HEALTH = 100 +DIE_HEALTH = 0 +MAX_AGE = 100 + +DEBUG_MODE = False + +# Game dynamics - these are not final: +# WINNER TRUTH WINNER, LOSER +pointsTable [Attacker] [False] = (2, -2) +pointsTable [Attacker] [True] = (2, -2) +pointsTable [Defender] [False] = (-2, 2) +pointsTable [Defender] [True] = (-2, 2) +pointsTable [Tie] [False] = (-1, -1) +pointsTable [Tie] [True] = (1, 1) + +def Debug (f): + def g (*args): + if DEBUG_MODE: + print f.__name__, args[1].__class__.__name__, args[1].GetID () + return f (*args) + return g + +class BaseAgent: + def __init__ (self): + self.id = uuid.uuid4().int + self.__points = DEFAULT_HEALTH + # The index will be changing all the time. It can go stale as soon as something dies. + # So use it cautiously. + self.__currentIndex = 0 + self.__reproduced = False + self.__age = 0 + + def GetCurrentIndex (self): + return self.__currentIndex + + def SetCurrentIndex (self, index): + self.__currentIndex = index + + def GetID (self): + return self.id + + def GetPoints (self): + return self.__points + + def SetPoints (self, points): + self.__points = points + + def Defend (self, foe, bluff): + return Rock + + def Attack (self, foe): + return Rock + + def IsDead (self): + return self.__points <= DIE_HEALTH + + def Reproduced (self): + self.__points = DEFAULT_HEALTH + self.__reproduced = True + + def HasReproduced (self): + return self.__reproduced + + def SetReproduced (self, repro): + self.__reproduced = repro + + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + self.__points += pointDelta + self.__age += 1 + if self.__age > MAX_AGE: self.__points = DIE_HEALTH + +class LearningAgent (BaseAgent): + def __init__ (self): + BaseAgent.__init__ (self) + self.winHistory = {} + + def Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta): + BaseAgent.Results (self, foeName, wasAttacker, winner, attItem, defItem, bluffItem, pointDelta) + if wasAttacker: + if winner == Attacker: result = Win + elif winner == Tie: result = Tie + else: result = Loss + else: + if winner == Attacker: result = Loss + elif winner == Tie: result = Tie + else: result = Win + + if foeName in self.winHistory: self.winHistory [foeName].append (result) + else: self.winHistory [foeName] = [result] + + def GetWinHistory (self, foeName): + if foeName in self.winHistory: return self.winHistory [foeName] + else: return [] + +class Supervisor: + def __init__ (self): + # The full list of living agents + self.population = [] + # A list of classes for each agent type + self.agentTypes = [] + # The current iteration + self.iteration = 0 + self.agentStats = {} + self.pendingDeaths = [] + + def RegisterAgent (self, agent): + self.agentTypes.append (agent) + + def GeneratePopulation (self, nAgentsPerClass): + for Agent in self.agentTypes: + for i in range (0,nAgentsPerClass): self.population.append (Agent ()) + self.agentStats [str(Agent)] = [nAgentsPerClass,0,0] + + def Iterate (self): + self.ClearStats () + self.UpdateIndexes () + self.iteration += 1 + for attacker, defender in self.Select (): + attack, bluff = attacker.Attack (defender.GetID ()) + defense = defender.Defend (attacker.GetID (), bluff) + winner = resultTable [attack] [defense] + attPoints, defPoints = pointsTable [winner][attack == bluff] + attacker.Results (defender.GetID (), True, winner, attack, defense, bluff, attPoints) + defender.Results (attacker.GetID (), False, winner, attack, defense, bluff, defPoints) + if attacker.IsDead (): self.KillAgent (attacker) + elif attacker.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (attacker) + if defender.IsDead (): self.KillAgent (defender) + elif defender.GetPoints () >= REPRODUCE_HEALTH: self.SpawnAgent (defender) + + def IsGameOver (self): + if self.population == []: return True + liveAgents = [id for id,stats in self.agentStats.iteritems () if stats[0] > 0] + print liveAgents + if len(liveAgents) < 2: return True + return False + + # This is needed because when we pick the players we also need a way of identifying them in the + # population list without manually searching each time. O(n) each iteration is better than O(n) + # each death. It also resets the check for if the agent has reproduced this round. + def UpdateIndexes (self): + for agentID in reversed(sorted(self.pendingDeaths)): del self.population [agentID] + for index, agent in enumerate(self.population): + agent.SetCurrentIndex (index) + agent.SetReproduced (False) + self.pendingDeaths = [] + + @Debug + def KillAgent (self, agent): + self.pendingDeaths.append (agent.GetCurrentIndex ()) + stat = self.agentStats [str(agent.__class__)] + stat [0] -= 1 + stat [2] += 1 + + @Debug + def SpawnAgent (self, agent): + child = agent.__class__ () + self.population.append (child) + agent.Reproduced () + stat = self.agentStats [str(agent.__class__)] + stat [0] += 1 + stat [1] += 1 + + def Select (self): + # This approach causes agents to keep fighting until they've either died or reproduced. + remaining = self.population[:] + attackerID = defenderID = random.randint (0,len(remaining)-1) + attacker = defender = remaining [attackerID] + while len (remaining) >= 2: + # Check to see if the attacker from last round needs to be dropped. + if attacker.IsDead () or attacker.HasReproduced (): + remaining.pop (attackerID) + if not len(remaining) >= 2: continue + if defenderID > attackerID: defenderID -= 1 + # Check to see if the defender from last round is up for some attacking. + if defender.IsDead () or defender.HasReproduced (): + remaining.pop (defenderID) + if not len(remaining) >= 2: continue + attackerID = random.randint (0,len(remaining)-1) + attacker = remaining [attackerID] + else: + attacker = defender + attackerID = defenderID + defender = None + defenderID = random.randint (0,len(remaining)-2) + if defenderID >= attackerID: defenderID += 1 + defender = remaining [defenderID] + + yield attacker, defender + + def GetStats (self): + return self.agentStats + + def ClearStats (self): + for agent in self.agentTypes: self.agentStats [str(agent)] = self.agentStats [str(agent)] [:1] + [0,0] + +def RandomAttack (): + return random.randint (0,2) diff --git a/src/uccProgComp.pyc b/src/uccProgComp.pyc new file mode 100644 index 0000000..77283f4 Binary files /dev/null and b/src/uccProgComp.pyc differ