Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #
- # horrible coding here. will refactor if I get a chance
- #
- import simpy # if we combine this with Ren'Py, do we get Ren and Simpy?
- import random
- import math
- SHIFT=60.0*6.0
- #
- # class representing the ladies providing the service
- #
- class Whore:
- def __init__(self, env, name, charm, skill):
- self.env = env
- self.name = name
- #
- # affect demand and satisfaction
- #
- self.charm = charm
- self.skill = skill
- #
- # the resouce lets customers queue to gain access
- #
- # actually I think I want a queue outside and 1:1 access inside
- #
- self.res = simpy.Resource(env, 1)
- #
- # earings and other accountancy
- #
- self.cash = 0
- self.hap_count = 0
- self.sad_count = 0
- self.ccount = 0
- self.skill_check = False
- #
- # end of shift report for this valued employee
- #
- def report(self):
- fmt = "{0:12s} {1:3d} {2:3d} {3:3d} {4:3d} {5:3d} {6:5d} "
- print fmt.format(
- self.name,
- int(self.charm),
- int(self.skill),
- int(self.ccount),
- int(self.hap_count),
- int(self.sad_count),
- int(self.cash)
- )
- #
- # should return true if able to service
- #
- def free(self):
- return self.res.count == 0
- def earned(self, inc):
- #print self.name, ": earned ", inc
- self.cash += inc
- def satisf(self, clev):
- self.ccount += 1
- roll = random.uniform(0, 100)
- diff = self.skill - roll
- if diff > 0: # pass
- self.hap_count += 1
- return 1
- if -1*diff > 25:
- self.sad_count += 1
- return -1
- return 0
- class House:
- def __init__(self, env, num_whores=3, rep=0):
- self.servers = [ ]
- for i in range(num_whores):
- server = Whore(env,
- name = "server_{}".format(i),
- charm = random.randint(1,50),
- skill = random.randint(1,50)
- )
- self.servers.append(server)
- #
- # sort them by looks and skill, in that order
- # we can get more creative with the selection process later
- #
- self.servers = sorted( self.servers,
- key = lambda g: g.charm * 100 + g.skill,
- reverse = True
- )
- #
- # rep draws in the customers. rep 10 gives us a mean of 10
- # cusomers per shift which would normally be adjusted
- # for the time of day.
- #
- # actual numbers can vary a fair amount
- #
- # plan is to make rep go up and down with customer satisfaction.
- # so if a lot of them go away unhappy, the number of punters
- # will slowly decrease over time
- #
- # Actually, I'd like to base this one fame and reputation
- # where 100 rep gives a nice bonus to the number of customers
- # and -100 rep means that everyone knows your house a den of
- # slavers and murderers and the only visitors you'll get will be
- # adventurers and guardsmen.
- #
- # but for now, we keep it simple
- #
- self.rep = rep
- #
- # mean time between arrivals - we'll pass this on to
- # random.expovariant to get a realistic scattering of times
- #
- self.mean_tba = SHIFT
- if self.rep:
- self.mean_tba /= self.rep
- self.n_bored = 0
- self.n_custs = 0
- #
- # the door: we allow N people inside at a time
- # (where N == number of servers)
- #
- # if the house is full, you queue to get in the door
- #
- self.door = simpy.Resource(env, num_whores)
- def ticket(self):
- return self.door.request()
- def cancel(self, ticket):
- return self.door.release(ticket)
- def top(self):
- for s in self.servers:
- flag = s.free()
- if flag:
- return s
- return None
- def report(self):
- print ""
- print "Shift Report"
- print "{} customers in total ({} bored)".format(
- self.n_custs, self.n_bored
- )
- print "Whore:"
- tot_g = tot_h = tot_s = 0
- print "Name Bty Skl NCu Hap Sad Cash"
- try:
- for s in self.servers:
- s.report()
- tot_g += s.cash
- tot_h += s.hap_count
- tot_s += s.sad_count
- except Exception as e:
- print e
- print "earnings: {}".format(tot_g)
- #
- # bored customers count as unhappy.
- # this will have the effect of bringing your house to an
- # equillibrium level over time - if you can't cope, rep will drop
- # until you can. There is not corresponding force tending to raise
- # rep to equilibrium point though, so you need to watch it
- #
- print "overal satisfaction: {}".format(
- tot_h - tot_s - self.n_bored
- )
- env = simpy.Environment()
- h = House(env, rep=20)
- def hhmmss(tim):
- mins = math.floor(tim)
- ss = math.floor((tim - mins) * 60)
- hh = mins // 60
- mm = mins % 60
- return "{0:02.0f}:{1:02.0f}:{2:02.0f}".format( hh, mm, ss)
- def stamp(env, seq):
- return "{0:s}: {1:3d}: ".format(hhmmss(env.now), seq)
- class Customer:
- next = 1
- levels = [
- { "chance" : 65, "level" : 0, "duration" : 10, "income" : 10 },
- { "chance" : 30, "level" : 1, "duration" : 30, "income" : 50 },
- { "chance" : 5, "level" : 2, "duration" : 60, "income" : 150 },
- ];
- def get_lvl():
- l0 = levels[0]["chance"]
- l1 = levels[1]["chance"]
- r = random.random()
- if r < l0:
- return levels[0]
- if r < l0 + l1:
- return levels[1]
- return levels[2]
- def __init__(self, env):
- self.env = env
- lvl = random.choice(self.levels)
- self.__dict__.update(lvl)
- self.seq = Customer.next
- Customer.next += 1
- self.name = "Customer S{}L{}".format(
- self.seq, self.level
- )
- self.process = env.process(self.go())
- self.paitence = env.timeout(random.uniform(20,100))
- def message(self, s):
- print "{}: {}: {}".format(
- hhmmss(self.env.now), self.name, s
- )
- def go(self):
- self.message("Arrival")
- self.arrive = env.now
- #
- # do the actual queue-to-get-through-the-door bit
- #
- ticket = h.ticket()
- result = yield ticket | self.paitence
- #
- # HOW long?
- #
- self.wait_time = env.now - self.arrive
- #
- # did the wait paitently, or did he give up
- # and go home
- #
- made_it = (ticket in result)
- if not made_it:
- self.message("Got bored, went home")
- h.n_bored += 1
- h.cancel(ticket)
- return
- h.n_custs += 1
- self.env.process(self.do_inside(ticket))
- def do_inside(self, ticket):
- self.message("Entered the House")
- #
- # otherwise, pick a "server"
- #
- # if the door capacity == number of servers
- # there should always be one free
- #
- w = h.top()
- if w == None:
- h.cancel(ticket)
- raise Exception("No free servers!")
- with w.res.request() as ww:
- #
- # a bit of narrative
- #
- self.message("service from {}".format(w.name))
- if self.wait_time > 0.01:
- self.message("waited: {}".format(
- hhmmss(self.wait_time)
- ))
- #
- # let some time pass for the customer to
- # conclude his business
- #
- yield env.timeout(
- random.expovariate(1.0/self.duration)
- )
- #
- # was it good for you?
- #
- (fee, tip) = self.calc_satisfaction(w)
- w.earned(fee + tip)
- self.message("Done")
- h.cancel(ticket)
- def calc_satisfaction(self, whore):
- tip = 0
- #
- # 10% of the income is expected tip
- # so the fee for the sex is 90%
- #
- # round down - we want unhappy customers to pay less,
- # not to get lost in the rounding error
- #
- fee = math.floor(self.income * 0.9)
- #
- # see if the girl satisfied her client
- #
- satisfaction = whore.satisf(self.level)
- #
- # negative means uphappy - no tip and house rep suffers
- #
- if satisfaction < 0:
- chatter = "Customer Unhappy: Fee = {}, no tip".format(
- fee
- )
- self.message(chatter)
- return (fee, 0)
- #
- # satisfaction 0 means acceptable. 10% tip brings income
- # up to expected levels
- #
- if satisfaction == 0:
- factor = 0.1
- #
- # otherwise we have a happy chappie. tips between 15 and 30%
- #
- else:
- factor = random.uniform(0.15, 0.3)
- #
- # work out the tip - round up this time
- #
- tip = math.ceil(self.income * factor)
- #
- # a bit of narrative for the user
- #
- fee_str = "Fee = {}, Tip = {}".format(int(fee), int(tip))
- if satisfaction == 0:
- self.message("Customer Satisfied: " + fee_str)
- else:
- self.message("Customer Happy: " + fee_str)
- #
- # return the numbers
- #
- return (fee, tip)
- def source(env):
- seq = 0
- while True:
- t = random.expovariate(1/h.mean_tba)
- yield env.timeout(t)
- #seq += 1
- #if seq > 4: break
- c = Customer(env)
- env.process(source(env))
- env.run(until = SHIFT)
- h.report()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement