supply/genetic.py

88 lines
2.3 KiB
Python

import supply
import random
import matrixbot
import numpy as np
from operator import itemgetter
SOLD_BENEFIT = 2
def run_generation(pop, i):
print("Generation %d" % i)
ranking = []
for x in pop:
score = evaluate(x)
ranking.append((score, x))
ranking.sort(key=itemgetter(0))
print("Best of generation: ", ranking[0])
newpop = [x[1] for x in ranking[:len(ranking)//2]]
newpop = breed(newpop, len(pop), i)
return newpop
def evaluate(mem):
g = supply.variableRequestGenerator(supply.TURNS, 8, 14)
#chain = [StupidAI(12), PlayerChain("Manufacturer", 12), Base()]
chain = [matrixbot.MatrixBot(mem[:25], mem[25:], 12), supply.Base()]
total_sold = 0
history = []
for topreq in g:
requests = [x.request() for x in chain]
requests = requests[:-1]
requests.insert(0, topreq)
got = 0
for i, c in reversed(list(enumerate(chain))):
got = c.reconcile(requests[i], got)
#print("Sold ", got, " units.")
total_sold += got
history.append([x.cost() for x in chain])
total_cost = [sum([x[0] * supply.SUPPLY_COST + x[1] * supply.BACKLOG_COST for x in y]) for y in history]
cost = supply.integrate(total_cost)[-1] - (total_sold * SOLD_BENEFIT)
return cost
def mate(a, b):
out = []
for x in range(len(a)):
if random.random() < 0.5:
out.append(a[x])
else:
out.append(b[x])
return np.array(out)
def mutate(a):
for i in range(5):
x = random.randint(0, len(a) - 1)
amt = random.uniform(-0.5, 0.5)
a[x] = a[x] + amt
WEIGHT = 0.9
LATE_WEIGHT = 0.2
GENS = 500
def breed(pop, n, i):
global WEIGHT
mut_chance = (WEIGHT - LATE_WEIGHT) * (GENS - i / GENS) + LATE_WEIGHT
total = n - len(pop)
newbies = []
while total != 0:
a = random.choice(pop)
b = random.choice(pop)
c = mate(a, b)
if random.random() < mut_chance:
mutate(c)
newbies.append(c)
total -= 1
c = pop[:]
c.extend(newbies)
return c
def main():
starting_pop = []
for i in range(300):
x = np.random.uniform(low=-2, high=2, size=30)
starting_pop.append(x)
pop = starting_pop
for gen in range(GENS):
pop = run_generation(pop, gen+1)
if __name__ == "__main__":
main()