c_wash.c 5.09 KB
Newer Older
1
/*
Daniel Axtens's avatar
Daniel Axtens committed
2
 *  c_wash.c
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *  c-link-lib
 *
 *  Created by Daniel Axtens on 22/04/10.
 *  Licensed under an MIT-style license: see the LICENSE file for details.
 *
 */

#include <c_link.h>
#include <stdlib.h>
#include <string.h>

/* Implement the wash agent, that is by default nice but will 
   permanently turn against any agent that betrays it.
   This is trickier in C than in any other language, for a number of reasons:
     - there's no classes in C, so we can't just write a generic learning agent
       and subclass it.
     - your agent has no idea how many agents it's going to battle, or how many
       battles it is going to fight, so you've got to do dynamic memory allocation.
        (anyone who tries to read the source of the supervisor to find out is liable
         to have their program break unexpectedly)
 */

/* To simplify things, we just look at whether we have lost to a particular agent.
   Unlike in the Python version, we don't keep a generic list
   This is also done in a inefficient (O(bot-cout)) way.
   Implementing a faster version is left as an exercise to the DSA student. */

/* Our guess at the number of agents I'm going to fight in my lifetime
   (note that this is only a guess, not an upper limit. Do *not* take it as 
   gospel on the number of agents you're going to see. */
#define NUMBEROFAGENTSGUESS 100

Daniel Axtens's avatar
Daniel Axtens committed
35 36
typedef char agentName[MAXAGENTNAMELEN];

37 38 39
/* data for each instance of my agent */
typedef struct {
	/* The name of the n-th foe who has beaten us */
Daniel Axtens's avatar
Daniel Axtens committed
40
	agentName * defeatingFoes;
41 42 43 44 45 46 47 48 49 50 51 52 53 54

	/* The length of the array, and how far we are along it */
	size_t foesLen;
	unsigned int foesCount;
} wash_data;


/* an internal function - have I lost to a given foe? */
int haveLostTo( wash_data * me, char * foeName ) {
    
	int foe;
    
    /* check every foe we know to have defeated us */
    for (foe=0; foe<me->foesCount; foe++) {
55
        if (strncmp( me->defeatingFoes[foe], foeName, MAXAGENTNAMELEN) == 0) {
56 57 58 59 60 61 62 63 64 65 66 67 68
            //debugmsg( "%d\thaveLostTo( %s ) -> Yes\n", me, foeName );
            return 1;
        }
    }
    
    /* this foe not found */
    return 0;
}

/* set up myself */
void * Initialise( char * myName ) {
	wash_data * me = malloc( sizeof( wash_data ) );
	
Daniel Axtens's avatar
Daniel Axtens committed
69
	me->defeatingFoes = calloc( NUMBEROFAGENTSGUESS, sizeof( agentName ) );
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	me->foesLen = NUMBEROFAGENTSGUESS;
    me->foesCount = 0;
	
	return (void *) me;
}

/* Attack */
ATTACKTYPE Attack( void * this, char * foeName ) {
	wash_data * me = (wash_data *)this;
    
	ATTACKTYPE attack;
	
	attack.realAttack =  RandomAttack();
	
    /* have I lost to this foe? */
    if ( haveLostTo(me, foeName) ) {
        /* Assume they are lying  */
        switch (attack.realAttack) {
            case rock:
                attack.promisedAttack = scissors;
                break;
            case paper:
                attack.promisedAttack = rock;
                break;
            default: /* attack = scissors */
                attack.promisedAttack = paper;
                break;
        }
    } else {
        /* be nice! */
        attack.promisedAttack = attack.realAttack;
    }

	
	return attack;
}

/* defend */
ITEMTYPE Defend( void * this, char * foeName, ITEMTYPE foePromisedAttack ) {
	wash_data * me = (wash_data *)this;
	
	ITEMTYPE defence;
	
    if (haveLostTo(me, foeName)) {
        /* They've screwed us in the past, assume they're lying and go for the
           kill. */
        switch (foePromisedAttack) {
            case rock:
                defence = scissors;
                break;
            case paper:
                defence = rock;
                break;
            default:
                defence = paper;
                break;
        }
    } else {
        /* be nice! */
        defence = foePromisedAttack;
    }

    return defence;
}

/* This is so much less fun in C */
void Results( void * this, char * foeName, int isInstigatedByYou, 
			 RESULTTYPE winner, ITEMTYPE attItem, ITEMTYPE defItem, 
			 ITEMTYPE bluffItem, int pointDelta ) {
	
    wash_data * me = (wash_data *)this;
	
	int foe;
    
    /* figure out if we lost, which is the only thing we care about
       if we didn't, move on. */
    if ((winner == tie) || 
        (winner==attacker && isInstigatedByYou) ||
        (winner==defender && !isInstigatedByYou) ) return;
    
    //fprintf( stderr, "%d\tsaving loss from %s\n", me, foeName );
    
    /* if we've already lost the foe, don't store again */
    for (foe=0; foe<me->foesCount; foe++) {
154
        if (strncmp( me->defeatingFoes[foe], foeName, MAXAGENTNAMELEN ) == 0) {
155 156 157 158 159 160 161 162 163
            /* we've found it! */
            return;
        }
    }
    
    /* we haven't found the foe. add it, expanding the array if needed */
    if (me->foesCount==me->foesLen) {
        /* double the array size. This should error check, but doesn't */
        me->defeatingFoes = realloc( me->defeatingFoes, 
Daniel Axtens's avatar
Daniel Axtens committed
164
		                             me->foesLen*2*sizeof( agentName ) );
165 166 167
        me->foesLen *= 2;
    }
    
168
    strncpy( me->defeatingFoes[me->foesCount], foeName, MAXAGENTNAMELEN );
169 170 171 172 173 174 175 176 177 178
    me->foesCount++;
    
    return;
}

/* Cleanup */
void Cleanup( void * this ) {
	wash_data * me = (wash_data *) this;
	free(me->defeatingFoes);
	free(me);
Daniel Axtens's avatar
Daniel Axtens committed
179
}