Skip to content

Instantly share code, notes, and snippets.

@Muon
Created October 11, 2012 22:18
Show Gist options
  • Save Muon/3875892 to your computer and use it in GitHub Desktop.
Save Muon/3875892 to your computer and use it in GitHub Desktop.
Achron economy model
"""A high-level simulation of Achron's economy."""
from __future__ import division
# Simulation time parameters
ticks_per_second = 18
simulation_length = 5 * 60
t = simulation_length * ticks_per_second
# RP constants
# EXPb
rp_cost = 100
lc_per_load = 10
ticks_per_load = 178
morph_time = 9 * ticks_per_second # EXPb v1.2.0
# morph_time = 4 * ticks_per_second # EXPb v1.1.0
# Achron v1.2.0.1
# rp_cost = 50
# lc_per_load = 8
# ticks_per_load = 284
# morph_time = 3 * ticks_per_second
# Map-dependent constants
distance_to_crates = 5 # Fudge factor for moving to starting resource patch
# Common constants
start_lc = 300
deploy_time = 24 # Time needed for RP to start collecting after being built
rp_width = 3 # Width of an RP, needed for biped start time fudge factor
# Biped constants
biped_move_rate = 10 # ticks/cell
biped_build_time = 20 * ticks_per_second # Time needed for biped RP to be built
# Grekim constants
octo_cost = 45
pharo_cost = 95
pharo_birth_time = 162
octo_birth_time = 288 # ticks
octo_move_rate = 6 # ticks/cell
grekim_rp_horiz_move_rate = 14 # ticks/cell
grekim_rp_vert_move_rate = 4 # ticks/height level
grekim_initial_rp_travel_time = 12 * ticks_per_second - deploy_time # distance_to_crates * grekim_rp_horiz_move_rate + grekim_rp_vert_move_rate * 2
# Fudge factors for Octo movement from duo to crate
octo_move_time = octo_move_rate * distance_to_crates
# octo_move_time = 0 # Walking duo, so travel time is negligible
initial_progen_energy = 20
progen_regeneration = 108 # ticks/unit regenerated
octo_progen_cost = 3 # Progen energy consumed to birth an octo
progen_toggle_time = 90 # ticks; time needed to enter progen mode
morph_cost = rp_cost - octo_cost
grekim_build_time = morph_time + deploy_time + octo_move_time
def compute_new_lc(t, lc, rps, build_time):
"""Computes new LC value. Species-agnostic."""
for time_built_at in rps:
time_since_build_issued = t - time_built_at
if build_time > time_since_build_issued:
continue
time_active = time_since_build_issued - build_time
if time_active > 0 and (time_active % ticks_per_load) == 0:
lc += lc_per_load
return lc
def count_active_rps(t, rps, build_time):
"""Counts active RPs. Species-agnostic."""
active_rps = 0
for time_built_at in rps:
time_since_build_issued = t - time_built_at
if build_time > time_since_build_issued:
continue
time_active = time_since_build_issued - build_time
if time_active > 0:
active_rps += 1
return active_rps
def biped():
lc = start_lc
first_rp = distance_to_crates * biped_move_rate
rps = [first_rp, first_rp + biped_move_rate * rp_width, first_rp + biped_move_rate * rp_width * 2] # times at which RPs were built
for i in range(0, rps[0]):
yield [0, lc]
lc -= rp_cost
for i in range(rps[0], rps[1]):
yield [0, lc]
lc -= rp_cost
for i in range(rps[1], rps[2]):
yield [0, lc]
lc -= rp_cost
start_time = rps[2]
for i in range(start_time, t):
assert lc >= 0
lc = compute_new_lc(i, lc, rps, biped_build_time + deploy_time)
if lc >= rp_cost:
rps.append(i)
lc -= rp_cost
yield [count_active_rps(i, rps, biped_build_time), lc]
def _grekim_mature_octos(t, octo_buildstart):
new_octos = 0
new_buildstart = []
for octo in octo_buildstart:
if t - octo >= octo_birth_time:
new_octos += 1
else:
new_buildstart.append(octo)
octo_buildstart[:] = new_buildstart
return new_octos
def _grekim_morph_octos(t, lc, octos, rps):
while octos > 0 and lc >= morph_cost:
rps.append(t)
octos -= 1
lc -= morph_cost
return lc, octos
def _grekim_predict_future(start, duration, lc, octos, rps, octo_buildstart):
rps = rps[:]
octo_buildstart = octo_buildstart[:]
for i in range(start, start + duration + 1):
lc = compute_new_lc(i, lc, rps, grekim_build_time)
lc, octos = _grekim_morph_octos(i, lc, octos, rps)
octos += _grekim_mature_octos(i, octo_buildstart)
return lc, octos
def grekim():
lc = start_lc - pharo_cost
octo_buildstart = [] # times at which octos were built
octos = 0
progen_energy = initial_progen_energy
rps = [grekim_initial_rp_travel_time - grekim_build_time] # times at which RPs were built
for i in range(0, grekim_initial_rp_travel_time + deploy_time):
yield [0, lc]
start_time = pharo_birth_time + progen_toggle_time
for i in range(grekim_initial_rp_travel_time + deploy_time, start_time):
yield [1, lc]
for i in range(start_time, t):
if (i % progen_regeneration) == 0:
progen_energy = min(initial_progen_energy, progen_energy + 1)
assert 0 <= progen_energy <= initial_progen_energy
assert lc >= 0
lc = compute_new_lc(i, lc, rps, grekim_build_time)
lc, octos = _grekim_morph_octos(i, lc, octos, rps)
while lc >= octo_cost and progen_energy >= octo_progen_cost:
future_lc, future_octos = _grekim_predict_future(
i, octo_birth_time, lc - octo_cost, octos, rps, octo_buildstart)
if future_lc >= morph_cost * (future_octos + 1):
octo_buildstart.append(i)
progen_energy -= octo_progen_cost
lc -= octo_cost
else:
break
octos += _grekim_mature_octos(i, octo_buildstart)
yield [count_active_rps(i, rps, grekim_build_time), lc]
from matplotlib import dates
import matplotlib.pyplot as plt
from datetime import datetime
def prettify_rp_data(data_iterable):
"""Takes model iterable and returns distinct RP counts with times.
Returns two lists (times, rp_counts).
"""
rp_counts = []
times = []
prev_rp_count = None
for i, (rp_count, lc) in enumerate(data_iterable):
if rp_count != prev_rp_count:
rp_counts.append(rp_count)
times.append(datetime.fromtimestamp(i / ticks_per_second))
prev_rp_count = rp_count
return times, rp_counts
def prettify_lc_data(data_iterable):
"""Takes model iterable and returns distinct LC counts with times.
Returns two lists (times, lc_counts).
"""
lc_counts = []
times = []
prev_lc = None
for i, (rp_count, lc) in enumerate(data_iterable):
if lc != prev_lc:
lc_counts.append(lc)
times.append(datetime.fromtimestamp(i / ticks_per_second))
prev_lc = lc
return times, lc_counts
biped_data = list(biped())
grekim_data = list(grekim())
# Plot RPs/time graph
biped_times, biped_rps = prettify_rp_data(biped_data)
grekim_times, grekim_rps = prettify_rp_data(grekim_data)
plt.figure(1)
plt.subplot(211)
axes = plt.gca()
axes.xaxis.set_major_formatter(dates.DateFormatter('%M:%S'))
axes.set_xlabel("Time")
axes.set_ylabel("Number of RPs")
axes.set_axisbelow(True)
plt.xlim([datetime.fromtimestamp(0), datetime.fromtimestamp(simulation_length)])
plt.step(biped_times, biped_rps, 'b.-', where="post", label="Biped RPs")
plt.step(grekim_times, grekim_rps, 'g.-', where="post", label="Grekim RPs")
plt.grid(True, which="major", linestyle="-")
plt.grid(True, which="minor", color="b", linestyle="--")
plt.legend(loc=2, prop={'size':10})
# Plot LC/time graph
biped_times, biped_lc = prettify_lc_data(biped_data)
grekim_times, grekim_lc = prettify_lc_data(grekim_data)
plt.subplot(212)
axes = plt.gca()
axes.xaxis.set_major_formatter(dates.DateFormatter('%M:%S'))
axes.set_xlabel("Time")
axes.set_ylabel("Amount of LC")
axes.set_axisbelow(True)
plt.xlim([datetime.fromtimestamp(0), datetime.fromtimestamp(simulation_length)])
plt.step(biped_times, biped_lc, 'b-', where="post", label="Biped LC")
plt.step(grekim_times, grekim_lc, 'g-', where="post", label="Grekim LC")
plt.grid(True, which="major", linestyle="-")
plt.grid(True, which="minor", color="b", linestyle="--")
plt.legend(loc=2, prop={'size':10})
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment