-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweasel.py
68 lines (57 loc) · 1.96 KB
/
weasel.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import random
import string
import click
VALID_CHARSET = string.ascii_uppercase + ' '
def validate_target(ctx, param, value):
if set(value).union(VALID_CHARSET) != set(VALID_CHARSET):
raise click.BadParameter('Target string must only contain spaces and uppercase ASCII characters.')
return value
@click.command()
@click.option(
'-t', '--target',
type=str,
default='METHINKS IT IS LIKE A WEASEL',
callback=validate_target,
show_default=True)
@click.option(
'-p', '--population-size',
type=click.IntRange(1),
default=100,
show_default=True)
@click.option(
'-r', '--mutation-rate',
type=click.FloatRange(0, 1),
default=.05,
show_default=True)
@click.option(
'--color/--no-color', 'is_colorized',
default=True,
is_flag=True,
show_default=True,
help='Uses ANSI colors when reporting generation results')
def cli(target, population_size, mutation_rate, is_colorized):
"""Simulate Dawkins' weasel experiment"""
best_subject = ''.join(random.choices(VALID_CHARSET, k=len(target)))
generation = 0
def mutate(subject):
return ''.join(
c if random.random() >= mutation_rate
else random.choice(VALID_CHARSET) for c in subject)
def evaluate(subject):
return sum(a == b for a, b in zip(subject, target))
def report(subject):
click.echo(f'{generation: 6}: ', nl=False)
styled_subject = ''.join(
click.style(a, bold=True, fg='green' if a == b else 'red')
for a, b in zip(subject, target))
click.echo(styled_subject, color=is_colorized, nl=False)
score = evaluate(subject)
click.echo(f' -- score: {score}/{len(target)}')
while True:
population = population_size * [best_subject]
population = map(mutate, population)
best_subject = max(population, key=evaluate)
report(best_subject)
if best_subject == target:
return 0
generation += 1