#!/usr/bin/python

# total agents
NUMAGENTS = 60
# open agents
NUMOPEN = 10
# fraction of features shared
SHARING = 0.05

import random, time

class Agent:
    """A software firm."""

    def __init__(self, id):
        self.id = id
        self.bankrupt = 0        
        self.init()

    def init(self, share=0.0):
        #self.size = random.choice(xrange(1,10))
        self.size = 1
        self.maxsize = self.size
        self.feat = 1
        self.share = share
        
    def add_size(self, profit):
        self.size += profit
        self.maxsize = max(self.maxsize, self.size)

    def add_feat(self, tech):
        self.feat += tech

    def audit(self):
        if self.size <= 0.0 or self.feat <= 0.0:
            self.bankrupt += 1            
            self.init()



    def __repr__(self):
        ret = "Agent_%02i | size: % 7.2f | feat: %9.2f | [%02d] <%0.3f> " % (
            self.id, self.size, self.feat, self.bankrupt, self.share)
        if self.share <= 0.0001:
            char = 'x'
        else:
            char = 'o'
        ret = ret + char * int(self.size)
        ret = ret + '.' * int(self.maxsize - self.size) + '>'
        return ret

class World:
    """A software market."""

    def __init__(self, numagents=100, numshare=10, propshare=0.0):
        self.i = 0
        self.numagents = numagents
        self.numshare = numshare
        self.propshare = float(propshare)
        self.agents = [Agent(i) for i in xrange(numagents)]
        for x in self.agents[:numshare]:
            x.share = propshare

    def show(self):
        print "World(%s) %s agents, %s open @ %0.1f%%" % (self.i, self.numagents, self.numshare, self.propshare*100)
        for x in self.agents:
            print " %s" % x
        print

    def turn(self, iterations=1):
        """Change the world:
        - distribute innovation proportionally to agent <size>
          (but randomly perturbed)
        - distribute sales proportionally to agent <feat>
        """
        for i in xrange(iterations):
            self._turn(iterations)
            
    def _turn(self, iterations):
        self.i += 1
        totalfeat = 0.0
        totalshare = 0.0
        totalsize = 0.0
        maxsize = 0
        for x in self.agents:
            depreciation = -0.3 * x.feat
            x.add_feat(depreciation)            
            innovation = random.random() * x.size
            x.add_feat(innovation)
            totalshare += (x.share * innovation)
            totalfeat += x.feat
            totalsize += x.size
            maxsize = max(maxsize, x.size)
        budget = float(self.numagents)            
        salesperfeat = budget / totalfeat
        costspersize = budget / totalsize
        for x in self.agents:
            sales = x.feat * salesperfeat
            costs = x.size * costspersize
            x.add_size(sales - costs)
            # share innovation
            x.add_feat(x.share * (totalshare))
            x.audit()
        
    
        
        
if __name__ == '__main__':
    while True:
        w = World(NUMAGENTS, NUMOPEN, SHARING)
        w.show()
        time.sleep(5)
        for i in xrange(100):
            w.turn(10)
            w.show()
            time.sleep(0.2)
        time.sleep(3)
            
