Advertisement
Guest User

Untitled

a guest
Dec 21st, 2013
296
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.94 KB | None | 0 0
  1. #
  2. # horrible coding here. will refactor if I get a chance
  3. #
  4. import simpy # if we combine this with Ren'Py, do we get Ren and Simpy?
  5. import random
  6. import math
  7.  
  8. SHIFT=60.0*6.0
  9.  
  10. #
  11. # class representing the ladies providing the service
  12. #
  13. class Whore:
  14. def __init__(self, env, name, charm, skill):
  15. self.env = env
  16. self.name = name
  17. #
  18. # affect demand and satisfaction
  19. #
  20. self.charm = charm
  21. self.skill = skill
  22. #
  23. # the resouce lets customers queue to gain access
  24. #
  25. # actually I think I want a queue outside and 1:1 access inside
  26. #
  27. self.res = simpy.Resource(env, 1)
  28. #
  29. # earings and other accountancy
  30. #
  31. self.cash = 0
  32. self.hap_count = 0
  33. self.sad_count = 0
  34. self.ccount = 0
  35. self.skill_check = False
  36.  
  37. #
  38. # end of shift report for this valued employee
  39. #
  40. def report(self):
  41. fmt = "{0:12s} {1:3d} {2:3d} {3:3d} {4:3d} {5:3d} {6:5d} "
  42. print fmt.format(
  43. self.name,
  44. int(self.charm),
  45. int(self.skill),
  46. int(self.ccount),
  47. int(self.hap_count),
  48. int(self.sad_count),
  49. int(self.cash)
  50. )
  51.  
  52. #
  53. # should return true if able to service
  54. #
  55. def free(self):
  56. return self.res.count == 0
  57.  
  58. def earned(self, inc):
  59. #print self.name, ": earned ", inc
  60. self.cash += inc
  61.  
  62. def satisf(self, clev):
  63. self.ccount += 1
  64. roll = random.uniform(0, 100)
  65. diff = self.skill - roll
  66. if diff > 0: # pass
  67. self.hap_count += 1
  68. return 1
  69. if -1*diff > 25:
  70. self.sad_count += 1
  71. return -1
  72. return 0
  73.  
  74. class House:
  75. def __init__(self, env, num_whores=3, rep=0):
  76. self.servers = [ ]
  77. for i in range(num_whores):
  78. server = Whore(env,
  79. name = "server_{}".format(i),
  80. charm = random.randint(1,50),
  81. skill = random.randint(1,50)
  82. )
  83. self.servers.append(server)
  84. #
  85. # sort them by looks and skill, in that order
  86. # we can get more creative with the selection process later
  87. #
  88. self.servers = sorted( self.servers,
  89. key = lambda g: g.charm * 100 + g.skill,
  90. reverse = True
  91. )
  92. #
  93. # rep draws in the customers. rep 10 gives us a mean of 10
  94. # cusomers per shift which would normally be adjusted
  95. # for the time of day.
  96. #
  97. # actual numbers can vary a fair amount
  98. #
  99. # plan is to make rep go up and down with customer satisfaction.
  100. # so if a lot of them go away unhappy, the number of punters
  101. # will slowly decrease over time
  102. #
  103. # Actually, I'd like to base this one fame and reputation
  104. # where 100 rep gives a nice bonus to the number of customers
  105. # and -100 rep means that everyone knows your house a den of
  106. # slavers and murderers and the only visitors you'll get will be
  107. # adventurers and guardsmen.
  108. #
  109. # but for now, we keep it simple
  110. #
  111. self.rep = rep
  112. #
  113. # mean time between arrivals - we'll pass this on to
  114. # random.expovariant to get a realistic scattering of times
  115. #
  116. self.mean_tba = SHIFT
  117. if self.rep:
  118. self.mean_tba /= self.rep
  119. self.n_bored = 0
  120. self.n_custs = 0
  121. #
  122. # the door: we allow N people inside at a time
  123. # (where N == number of servers)
  124. #
  125. # if the house is full, you queue to get in the door
  126. #
  127. self.door = simpy.Resource(env, num_whores)
  128.  
  129. def ticket(self):
  130. return self.door.request()
  131.  
  132. def cancel(self, ticket):
  133. return self.door.release(ticket)
  134.  
  135. def top(self):
  136. for s in self.servers:
  137. flag = s.free()
  138. if flag:
  139. return s
  140. return None
  141.  
  142. def report(self):
  143. print ""
  144. print "Shift Report"
  145. print "{} customers in total ({} bored)".format(
  146. self.n_custs, self.n_bored
  147. )
  148. print "Whore:"
  149. tot_g = tot_h = tot_s = 0
  150. print "Name Bty Skl NCu Hap Sad Cash"
  151.  
  152. try:
  153. for s in self.servers:
  154. s.report()
  155. tot_g += s.cash
  156. tot_h += s.hap_count
  157. tot_s += s.sad_count
  158. except Exception as e:
  159. print e
  160. print "earnings: {}".format(tot_g)
  161. #
  162. # bored customers count as unhappy.
  163. # this will have the effect of bringing your house to an
  164. # equillibrium level over time - if you can't cope, rep will drop
  165. # until you can. There is not corresponding force tending to raise
  166. # rep to equilibrium point though, so you need to watch it
  167. #
  168. print "overal satisfaction: {}".format(
  169. tot_h - tot_s - self.n_bored
  170. )
  171.  
  172. env = simpy.Environment()
  173. h = House(env, rep=20)
  174.  
  175. def hhmmss(tim):
  176. mins = math.floor(tim)
  177. ss = math.floor((tim - mins) * 60)
  178. hh = mins // 60
  179. mm = mins % 60
  180. return "{0:02.0f}:{1:02.0f}:{2:02.0f}".format( hh, mm, ss)
  181.  
  182. def stamp(env, seq):
  183. return "{0:s}: {1:3d}: ".format(hhmmss(env.now), seq)
  184.  
  185. class Customer:
  186. next = 1
  187. levels = [
  188. { "chance" : 65, "level" : 0, "duration" : 10, "income" : 10 },
  189. { "chance" : 30, "level" : 1, "duration" : 30, "income" : 50 },
  190. { "chance" : 5, "level" : 2, "duration" : 60, "income" : 150 },
  191. ];
  192.  
  193. def get_lvl():
  194. l0 = levels[0]["chance"]
  195. l1 = levels[1]["chance"]
  196.  
  197. r = random.random()
  198. if r < l0:
  199. return levels[0]
  200. if r < l0 + l1:
  201. return levels[1]
  202. return levels[2]
  203.  
  204. def __init__(self, env):
  205. self.env = env
  206. lvl = random.choice(self.levels)
  207. self.__dict__.update(lvl)
  208. self.seq = Customer.next
  209. Customer.next += 1
  210. self.name = "Customer S{}L{}".format(
  211. self.seq, self.level
  212. )
  213. self.process = env.process(self.go())
  214. self.paitence = env.timeout(random.uniform(20,100))
  215.  
  216. def message(self, s):
  217. print "{}: {}: {}".format(
  218. hhmmss(self.env.now), self.name, s
  219. )
  220.  
  221. def go(self):
  222. self.message("Arrival")
  223. self.arrive = env.now
  224.  
  225. #
  226. # do the actual queue-to-get-through-the-door bit
  227. #
  228. ticket = h.ticket()
  229. result = yield ticket | self.paitence
  230.  
  231. #
  232. # HOW long?
  233. #
  234. self.wait_time = env.now - self.arrive
  235.  
  236. #
  237. # did the wait paitently, or did he give up
  238. # and go home
  239. #
  240. made_it = (ticket in result)
  241. if not made_it:
  242. self.message("Got bored, went home")
  243. h.n_bored += 1
  244. h.cancel(ticket)
  245. return
  246.  
  247. h.n_custs += 1
  248. self.env.process(self.do_inside(ticket))
  249.  
  250.  
  251. def do_inside(self, ticket):
  252. self.message("Entered the House")
  253. #
  254. # otherwise, pick a "server"
  255. #
  256. # if the door capacity == number of servers
  257. # there should always be one free
  258. #
  259. w = h.top()
  260. if w == None:
  261. h.cancel(ticket)
  262. raise Exception("No free servers!")
  263.  
  264. with w.res.request() as ww:
  265.  
  266. #
  267. # a bit of narrative
  268. #
  269. self.message("service from {}".format(w.name))
  270. if self.wait_time > 0.01:
  271. self.message("waited: {}".format(
  272. hhmmss(self.wait_time)
  273. ))
  274.  
  275. #
  276. # let some time pass for the customer to
  277. # conclude his business
  278. #
  279. yield env.timeout(
  280. random.expovariate(1.0/self.duration)
  281. )
  282. #
  283. # was it good for you?
  284. #
  285. (fee, tip) = self.calc_satisfaction(w)
  286. w.earned(fee + tip)
  287. self.message("Done")
  288. h.cancel(ticket)
  289.  
  290. def calc_satisfaction(self, whore):
  291. tip = 0
  292. #
  293. # 10% of the income is expected tip
  294. # so the fee for the sex is 90%
  295. #
  296. # round down - we want unhappy customers to pay less,
  297. # not to get lost in the rounding error
  298. #
  299. fee = math.floor(self.income * 0.9)
  300. #
  301. # see if the girl satisfied her client
  302. #
  303. satisfaction = whore.satisf(self.level)
  304. #
  305. # negative means uphappy - no tip and house rep suffers
  306. #
  307. if satisfaction < 0:
  308. chatter = "Customer Unhappy: Fee = {}, no tip".format(
  309. fee
  310. )
  311. self.message(chatter)
  312. return (fee, 0)
  313.  
  314. #
  315. # satisfaction 0 means acceptable. 10% tip brings income
  316. # up to expected levels
  317. #
  318. if satisfaction == 0:
  319. factor = 0.1
  320. #
  321. # otherwise we have a happy chappie. tips between 15 and 30%
  322. #
  323. else:
  324. factor = random.uniform(0.15, 0.3)
  325. #
  326. # work out the tip - round up this time
  327. #
  328. tip = math.ceil(self.income * factor)
  329.  
  330. #
  331. # a bit of narrative for the user
  332. #
  333. fee_str = "Fee = {}, Tip = {}".format(int(fee), int(tip))
  334. if satisfaction == 0:
  335. self.message("Customer Satisfied: " + fee_str)
  336. else:
  337. self.message("Customer Happy: " + fee_str)
  338. #
  339. # return the numbers
  340. #
  341. return (fee, tip)
  342.  
  343.  
  344. def source(env):
  345. seq = 0
  346. while True:
  347. t = random.expovariate(1/h.mean_tba)
  348. yield env.timeout(t)
  349. #seq += 1
  350. #if seq > 4: break
  351. c = Customer(env)
  352.  
  353.  
  354.  
  355. env.process(source(env))
  356. env.run(until = SHIFT)
  357.  
  358. h.report()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement