Guest User

Untitled

a guest
Jun 20th, 2019
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.90 KB | None | 0 0
  1. import random
  2. import time
  3.  
  4.  
  5. class Unit:
  6.     def __init__(self, name, e_cost, e_prod, bt, bp):
  7.         self.name = name
  8.         self.e_cost = e_cost
  9.         self.e_prod = e_prod
  10.         self.bt = bt
  11.         self.bp = bp
  12.  
  13.     def bp_per_e(self):
  14.         return self.bp / self.e_cost
  15.  
  16.     def e_per_e(self):
  17.         return self.e_prod / self.e_cost
  18.  
  19.     def bp_per_bt(self):
  20.         return self.bp / self.bt
  21.  
  22.     def e_per_bt(self):
  23.         return self.e_prod / self.bt
  24.  
  25.     def is_fac(self):
  26.         return 'f' in self.name
  27.  
  28.     def is_engy(self):
  29.         return 'e' in self.name
  30.  
  31.  
  32. acu_t1 = Unit('a1', 5000000, 20, 6000000, 10)
  33. acu_t2 = Unit('a2', 21000, 0, 1000, 42-acu_t1.bp)                     # consumes an acu_t1
  34. acu_t3 = Unit('a3', 50000, 0, 8400, 100-acu_t2.bp-acu_t1.bp)          # consumes an acu_t2
  35.  
  36. fac_navy_t1 = Unit('f1', 1500, 0, 300, 20)
  37. fac_navy_t2_hq = Unit('f2h', 10000, 0, 3600, 90-fac_navy_t1.bp)        # consumes a fac_navy_t1
  38. fac_navy_t3_hq = Unit('f3h', 45000, 0, 11250, 150-fac_navy_t2_hq.bp)   # consumes a fac_navy_t2_hq
  39. fac_navy_t2_sl = Unit('f2s', 5500, 0, 3300, 90)
  40. fac_navy_t3_sl = Unit('f3s', 11000, 0, 3500, 150)
  41.  
  42. engy_t1 = Unit('e1', 260, 0, 260, 5)
  43. engy_t2 = Unit('e2', 650, 0, 650, 12.5)
  44. engy_t3 = Unit('e3', 1560, 0, 1560, 30)
  45.  
  46. pgn_t1 = Unit('p1', 750, 20, 125, 0)
  47. pgn_t2 = Unit('p2', 12000, 500, 2198, 0)
  48. pgn_t3 = Unit('p3', 57600, 2500, 6824, 0)
  49.  
  50. all_acus = [acu_t1, acu_t2, acu_t3]
  51. all_facs = [fac_navy_t1, fac_navy_t2_hq, fac_navy_t3_hq, fac_navy_t2_sl, fac_navy_t3_sl]
  52. all_engy = [engy_t1, engy_t2, engy_t3]
  53. all_pgn = [pgn_t1, pgn_t2, pgn_t3]
  54. all_units = all_acus + all_facs + all_engy + all_pgn
  55.  
  56. name_to_unit = dict([(u.name, u) for u in all_units])
  57.  
  58. """
  59. for u in all_pgn:
  60.    print('%5s \t e/e: %.4f \t e/bt %.4f' % (u.name, u.e_per_e(), u.e_per_bt()))
  61.  
  62. for u in all_acus+all_engy+all_facs:
  63.    print('%5s \t bp/e: %.4f \t bp/bt %.4f' % (u.name, u.bp_per_e(), u.bp_per_bt()))
  64.  
  65. for k, v in name_to_unit.items():
  66.    print(k, v.name)
  67.  
  68. notes:
  69. t1 fac wins in bp/bt over everything else, can only build t1 engies though
  70. all engies are equal in bp/e, better than anything else, slave facs can therefore be ignored
  71. upgrading acu to t3 is better in terms of bp/bt, fac in terms of bp/e
  72. higher tech pgns are more efficient in both e/e and e/bt -> no going back in tech
  73. """
  74.  
  75.  
  76. class Run:
  77.     def __init__(self, transition_with_acu=True, e_stop=30000):
  78.         self.units = [acu_t1, fac_navy_t1]
  79.         self.e_prod = sum([u.e_prod for u in self.units])
  80.         self.fac_bp = sum([u.bp for u in self.units if u.is_fac()])
  81.         self.engy_bp = sum([u.bp for u in self.units if not u.is_fac()])
  82.         self.t = fac_navy_t1.bt / acu_t1.bp
  83.         self.e = 4000 - fac_navy_t1.e_cost + self.t * acu_t1.e_prod
  84.  
  85.         self.t2_trans = [acu_t2] if transition_with_acu else [fac_navy_t2_hq, engy_t2]
  86.         self.t3_trans = [acu_t3] if transition_with_acu else [fac_navy_t3_hq, engy_t3]
  87.         self.queues = [[], [], []]
  88.  
  89.         self.t1_options = [fac_navy_t1, engy_t1, pgn_t1]
  90.         self.t2_options = [fac_navy_t1, engy_t1, pgn_t2]
  91.         self.t3_options = [fac_navy_t1, engy_t1, pgn_t3]
  92.         self.options = [self.t1_options, self.t2_options, self.t3_options]
  93.  
  94.         self.e_stop = e_stop
  95.         self.transition_with_acu = transition_with_acu
  96.  
  97.     def mutated_copy(self, max_mutations=3):
  98.         run = Run(transition_with_acu=self.transition_with_acu, e_stop=self.e_stop)
  99.         run.init_from(*self.get_queues())
  100.         for __ in range(random.randint(1, max_mutations)):
  101.             run.mutate()
  102.         return run
  103.  
  104.     def mutate(self):
  105.         """ random insertion or deletion of a queue element """
  106.         while True:
  107.             r_q = random.randint(0, len(self.queues)-1)
  108.             q = self.queues[r_q]
  109.             r_i = random.randint(0, len(q))
  110.             r_o = random.randint(0, len(self.options[r_q]))
  111.             # insert when rolling one of the available options
  112.             if r_o < len(self.options[r_q]):
  113.                 self.queues[r_q].insert(r_i, self.options[r_q][r_o])
  114.                 return
  115.             # remove something, if possible
  116.             elif r_i < len(q):
  117.                 self.queues[r_q].pop(r_i)
  118.                 return
  119.  
  120.     def init_from(self, t1q, t2t, t2q, t3t, t3q):
  121.         """ each is a list of strings """
  122.         self.queues = [[], [], []]
  123.         self.queues[0] = [name_to_unit.get(s) for s in t1q]
  124.         self.t2_trans = [name_to_unit.get(s) for s in t2t]
  125.         self.queues[1] = [name_to_unit.get(s) for s in t2q]
  126.         self.t3_trans = [name_to_unit.get(s) for s in t3t]
  127.         self.queues[2] = [name_to_unit.get(s) for s in t3q]
  128.  
  129.     def print_stats(self):
  130.         print('t: %.2f \t e_prod: %d \t e_storage: %.1f \t f_bp: %d \t e_bp: %d'
  131.               % (self.t, self.e_prod, self.e, self.fac_bp, self.engy_bp))
  132.  
  133.     def get_queues(self):
  134.         return [u.name for u in self.queues[0]],\
  135.                [u.name for u in self.t2_trans],\
  136.                [u.name for u in self.queues[1]],\
  137.                [u.name for u in self.t3_trans],\
  138.                [u.name for u in self.queues[2]]
  139.  
  140.     def print_queue(self):
  141.         print(', '.join(str(q) for q in self.get_queues()))
  142.  
  143.     def evaluate(self, verbose=False):
  144.         def steps(units: [Unit]):
  145.             for u in units:
  146.                 # figure out time/e to build the unit
  147.                 bp = (self.fac_bp + self.engy_bp) if u.is_engy() else self.engy_bp  # which bp for current unit
  148.                 td_b = u.bt / bp                                                    # time by bp alone
  149.                 e_later = self.e + td_b * self.e_prod                               # energy in storage by then
  150.                 td_e = (u.e_cost - e_later) / self.e_prod                           # remaining time for e
  151.                 td = td_b + max(0, td_e)                                            # total required time to build
  152.  
  153.                 # update values
  154.                 self.e = self.e + self.e_prod * td - u.e_cost   # e storage
  155.                 self.e_prod += u.e_prod                         # e production
  156.                 self.fac_bp += u.bp if u.is_fac() else 0        # fac bp
  157.                 self.engy_bp += u.bp if not u.is_fac() else 0   # engy bp
  158.                 self.t += td                                    # passed time
  159.  
  160.                 if self.e_prod >= self.e_stop:
  161.                     return True
  162.             return False
  163.  
  164.         for unit_groups in [self.queues[0], self.t2_trans, self.queues[1], self.t3_trans, self.queues[2]]:
  165.             done = steps(unit_groups)
  166.             if verbose:
  167.                 self.print_stats()
  168.             if done:
  169.                 return
  170.         while not steps([pgn_t3]):
  171.             pass
  172.  
  173.  
  174. class Climber:
  175.     def __init__(self, init_run: Run, pool_size=10, max_mutations=5):
  176.         init_run.evaluate()
  177.         self.all = [init_run]
  178.         self.pool_size = pool_size
  179.         self.max_mutations = max_mutations
  180.         self.score = init_run.t
  181.  
  182.     def step(self):
  183.         # insert runs and evaluate
  184.         for _ in range(self.pool_size-1):
  185.             run = self.all[0].mutated_copy(max_mutations=self.max_mutations)
  186.             run.evaluate(verbose=False)
  187.             self.all.append(run)
  188.         # keep only the best alive
  189.         self.all = sorted(self.all, key=lambda u: u.t)
  190.  
  191.         # for a in self.all:
  192.         #     print(a.t)
  193.  
  194.         self.all = self.all[0:1]
  195.         s = self.all[0].t
  196.         if s < self.score:
  197.             print('-'*50)
  198.             self.all[0].print_stats()
  199.             self.all[0].print_queue()
  200.             self.score = s
  201.  
  202.  
  203. t0 = time.time()
  204. r = Run(transition_with_acu=False)
  205. # r.init_from(['e1', 'p1', 'p1'], ['a2'], [], ['a3'], [])
  206. r.print_queue()
  207.  
  208. print('-'*100)
  209. print('starting search')
  210. print('-'*100)
  211.  
  212. climber = Climber(r, pool_size=5)
  213. for i in range(10000):
  214.     climber.step()
  215.  
  216. print('\n')
  217. print('search time: %.2f' % (time.time() - t0))
Advertisement
Add Comment
Please, Sign In to add comment