2048-ml

git clone git://git.codymlewis.com/2048-ml.git
Log | Files | Refs | README | LICENSE

Evolve.py (2153B)


      1 #!/usr/bin/env python3
      2 
      3 import random
      4 import numpy as np
      5 import sys
      6 
      7 import Autoplay
      8 
      9 
     10 '''
     11 Functions to perform evolutionary learning of 2048
     12 '''
     13 
     14 
     15 BASES = ["u", "d", "l", "r"]
     16 
     17 
     18 def pool_play(genomes):
     19     '''Get the population of genomes to play the game'''
     20     return [Autoplay.convert_and_play(g) for g in genomes]
     21 
     22 
     23 def crossover(a, b):
     24     '''Crossover two genomes'''
     25     min_len = min(len(a), len(b))
     26     result = a[:min_len]
     27     for i, gene in enumerate(b[:min_len]):
     28         if random.randint(1, 100) <= 50:
     29             result[i] = gene
     30     return result
     31 
     32 
     33 def mutate(genome):
     34     '''Mutate a genome'''
     35     for i, gene in enumerate(genome):
     36         if random.randint(1, 100) < 30:
     37             genome[i] = random.choice(BASES)
     38     if random.randint(1, 100) < 25:
     39         genome.extend(random.choices(BASES, k=random.randint(1, 5)))
     40     return genome
     41 
     42 
     43 def evolve(epochs, verbose=True):
     44     '''Perform an evolutionary algorithm'''
     45     population = [
     46         random.choices(BASES, k=random.randint(4, 20)) for _ in range(100)
     47     ]
     48     the_best = str()
     49     for epoch in range(epochs):
     50         fitnesses = pool_play(population)
     51         med = np.median(fitnesses)
     52         new_pop = []
     53         for i, fitness in enumerate(fitnesses):
     54             if fitness >= med:
     55                 new_pop.append(population[i])
     56         for _ in range(50):
     57             new_pop.append(
     58                 mutate(
     59                     crossover(random.choice(new_pop), random.choice(new_pop))
     60                 )
     61             )
     62         max_index = np.argmax(fitnesses)
     63         the_best = str().join(population[max_index])
     64         if verbose:
     65             sys.stdout.write("\033[K")
     66             print(
     67                 f"Epoch {epoch + 1}: " +
     68                 f"genome {the_best} " +
     69                 f"scored {fitnesses[max_index]}",
     70                 end="\r"
     71             )
     72         population = new_pop
     73     return the_best
     74 
     75 
     76 if __name__ == "__main__":
     77     NUM_EPOCHS = 100
     78     print("Evolving a strategy for 2048...")
     79     RESULT = evolve(NUM_EPOCHS)
     80     SCORE = Autoplay.play(RESULT, verbose=True)
     81     print(f"The best strategy found was {RESULT}")
     82     print(f"It scored {SCORE}")