- Sacramento - California State University

Transcription

- Sacramento - California State University
GENETIC QWOP
EVOLVING A BIPEDAL GAIT IN A TWO-DIMENSIONAL WORLD
A Project
Presented to the faculty of the Department of Computer Science
California State University, Sacramento
Submitted in partial satisfaction of
the requirements for the degree of
MASTER OF SCIENCE
in
Computer Science
by
Steven Ray
FALL
2013
GENETIC QWOP
EVOLVING A BIPEDAL GAIT IN A TWO-DIMENSIONAL WORLD
A Project
by
Steven Ray
Approved by:
__________________________________, Committee Chair
V. Scott Gordon, Ph.D.
__________________________________, Second Advisor
Du Zhang, Ph.D.
____________________________
Date
ii
Student: Steven Ray
I certify that this student has met the requirements for format contained in the University format
manual, and that this project is suitable for shelving in the Library and credit is to be awarded for
the project.
__________________________, Graduate Coordinator
Nikrouz Faroughi, Ph.D.
Department of Computer Science
iii
___________________
Date
Abstract
of
GENETIC QWOP
EVOLVING A BIPEDAL GAIT IN A TWO-DIMENSIONAL WORLD
by
Steven Ray
QWOP is a popular Flash game developed by Bennet Foddy in which the user takes control of an
Olympic sprinter running a 100-meter dash. Designed to force the user essentially to re-learn to walk,
QWOP has gained notoriety for its difficulty due to an unintuitive control scheme and its ragdoll physics
system.
This master project seeks to solve QWOP using a genetic algorithm (GA), a search heuristic
inspired by biological evolution through natural selection. The GA implemented here aims to solve QWOP
by evolving sequences of inputs that, when looped, play the game. This particular implementation, lacking
any dynamic sensory feedback with which to adjust the runner’s movements, will essentially learn to solve
QWOP blind. In this way, the project may demonstrate a proof of concept for learning a robotic gait in a
complex environment with very limited inputs and feedbacks.
A Java-based QWOP controller program, developed by Laurent Vaucher, is used to play QWOP
using input sequences produced by several different GA implementations. Stable gaits are achieved that
consistently converge towards speeds comparable to those of human players.
_______________________, Committee Chair
V. Scott Gordon, Ph.D.
_______________________
Date
iv
ACKNOWLEDGEMENTS
I would like to thank everyone who helped me to finish this project. I would like to thank
Dr. V. Scott Gordon, my project advisor, for taking active interest in this experiment. Dr.
Gordon’s encouragement and guidance not only persuaded me to extend this project from a
semester class project into a master’s project, but also helped me to complete the project. I would
also like to thank Dr. Du Zhang for being my project’s second reader. I would like to thank Dr.
Nikrouz Faroughi, Graduate Coordinator of the Computer Science Department at Sacramento
State, for his support. I would also like to thank Laurent Vaucher for developing and releasing the
Qwopper software that made this project possible. I would like to thank my friends and family for
their encouragement. Lastly, I would like to thank my wife, Sally, for her unwavering love,
support and inspiration throughout this endeavor.
v
TABLE OF CONTENTS
Page
Acknowledgements ................................................................................................................... v
List of Tables ........................................................................................................................ viii
List of Figures .......................................................................................................................... ix
Chapter
1. INTRODUCTION .............................................................................................................. 1
1.1 QWOP.................................................................................................................... 1
1.2 Controls ................................................................................................................. 1
1.3 Ragdoll Physics...................................................................................................... 2
1.4 Project Motivation ................................................................................................. 2
2. BACKGROUND ................................................................................................................ 4
2.1 QWOP Research .................................................................................................... 4
2.2 Genetic Algorithms ................................................................................................ 5
2.3 Steady-State Genetic Algorithm ............................................................................ 5
2.4 Cellular Genetic Algorithm.................................................................................... 6
2.5 Evolving Gaits ....................................................................................................... 6
3. SYSTEM ORGANIZATION ............................................................................................. 8
3.1 The QWOP Controller ........................................................................................... 8
3.2 Selection Strategy ................................................................................................ 10
3.3 Evolutionary Model ............................................................................................. 10
3.4 Fitness Function ................................................................................................... 12
3.5 Genetic Encoding ................................................................................................. 12
vi
3.6 Crossover ............................................................................................................. 15
3.7 Mutation ............................................................................................................... 16
3.8 Initial Population Generation ............................................................................... 16
3.9 Measuring Success ............................................................................................... 17
4. RESULTS ......................................................................................................................... 19
4.1 Quantitative Results ............................................................................................. 19
4.2 Genotypic Analysis .............................................................................................. 24
5. DISCUSSION ................................................................................................................... 28
5.1 Implications ......................................................................................................... 28
5.2 On Premature Convergence ................................................................................. 29
6. CONCLUSION AND FUTURE WORK ......................................................................... 30
6.1 Conclusion ........................................................................................................... 30
6.2 Future Work ......................................................................................................... 30
Appendix A. Source Code ...................................................................................................... 32
Appendix B. Sample Evolution Log ....................................................................................... 43
Appendix C. Sample Generation Summary Log .................................................................... 50
Bibliography ........................................................................................................................... 56
vii
LIST OF TABLES
Tables
Page
Table 1 – Encoding 2 Alphabet With Input States................. .………………………………. 14
viii
LIST OF FIGURES
Figures
Page
Figure 1 – Qwopper system diagram ....................................... .………………………………. 9
Figure 2 - Generational Model Pseudo Code ......................... .………………………………. 10
Figure 3 – Cellular Model Pseudo Code ..................................... ……………………………. 11
Figure 4 – Example Runner Using Encoding 1 .......................... ……………………………. 13
Figure 5 – Example Runner Using Encoding 2 .............................. …………………………. 15
Figure 6 - Single-point “Cut-and-splice” Crossover ....................... …………………………. 15
Figure 7 - Two-point Crossover ...................................................... …………………………. 16
Figure 8 – Genetic Implementation and Qwopper system diagram …………………………. 18
Figure 9 – Config. 1 Average Fitness (9 Generations) ................... …………………………. 20
Figure 10 – Config. 2 Average Fitness (30 Generations) ............... …………………………. 21
Figure 11 – Config. 2 vs. Config. 3, Average Fitness (30 Generations)………...……………22
Figure 12 – Config. 3 Fit vs. Unfit Initial Population ..................... …………………………. 24
Figure 13 – Opening Move Genes ‘QO’ and ‘WP’ ........................ …………………………. 26
Figure 14 – The ‘WO’ Opening Stride and Resulting Stance……….………………………. 26
Figure 15 – Gait involving hopping on one knee while kicking with the free leg………..…. 27
ix
1
Chapter 1
INTRODUCTION
1.1 QWOP
QWOP is a popular computer game developed in Adobe Flash by Bennett Foddy, and is
available for free on his site Foddy.net [1]. In QWOP, the player takes control of an Olympic
sprinter running a 100-meter race. Upon reaching the 100-meter mark, the player wins the game.
If the runner's head or one of his hands touches the ground at any point along the way, QWOP
considers him fallen, and the game is over. The game quickly became notorious for its difficulty,
despite what seems like a simple task. Playing QWOP well has been described as "a ballet of tiny
corrections, any of which is likely to throw off the player’s timing and may result in a fatal error."
[2] QWOP's difficulty is largely a function of two factors: the control scheme and the physics
engine.
1.2 Controls
QWOP gets its name from the game's control scheme. To play a game of QWOP, the
user controls the runner using only the Q, W, O, and P keys on the keyboard, each of which
controls a specific muscle group in the runner’s legs. Q and W move forward the runner’s left and
right thighs respectively. The O and P keys each map to his left and right calves. Achieving a
realistic bipedal gait in QWOP is often soon abandoned by new players, who tend to resort either
to finding a repeatable pattern of inputs sufficient enough to scoot the sprinter to the finish line or
to giving up in frustration, amusement, or both.
The primary factor contributing to QWOP's difficulty is its unintuitive control scheme.
Bennet Foddy designed QWOP to force users to work out mechanically a task that most of us
perform every day and to which we do not devote much active thought. Users are precluded from
2
relying on their own experience and knowledge of balancing and walking on two legs, because
QWOP reroutes the motor skill of synchronized leg muscle manipulation to the user's fingers via
the game controls. Players are also limited with regard to the amount and type of relevant sensory
feedback available to tell how well they are doing and make necessary adjustments to their
runner's gait to avoid falling, as the only relevant and available sensory feedback is the visual
state of the runner.
1.3 Ragdoll Physics
The second factor that most complicates QWOP is its ragdoll physics engine. Ragdoll
physics is a method for procedurally animating characters based on a skeletal configuration of
rigid bodies connected by joints and muscles in a simulated physical environment [3]. The
physics system is an approximation of the real world that creates a simplified but reasonably
realistic experience for the QWOP runner’s body with regard to physical laws like gravity,
friction, and inertia. The player must constantly work not only to complete the race, but also to
keep the runner from falling over with each step. Every slight movement of the runner's legs
carries with it consequences of momentum and velocity compounded by the game world's gravity
and friction. Combined with the unintuitive control scheme, achieving QWOP's seemingly simple
goal becomes extremely difficult, as the game is very unforgiving to imprecise and poorly timed
movements.
1.4 Project Motivation
QWOP is a simple game without an obvious solution. For a game with only four inputs,
improving the runner's performance has proven to be a difficult, unintuitive task for humans. The
goal of solving a game like QWOP seems well suited to a machine learning algorithm. This
3
project seeks to achieve this goal by optimizing QWOP input loops using a genetic algorithm.
Due to the combination of its high difficulty and relatively small search space, QWOP seems well
suited to a genetic approach. The significance of solving QWOP genetically using only variations
and recombinations of input sequences would demonstrate a proof of concept for robotic bipedal
gait learning in a complex space using very few inputs and feedbacks. A secondary goal of this
project is to learn how different types of genetic learning impact the algorithm's overall
performance.
4
Chapter 2
BACKGROUND
2.1 QWOP Research
Interestingly, research into leveraging machine learning algorithms to solve QWOP is not
without precedent. In 2012, Gustav Brodman and Ryan Volstad of Stanford used reinforcement
learning to achieve bipedal gaits in a stick-figure simulation of QWOP. Their program took a
multi-dimensional feedback approach that moved the runner and adjusted his various limbs based
on their horizontal, vertical and angular velocities, the body's calculated center of mass, and
whether or not at least one foot was touching the ground. Their learning approach was able to
achieve a stable "shuffle-like” gait and a less stable but faster gait, depending on the
reinforcement learning model used [4].
In March of 2011, a French programmer named Laurent Vaucher attempted to solve
QWOP genetically by building a Java-based controller program that could play QWOP through a
web browser. Unlike the work of Brodman and Volstad, which used a model of QWOP,
Vaucher's program attempted to play QWOP itself. Vaucher's "Qwopper" program was able to
interact with the desktop to locate the game display in an open browser window, could read the
game's display to parse key information like the score and whether or not the runner had fallen,
and was able to send mouse commands to QWOP's on-screen interface to control the game.
Vaucher had planned to solve QWOP genetically using his controller, and he made it as far as
developing a genetic encoding for the input patterns with which he generated and tested random
runners. Before moving on to other projects, Vaucher posted his progress to his blog,
slowfrog.blogspot.com, and released his source code to anyone interested in the problem [5].
5
This project picks up Vaucher's baton and utilizes his QWOP controller to implement a
genetic learning algorithm that will converge toward an optimal solution by evolving populations
of looped input sequences.
2.2 Genetic Algorithms
A genetic algorithm (GA) is a type of search algorithm inspired by the biological
processes of evolution through natural selection. GAs are used primarily in search and
optimization problems, and work by evolving populations of candidate solutions toward better
solutions. The solution space is encoded into some form of genetic representation, which may
vary from an array of bits to a set of properties. A population of genetically encoded candidate
solutions is initialized. Each member of the population is then evaluated by a fitness function
which selects for the best solutions in the population. The fittest candidates in a given generation
are selected to "mate" with each other to produce child solutions comprised of parts of each
parent through some form of crossover process. The children are then typically mutated before
being added to the next generation. The GA iterates through generations in this manner until it
reaches some terminating condition, such as a sufficiently optimized solution or a fixed number
of generations.
2.3 Steady-State Genetic Algorithm
Steady-state GAs are a variation of the algorithm which do not follow a generational
model. Instead of populating generation N+1 with the children of selected individuals from
generation N, children in the steady-state variant are evaluated against their parents. The best two
individuals from the parents and children are inserted back into the population. The population
size remains constant, and children that are worse than their parents are discarded to guarantee
6
that the average fitness of the population does not decline. The steady-state model has been
shown to yield better performance than the generational model in some problem spaces, and has
been shown to benefit from parallelization [6].
2.4 Cellular Genetic Algorithm
Cellular GAs disallow individuals from mating arbitrarily by limiting mating possibilities
only to nearby individuals in a structured population. The population exists in a multidimensional grid or graph structure in which each individual is connected to other nearby
individuals. In the Cellular GA model, each individual in a population selects a mate from those
in its local proximity. This mechanic simulates isolation by distance within the population, and
results in the creation of niches of subpopulations that promote overall diversity and allow for
broader exploration of the solution space by helping to prevent premature convergence [7]. Like
the steady-state model, the cellular model’s performance also benefits from parallelization.
2.5 Evolving Gaits
Considerable research has been done with GAs in the area of robotic gait learning. GAs
have been explored for learning and optimizing gaits in hexapod [8], quadruped [9], and biped
robots [10]. Biped robotic gait learning offers a slightly different problem domain from
learning for robots with more than two legs, as walking with only two legs necessarily
involves lengths of time during which the robot is supported entirely by only one leg. In
this way, bipedal gaits require greater balance than gaits in which multiple legs are
supporting the robot at any given moment. The vast majority of research into evolving
bipedal gaits uses either physical or simulated robots with relatively high degrees of
7
freedom compared to QWOP’s runner, which has only four degrees of freedom.
Evolutionarily learning a bipedal gait in QWOP could demonstrate a proof of concept for
learning and optimizing a bipedal gait despite great limitation with regard to the robot’s
degrees of freedom and sensory feedback.
8
Chapter 3
SYSTEM ORGANIZATION
3.1 The QWOP Controller
Laurent Vaucher's QWOP controller program, named Qwopper, uses the java.awt.Robot
class to interact with the screen and play QWOP. It captures screen images and compares them
with screenshots and known patterns and colors found in the QWOP interface to locate the game
window. Once the game window is located, Qwopper will give it focus by sending a mouse event
to the game. Once the game window has focus, QWOP is played entirely using keyboard
commands sent by Qwopper. Qwopper monitors the current game score, consisting of the current
distance traveled by the runner, by periodically capturing a rectangular image of the location on
the game screen where the score is displayed. Qwopper then applies a thresholding function that
converts the image to black and white, tokenizes each character in the image, and then compares
against a set of reference images of each character to parse the score for each runner. If the runner
falls over, Qwopper sends a spacebar command to restart the game.
9
Figure 1 – Qwopper system diagram
The genetic implementation uses Voucher's Qwopper software to evaluate the fitness of
each runner in a population by playing QWOP according to each runner's genetic sequence,
which is looped until the runner crashes, reaches the time limit, or beats the game. Generations of
runners evaluated by Qwopper are evolved using a genetic algorithm and logged for analysis.
10
3.2 Selection Strategy
The selection strategies examined for this project were 3:2 tournament selection and local
selection. 3:2 tournament selection randomly chooses three runners from a population and selects
the two with the highest fitness scores to become parents. Local selection restricts the pool of
potential mates of a given individual to the individual’s neighbors in the population, and mates
the individual with the neighbor with the highest fitness score.
3.3 Evolutionary Model
The project examined two different implementations of the evolutionary model: a
generational model and a cellular model. The generational model used is described by the
following pseudo code:
P = generate a population of runners
while termination criteria not met
{
nextGen = new empty population
while nextGen is not full
{
select three random runners from P
parent1, parent2 = the two fittest runners of those selected
child1, child2 = crossover(parent1, parent2)
add child1 and child2 to nextGen
}
P = nextGen
}
Figure 2 - Generational Model Pseudo Code
11
The cellular GA implementation used a local selection strategy that restricted the pool of
potential mates for a given runner to those nearest to it in the population. Local selection was
realized using a two-dimensional borderless “wrap-around” grid structure so that each index
would have the same number of neighbors, as well as to avoid introducing an arbitrary boundary
around the population. Local selection was introduced to prevent, or at least slow considerably,
premature convergence on a suboptimal solution due to loss of genetic diversity in the population.
Population size was also increased for this configuration to help prevent premature
convergence. The cellular configuration also borrowed from steady-state GAs in how child
runners were allowed to advance to the next generations. Children were only allowed to advance
to the next generation if they performed better than their parents. This both guaranteed that
average population fitness could only increase, and also introduced elitism, whereby good
solutions that outperformed their children would themselves survive to the next generation. The
pseudo code for the cellular implementation is a follows:
P = generate a population of runners in a 2D borderless grid
while termination criteria not met
{
nextGen = new empty borderless grid
for each runner in P
{
parent1 = the current runner
parent2 = the fittest neighbor to parent1 in P
child1, child2 = crossover(parent1, parent2)
best = the fittest runner among parent1, child1, and child2
add best to nextGen at parent1’s index
}
P = nextGen
}
Figure 3 – Cellular Model Pseudo Code
12
In the cellular configuration, each runner is allowed to mate with its fittest neighbor. The
cellular configuration is synchronous, meaning that the algorithm proceeds from the top left
individual through each row until every individual has mated. A temporary population is used to
store the best runners produced for each index. After the entire population has mated, the current
generation is replaced with the new temporary population.
3.4 Fitness Function
The fitness function is informed by two parameters, both of which are collected by
Qwopper. The first parameter is the final state of the runner when a run ends, of which there are
two: stopped and crashed. If the runner falls over, Qwopper recognizes the game over screen and
considers the runner crashed. If the run ends for any other reason, either because a time limit has
been reached or the race was completed, the final state is "stopped." The second parameter is the
final score achieved when the runner reaches its final state. The duration of each run is also
recorded. Fitness functions favoring stability, average speed, max distance traveled, and
combinations thereof were each explored through experimentation.
3.5 Genetic Encoding
Two different encodings were explored. The first encoding was developed by Vaucher,
and was the encoding that Qwopper first used to create and play random runners. A second
encoding was developed for this project that addressed some issues discovered when populations
created in the original encoding were subjected to crossover and mutation functions during
evolution.
Vaucher’s encoding ( Encoding 1 ) represented a sequence of QWOP inputs as a string of
characters. Each character represents either a key press, a key release, or a delay. An example
13
individual could look like the following:
QO+qPW+wpo+QPW+wO+qp+P+Q+++qp+QPW+wo+qp+POQ+q+W+Qp+qwo
Figure 4 – Example Runner Using Encoding 1
A capital letter represents pressing that key on the keyboard, a lowercase letter represents
a key release, and the ‘+’ represents a delay in which the current state of inputs is maintained for
a set length of time. The individual in the above figure translates to “Press Q and O, hold them for
150ms, release Q, press P and W, hold for 150ms, release W, P and O, wait…” and so on. One
beneficial feature of Encoding 1 is that it is very easy to read and understand the sequence of
inputs represented by the solution candidate.
Encoding 1 proved problematic when crossover and mutation were introduced, because the
control state at any given point on an individual using this encoding is highly dependent on its
context within the sequence. Crossover and mutation operations on individuals defined with
Encoding 1 resulted in producing “non-coding DNA” or redundant commands like consecutive
capitals or lower-case letters. Encoding 1 was designed such that each letter indicates a change in
the current input state. Each crossover and mutation operation had a high probability of rendering
one or more characters in the chromosome redundant, which often dramatically altered the input
sequence. The second genetic encoding explored ( Encoding 2 ) encodes input sequences using a
16-character alphabet, each letter of which represents one of the possible input combinations in
QWOP.
14
Table 1 – Encoding 2 Alphabet With Input States
Alphabet
Q
W
O
P
P
D
C
J
B
I
H
N
A
G
F
M
E
L
K
O
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
0
0
0
0
1
1
1
1
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
0
1
QWOP uses only four buttons, so there are 16 possible input combinations that comprise
QWOP’s input space. Each letter in Encoding 2 maps to one of these 16 input combinations.
Unlike Encoding 1, input sequences built with this alphabet assume a small delay between each
letter’s execution, since each letter defines a distinct input state for all four control keys.
Encoding 2 also did not suffer from the context-dependence of letters in Encoding 1, since each
letter here represents a distinct input state for all four keys. As seen in Figure # above, a key value
of 0 indicates a key release command, and the key value 1 indicates a command to press the key.
Redundant sequential press commands for a given key will simply continue to hold the pressed
key continuously, while redundant release commands will just continue to refrain from pressing
that key. An example individual defined using Encoding 2 follows:
15
FGBCHFELMIEFNGJCLHLEMCLJKJLNEKGHDGJDAJLE
Figure 5 – Example Runner Using Encoding 2
Each letter in the sequence is separated by an implied wait period of 150ms, like Encoding 1,
during which the current input state is maintained, meaning that any keys pressed according to the
current letter are held until a letter is encountered that releases that key. This individual translates
to “press Q and O, hold for 150ms, press P and release O while continuing to hold Q, wait for
150ms, release Q and O and press W, hold for 150ms, release W and press O, wait…” and so on.
3.6 Crossover
This project experimented with two crossover strategies: single-point “cut-and-splice”
crossover, and standard two-point crossover.
Figure 6 - Single-point “Cut-and-splice” Crossover
The “cut-and-splice” strategy selects a different crossover point for each parent, allowing
for varying chromosomal lengths to be produced in offspring. The motivation for this approach
was that the appropriate length of a good input loop in QWOP is not at all obvious, and this
strategy increases the search space of the algorithm with regard to the length of looped input
sequences.
16
Figure 7 - Two-point Crossover
A two-point crossover strategy creates two crossover points for each parent at the same
location on both parent chromosomes, thus maintaining chromosomal length in children and
throughout all generations. The average fitness of populations evolved using this and the “cutand-splice” approach were compared to determine whether the length of the sequence was a
relevant characteristic.
3.7 Mutation
The mutation mechanic used throughout the project for both genetic encodings was to
randomly select and alter a single character in every child runner.
3.8 Initial Population Generation
A population was initialized in one of two ways. A collection of hundreds of random
runners were generated with each of the two encodings and fitness-tested. Each random runner
played QWOP for 60 seconds or until it fell down. The first initialization strategy seeded
Generation 0 with the best performing randomly generated runners. The second initialization
strategy populated Generation 0 with untested random runners. The generational implementation
used a population size of 16 individuals, while the hybrid model increased the population size to
17
30 to promote increased genetic diversity and help avoid premature convergence.
3.9 Measuring Success
This project seeks to evolve a stable bipedal gait with a maximum average speed using
very limited sensory input. Output from variations on the configuration of the GA will be
compared as the GA is tuned to improve its performance. The fastest runners, measured by
meters traveled per minute, will then be compared against the best QWOP scores achieved by
humans.
18
Figure 8 – Genetic Implementation and Qwopper system diagram
19
Chapter 4
RESULTS
4.1 Quantitative Results
Three configurations of the GA parameters described above were tested. The first
configuration used a generational model, Encoding 1, 3:2 tournament selection, single-point cutand-splice crossover, and a population consisting of the 16 best-performing runners from a pool
of 390 randomly generated individuals. As seen in Figure 9, this configuration failed to evolve
solutions that played QWOP any better than the best randomly generated ones. This lack of
improvement was attributed to a consistently observed high rate of failure in children ( >50% ).
Because this GA configuration used a naïve succession policy wherein every child produced was
guaranteed to succeed to the next generation, this high failure rate precluded the gene pool from
improving with any significance.
20
Configuration 1 - Average Generational Fitness
(9 Generations)
30
25
20
Speed
15
(m/min)
10
5
0
1
2
3
4
5
6
7
8
9
Generation
Figure 9 – Config. 1 Average Fitness (9 Generations)
The second configuration was identical to the first, except that it used a succession
policy similar to that of the steady-state model. In this configuration, children only succeeded to
the next generation if they outperformed the worst of the three potential parents selected. This
single parameter tweak resulted in a GA that produced positive results, as seen in Figure 10. The
steady-state succession policy conferred a significant performance improvement over the first
configuration’s naïve policy that did not test and weed out children that performed worse than
their parents, as both of these configurations were run using the same initial population.
Though the second configuration was successful at evolving better runners, average
generational fitness did not always improve, as seen in Figure 10. This generational variance was
again attributed to the succession policy. Selecting children that performed better than only the
potential parent that was not selected to mate left some room for the possibility of generational
21
fitness decline because children could still advance if they performed worse than their parents but
better than the weakest potential parent chosen by 3:2 tournament selection.
Configuration 2 - Average Generational Fitness
(30 Generations)
30
25
20
Speed
15
(m/min)
10
5
0
1
5
10
15
20
25
30
Generation
Figure 10 – Config. 2 Average Fitness (30 Generations)
The configuration that eventually yielded the most stable and consistently efficient
gaits is featured in Figure 11 compared with the Configuration 2 data series from Figure 10.
Configuration 3 used the hybrid generational/steady-state grid model, the new 16-letter encoding,
local selection, two-point crossover, and an increased population of 30 individuals. This
population was also initialized with the best randomly generated runners from a pool of 500 built
using Encoding 2.
Compared with previous configurations, the fitness curve was smoother, generational
fitness never declined, solutions improved more quickly through the early generations, and the
configuration converged toward better solutions in fewer generations than other successful
configurations.
22
Configuration 3 vs. Configuration 2
(30 Generations)
30
Config 2
Config 3
25
20
Speed
15
(m/min)
10
5
0
1
5
10
15
20
25
30
Generation
Figure 11 – Config. 2 vs. Config. 3, Average Fitness (30 Generations)
Two pools of random runners were generated. The first pool of random runners was
produced by Laurent Vaucher using his original genetic representation of the solution space,
Encoding 1. The second pool was generated using Encoding 2, the 16-character encoding
developed during this project. All three GA configurations were tested using initial populations
consisting of the best-performing candidates taken from these pools of randomly generated
runners.
Encoding 2 produced, on average, better runners than did Encoding 1. For both genetic
encodings, though, the vast majority of randomly generated solutions crashed at or very near the
starting line. The top 30 random runners filtered from a pool of 500 using Encoding 2 traveled, on
average, over twice as fast as the best 16 runners from a pool of 390 using the Encoding 1. The
average fitness of the 30 fastest random runners from Encoding 2 was 5.767 meters per minute,
while Encoding 1 averaged 2.033 meters per minute in its 16 fastest random runners. These
23
results constitute a 180% increase in the average fitness of Encoding 2’s best random runners
compared to the best random runners from Encoding 1.
To control for this performance gap between the best random runners generated by the
two different encodings, Configuration 3 was further tested using a different initial population of
random runners, of which each runner had crashed outright when first tested by Qwopper.
Despite a low average fitness of this initial population at 1.3 meters per minute, the average
generational fitness accelerated just as quickly in early generations as did the population seeded
with high quality random candidates. Regardless of the fitness of the initial population,
Configuration 3 consistently performed better than Configuration 2, suggesting that the other GA
parameters were largely responsible for the algorithm’s accelerated evolution toward faster
runners compared to the previous configurations.
24
Configuration 3 - Fit vs. Unfit Initial Population
Fit
Unfit
30
25
20
Avg. Speed
15
(m/min)
10
5
0
0
10
20
30
40
50
60
70
80
Generation
Figure 12 – Config. 3 Fit vs. Unfit Initial Population
4.2 Genotypic Analysis
The combination of the physics engine and restrictive control scheme make falling over
in QWOP very easy, both for humans and, as it turned out, also for the GA implementations
described in this paper. Significant selective pressure was placed on finding a stable gait. The
fitness function also selected for speed, which necessarily, only ever evolved after stability.
Compounding this selective pressure was the fact that some amount of effective randomness
exists when the Qwopper program plays QWOP. Because of the ragdoll physics system, when the
game starts, the runner is first initialized to a standing state, and then the physics rules are
immediately applied, causing his body to “settle in” to the gravity. To illustrate the runner’s
instability due to the physics calculations, one can simply start a game and not press any buttons,
then watch as the runner eventually begins to wobble and fall forward as the physics calculations
appear to create a positive feedback loop that gradually increases the wobble. This introduces
25
some amount of effectively random variability in the performance of any given solution sequence
played by the Qwopper program. A single sequence of inputs, run multiple times, will rarely
result in the same score. It was often observed in early generations that the same runner could
score well in one trial and crash in the next. This is evident in the run logs, as many populations
were initialized to the same generation of runners, and in each trial these runners achieved
different scores. This inconsistency only increased selective pressure on producing a stable gait,
as the best surviving gaits were necessarily those that crashed the least despite this variability.
The primary trait that emerged in populations was the stability “gene,” usually expressed
as an opening sequence that resulted in a stable stance.
There were two button combinations that almost always came to dominate the population. The
stable openings were to simultaneously press Q and O or to simultaneously press W and P.
The ‘QO’ combination moves the left thigh backward and extends the right calf forward,
causing the runner to step forward and drop to his left knee with the right leg extended in front.
The ‘WP’ opening performs the inverse operation of bending the right leg back and extending the
left leg forward, which drops the runner to his right knee. In both openings, the runner lowers his
center of gravity and spreads his legs wide, as if trying to do the splits.
26
‘QO’ Opening
‘WP’ Opening
Figure 13 – Opening Move Genes ‘QO’ and ‘WP’
The ‘QO’ and ‘WP’ openings quickly come to dominate populations, even when using a
local selection policy in a large population to slow premature convergence. Notably, the opening
consistently used by the fastest human QWOP scores documented is ‘WO’, which causes the
runner to push off with the back foot and raise the knee of the other leg. The GA always evolves
away from this opening because following it with a stable gait is likely impossible without the
visual sensory feedback that the fastest human players enjoy.
Figure 14 – The ‘WO’ Opening Stride and Resulting Stance
27
The ‘WO’ opening sequence seems to be the most efficient, as it consistently appears in
all of the fastest human “speed-runs” on record. However, this opening does not lead to a stance
stable enough to transition out of well. The GA implementation, as a blind input loop, is
inherently unable to react to visual feedback to adjust its gait during a run like a human player
can, so the ‘WO’ gene is quickly bred out of the population in favor of solutions with more stable
openings.
Figure 15 – Gait involving hopping on one knee while kicking with the free leg
The best-evolved solutions transitioned from one of the two stable openings into a gait
that scooted forward while largely maintaining the runner’s stable stance. Later generations gave
way to the transition from scooting forward to more of a hopping gait. In these gaits, the runner
would typically hop on one knee while kicking his free leg out in front of him to increase forward
momentum. Even in the hopping gait, the legs remained spread apart, maintaining stability.
28
Chapter 5
DISCUSSION
5.1 Implications
This experiment confirms previous research that has shown that the steady-state
evolutionary model outperforms generational models in optimization applications such as
this one, where randomly generated strings are usually very weak, and where a persistent
population of difficult-to-generate above-average strings is needed in order to make
progress. This is intuitive considering the high failure rate of children observed
throughout this experiment. Maintaining successful individuals and only replacing the
weak ones with children of higher quality both helped Configuration 2 to outperform
Configuration 1 and helped Configuration 3 to outperform all other configurations.
Interestingly, the best solutions found by the GA bear a striking resemblance to the way
many people actually play the game. Most people who play QWOP do not post speed-run videos
on YouTube and compete for the world record, which is currently held by Roshan Ramachandra
at 51 seconds [11]. Finding a repeatable pattern and scooting to the finish line is a commonlyrecommended strategy in online discussions about how to beat QWOP, which is the same type of
solution that the GA consistently achieves.
Considering QWOP’s volatile ragdoll physics system, its limited control scheme, and the
fact that the GA used no mechanism for direct sensory feedback with which to respond and make
adjustments, the gaits achieved by the GA implementations described in this paper serve as a
proof of concept for robotic gait learning in a complex space with minimal inputs and feedbacks.
29
5.2 On Premature Convergence
Through repeated trials we observed that certain traits, particularly traits that conferred
some degree of greater gait stability, consistently emerged and often eventually came to dominate
the population. This observation held true even in a Cellular GA implementation which used a
local selection policy in conjunction with a larger population size. If an argument can be made
that the GA prematurely converged toward only solutions with the most stable opening moves, it
is likely a consequence of one of the experiment’s stated goals: to learn to play QWOP without
the ability to react to dynamic sensory feedback. This goal inherently limited the solution space
that the GA could feasibly search.
30
Chapter 6
CONCLUSION AND FUTURE WORK
6.1 Conclusion
This project was undertaken with the hypothesis that QWOP could be solved using a
genetic algorithm. This hypothesis is certainly validated by the data, though there is reason to
expect that improvements could be made to evolve better solutions more efficiently than have
been produced so far. Nevertheless, the results, at the very least, demonstrate a proof of concept
for evolving bipedal robotic gaits with very limited inputs and feedbacks in a complex
environment.
6.2 Future Work
More research could be done that may yield better solutions to QWOP. For instance, long
sequences of inputs that are not looped, rather than sequences of looped inputs, could support the
evolution of a stable opening move while also enabling the evolution of a gait that, unlike looped
sequences, does not necessarily include the opening sequence. Another possible approach would
be to evolve both an opening sequence and a main input loop as distinct entities, since it is
entirely possible that an optimal input loop may not contain the same sequence that starts the
runner from his initial standing position, which is only needed once at the beginning of the race.
This project experimented with and compared many different flavors of the genetic
algorithm and its components, some of which were demonstrably better suited to solving this
particular problem than others. This experiment found the greatest success with a Cellular GA
implementation. There is room for further exploration with regard to solving QWOP using other
variations of the genetic algorithm that were not explored here.
31
One factor that greatly limited the amount of experimentation we were able to achieve is
that solving QWOP requires the GA to evolve populations of solutions that must each play
QWOP in real time at least once. The Qwopper program developed by Laurent Vaucher is a bot
program that takes over the computer it is run on to play QWOP in an open browser window. A
typical population of 30 solution candidates evolved for 30 generations often took over 20 hours
of uninterrupted execution for this project. We have described a highly parallelizable genetic
implementation, and other well-known parallel implementations exist, but we were not able to
leverage this capability on multiple instances due to limited time and resources. This is an area
with the potential to greatly reduce the learning time required to converge on an optimal solution.
Learning time could very likely be reduced by a factor equal to the number of machines used to
process a population in parallel, as long as the number of machines did not exceed the size of the
population.
32
APPENDIX A. SOURCE CODE
package com.slowfrog.qwop;
import java.awt.Robot;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
*
* @author Laurent Vaucher
* Extended by Steven Ray
*
* Running this class will begin executing the
* genetic algorithm on the population.
*
* For the program to inteface with QWOP and execute
* its instructions, the game must fully visible in
* your web browser on your monitor
*
* The results of the execution will be saved to an
* output file titled "evoOut.txt."
*
*/
public class Genetic {
/**
* main method
* @param args
*/
public static void main(String[] args) {
Genetic g = new Genetic();
}
private Map<String, Individual> population;
private WrapGrid<Individual> indivs, nextGen;
//private static final String NOTES = "QWOPqwop++"; //Encoding 1
private static final String NOTES = "ABCDEFGHIJKLMNOP"; //Encoding 2
private List<Individual> good;
private static final Log LOG = new ConsoleLog();
private float fitSum = 0;
private int size;
private int RUNTIMELIMIT = 60000; //60 seconds
private int runsPerIndiv = 1;
private Robot rob;
private Qwopper qwop;
private PrintStream evoOut, genOut; //evolution log and generation log streams
private float genAvgFitness;
private boolean crashed;
private boolean randomGen0 = true; //set to true is using a random gen stored in runs3.txt
33
public Genetic() {
this.population = new HashMap<String, Individual>();
if(randomGen0)
{
this.readPopulation("runs3.txt"); //file containing the bad generation 0
}
else
{
this.readPopulation("runs2.txt");
}
System.out
.println("Population: " + this.population.size() + " individuals");
int totalRuns = 0;
String logFileName = "evo_log_2013_26_1min_RND.txt";
String genLogFileName = "gen_log_2013_26_1min_RND.txt";
int maxGens = 100;
float numRuns = 0;
for (Individual indiv : this.population.values()) {
totalRuns += indiv.runs.size();
}
System.out.println("Total runs: " + totalRuns);
if(!randomGen0) //execute this block for an alternate Gen0
{
IFilter<RunInfo> twoMetersNotCrashed = new AndFilter<RunInfo>(
new MinDistFilter(2), new NotFilter<RunInfo>(new CrashedFilter()));
IFilter<Individual> individualFilter = new MinRatioFilter(
twoMetersNotCrashed);
good = this.filter(individualFilter);
System.out.println("Good Runners: ");
for(int i=0; i<good.size(); i++)
{
System.out.println(good.get(i).toString());
System.out.println(good.get(i).str);
System.out.println(good.get(i).runs.get(0).distance);
}
}
else
{
good = new ArrayList<Individual>();
//runs3 contains 30 random runners. if the flag is set, use this as gen0
for (Individual individual : this.population.values())
{
good.add(individual);
}
}
//init grid for a population of 30 individuals and 4 connections each
indivs = new WrapGrid<Individual>(5, 6, 4);
//store each individual's string and average distance traveled for manipulation
for(int i=0; i<good.size();i++){
float sumFits = 0;
for(int j=0; j<good.get(i).runs.size();j++){
sumFits += good.get(i).runs.get(j).distance;
}
numRuns = good.get(i).runs.size();
good.get(i).fitness = sumFits/numRuns;
//add individual with calculated fitness to the grid
34
indivs.add(good.get(i));
}
try {
rob = new Robot();
qwop = new Qwopper(rob, LOG);
qwop.findRealOrigin();
try {
evoOut = new PrintStream(new FileOutputStream(logFileName, true));
genOut = new PrintStream(new FileOutputStream(genLogFileName, true));
size = good.size();
//list Gen 0
evoOut.println("########## Generation 0 ##########");
for(int i =0; i<size; i++){
evoOut.println(i + ") " + indivs.get(i).str + " avgFitness: " + indivs.get(i).fitness);
}
evoOut.println("###################################");
for(int genCnt = 1; genCnt<=maxGens; genCnt++)
{
evoOut.println("########## " + "Generation " + genCnt + " ##########");
genOut.println("########## " + "Generation " + genCnt + " ##########\n");
genAvgFitness = 0;
for(int i=0; i<size; i++){
evoOut.println("---------- " + "Individual " + (i+1) + " ----------");
//test string specified number of times, average the distance
//after generation 1, each individual gets tested during reproduction of the prev generation
if(genCnt == 1)
{
testString(qwop, indivs.get(i).str, runsPerIndiv, logFileName);
indivs.get(i).fitness = fitSum/runsPerIndiv;
}
genOut.println((i+1) + ") " + indivs.get(i).fitness + " | " + indivs.get(i).str);
evoOut.println((i+1) + ") " + indivs.get(i).fitness + " | " + indivs.get(i).str);
genAvgFitness += indivs.get(i).fitness;
//sum up average generational fitness
}
//log this generation's average fitness
LOG.log("Generation " + genCnt + " Average Fitness: " + genAvgFitness/size);
evoOut.println("Generation " + genCnt + " Average Fitness: " + genAvgFitness/size);
genOut.println("Generation " + genCnt + " Average Fitness: " + genAvgFitness/size + "\n");
//select and mate the parents, mutate the children, and generate the next generation
nextGen = crossoverSteadyStateGrid(indivs);
indivs = nextGen;
}//end generation loop
evoOut.flush();
evoOut.close();
} catch (FileNotFoundException e) {
35
e.printStackTrace();
}
} catch (Throwable t) {
LOG.log("Error", t);
}
}
//copied from MAIN
private void testString(Qwopper qwop, String str, int count, String filename)
{
fitSum = 0;
for (int i = 0; i < count; ++i) {
//LOG.logf("Run #%d\n", i);
qwop.startGame();
RunInfo info = qwop.playOneGame(str, RUNTIMELIMIT);
LOG.log(info.toString());
LOG.log(info.marshal());
evoOut.println(info.toString());
evoOut.println(info.marshal());
//time limit in ms
//info.distance goes into sumfitness
fitSum += info.distance;
crashed = info.crashed;
}
}
//tests a child runner a specified number of times and returns the average fitness
private float testChild(Qwopper qwop, String str, int count) {
float fitness = 0;
evoOut.println("Testing child: " + str);
LOG.log("Testing child: " + str);
for (int i = 0; i < count; ++i) { //currently we only test each child once
qwop.startGame();
RunInfo info = qwop.playOneGame(str, RUNTIMELIMIT);
LOG.log(info.toString());
LOG.log(info.marshal());
evoOut.println(info.toString());
evoOut.println(info.marshal());
//info.distance goes into sumfitness
fitness += info.distance;
crashed = info.crashed;
}
return fitness/count;
}
private static void saveRunInfo(String filename, RunInfo info) {
try {
PrintStream out = new PrintStream(new FileOutputStream(filename, true));
try {
out.println(info.marshal());
} finally {
out.flush();
out.close();
}
} catch (IOException ioe) {
LOG.log("Error marshalling", ioe);
}
}
36
public List<Individual> filter(IFilter<Individual> filter) {
List<Individual> ret = new ArrayList<Individual>();
for (Individual individual : this.population.values()) {
if (filter.matches(individual)) {
ret.add(individual);
}
}
return ret;
}
//finds the fittest of the neighbors of the individual located at curPop[curRow][curCol]
public Individual fittestNeighbor(int curRow, int curCol, WrapGrid<Individual> curPop)
{
Individual up,
right,
left,
down,
fittest;
up
right
down
left
= curPop.get(curRow - 1
= curPop.get(curRow
= curPop.get(curRow + 1
= curPop.get(curRow
, curCol );
, curCol + 1);
, curCol );
, curCol - 1);
//set fittest to the neighbor with the highest fitness
fittest = up;
if (fittest.fitness < right.fitness) fittest = right;
if (fittest.fitness < down.fitness) fittest = down;
if (fittest.fitness < left.fitness) fittest = left;
return fittest;
}
//perform crossover using a 2D wrap-around array of Individuals
public WrapGrid<Individual> crossoverSteadyStateGrid(WrapGrid<Individual> curPop)
{
WrapGrid<Individual> newPop = new WrapGrid<Individual>(curPop.rows, curPop.cols, curPop.conNum);
Random random = new Random(System.currentTimeMillis());
Individual current,
mate;
for(int i = 0; i < curPop.rows; i++)
{
for(int j = 0; j < curPop.cols; j++)
{
current = curPop.get(i, j);
//find the mate for this individual
mate = fittestNeighbor(i, j, curPop);
//update log
LOG.log("Crossover: Finding the fittest neighbor");
LOG.log("Runner: " + current.str + "| fitness: " + current.fitness);
LOG.log("Fittest Neighbor: " + mate.str + "| fitness: " + mate.fitness);
evoOut.println("Crossover: Finding the fittest neighbor");
evoOut.println("Runner: " + current.str + "| fitness: " + current.fitness);
evoOut.println("Fittest Neighbor: " + mate.str + "| fitness: " + mate.fitness);
//this crossover mechanism should maintain chromosomes to a consistent length
int p1 = random.nextInt(current.str.length()/2);
int p2 = p1 + random.nextInt(mate.str.length()/2);
String child1 = current.str.substring(0, p1) + mate.str.substring(p1, p2)
37
+ current.str.substring(p2);
String child2 = mate.str.substring(0, p1) + current.str.substring(p1, p2)
+ mate.str.substring(p2);
//mutate children here, before testing them for fitness
mutate(child1);
mutate(child2);
//test each child
float child1Fitness = testChild(qwop, child1, 1);
boolean child1crashed = crashed;
float child2Fitness = testChild(qwop, child2, 1);
boolean child2crashed = crashed;
//add the best child to the new population if it performs better than the current runner
if( !child1crashed && child1Fitness > child2Fitness && child1Fitness > current.fitness )
{
evoOut.println("Child 1 fit enough to join next generation: " + child1 + "|" + child1Fitness
+ "\nReplacing: " + current.str + "|" + current.fitness);
LOG.log("Child 1 fit enough to join next generation: " + child1 + "|" + child1Fitness
+ "\nReplacing: " + current.str + "|" + current.fitness);
newPop.add( new Individual(child1, child1Fitness) );
}
else if( !child2crashed && child2Fitness > child1Fitness && child2Fitness > current.fitness )
{
evoOut.println("Child 2 fit enough to join next generation: " + child2 + "|" + child2Fitness
+ "\nReplacing: " + current.str + "|" + current.fitness);
LOG.log("Child 2 fit enough to join next generation: " + child2 + "|" + child2Fitness
+ "\nReplacing: " + current.str + "|" + current.fitness);
newPop.add( new Individual(child2, child2Fitness) );
}
//neither child is fitter than the current runner, therefore the current runner advances to next gen
else
{
newPop.add(current);
}
}
}
return newPop;
}
/** Randomly choose three individuals from the pop, select the best two for crossover,
* repeat until a new population of the same size has been generated
*
* Tournament Selection, one-point "cut and splice" crossover,
* and single point mutation for the entire population
*
* This function was used only in Configurations 1 and 2
**/
/* public void crossover(){
Random random = new Random(System.currentTimeMillis());
int rnd;
//reset newpop size
newPopCnt = 0;
newpop = new String[size];
38
boolean newPopFull = false; //true when the new generation has been populated
String[] inds;
float[] fits;
String[] sel;
int weakest = -1;
while(!newPopFull){
//pick three individual strings from current population, select the best two
inds = new String[3];
fits = new float[3];
sel = new String[2];
rnd = random.nextInt(size);
inds[0] = indivs[rnd];
fits[0] = avgFits[rnd];
rnd = random.nextInt(size);
inds[1] = indivs[rnd];
fits[1] = avgFits[rnd];
rnd = random.nextInt(size);
inds[2] = indivs[rnd];
fits[2] = avgFits[rnd];
LOG.log("Crossover: 3 Runners picked at random");
LOG.log("1: " + inds[0] + "| fitness: " + fits[0]);
LOG.log("2: " + inds[1] + "| fitness: " + fits[1]);
LOG.log("3: " + inds[2] + "| fitness: " + fits[2]);
evoOut.println("Crossover: 3 Runners picked at random");
evoOut.println("1: " + inds[0] + "| fitness: " + fits[0]);
evoOut.println("2: " + inds[1] + "| fitness: " + fits[1]);
evoOut.println("3: " + inds[2] + "| fitness: " + fits[2]);
if ( (fits[0] >= fits[1])
|| (fits[0] >= fits[2]))
{
if (fits[1] > fits[2])
{ sel[0] = inds[0]; sel[1] = inds[1]; weakest = 2;}
else
{ sel[0] = inds[0]; sel[1] = inds[2]; weakest = 1; }
}
else
{
if ( (fits[1] >= fits[0])
|| (fits[1] >= fits[2]))
{
if (fits[0] > fits[2])
{ sel[0] = inds[1]; sel[1] = inds[0]; weakest = 2; }
else
{ sel[0] = inds[1]; sel[1] = inds[2]; weakest = 0;}
}
else
{
if ( (fits[2] >= fits[0])
|| (fits[2] >= fits[1]))
{
if (fits[0] > fits[1])
{ sel[0] = inds[2]; sel[1] = inds[0]; weakest = 1;}
else
{ sel[0] = inds[2]; sel[1] = inds[1]; weakest = 0;}
}
}
39
}
LOG.log("Crossover: Parents selected\n");
LOG.log("1: " + sel[0]);
LOG.log("2: " + sel[1]);
evoOut.println("Crossover: Parents selected\n");
evoOut.println("1: " + sel[0]);
evoOut.println("2: " + sel[1]);
//best two selected. perform one-point "cut and splice" crossover.
//two random numbers, each within the size of a parent
int p1 = random.nextInt(sel[0].length());
int p2 = random.nextInt(sel[1].length());
String child1 = sel[0].substring(0, p1) + sel[1].substring(p2);
String child2 = sel[1].substring(0, p2) + sel[0].substring(p1);
//mutate children here, before adding to newpop
mutate(child1);
mutate(child2);
//test each child once
float child1Fitness = testChild(qwop, child1, 1);
//add each child to the new population if it doesn't crash at less than 3m,
//and if it performs better than the weakest potential parent
if( (!crashed || child1Fitness >= 3.0) && child1Fitness > fits[weakest])
{
evoOut.println("Child 1 fit enough to join next generation: " + child1 + "|" + child1Fitness
+ "\nReplacing: " + inds[weakest] + "|" + fits[weakest]);
LOG.log("Child 1 fit enough to join next generation: " + child1 + "|" + child1Fitness
+ "\nReplacing: " + inds[weakest] + "|" + fits[weakest]);
newpop[newPopCnt] = child1;
newPopCnt++;
}
//if new population is full, exit loop
if(newPopCnt == size)
{
newPopFull = true;
continue;
}
float child2Fitness = testChild(qwop, child2, 1);
if((!crashed || child1Fitness >= 3.0) && child2Fitness > fits[weakest])
{
evoOut.println("Child 2 fit enough to join next generation: " + child2 + "|" + child2Fitness
+ "\nReplacing: " + inds[weakest] + "|" + fits[weakest]);
LOG.log("Child 2 fit enough to join next generation: " + child2 + "|" + child2Fitness
+ "\nReplacing: " + inds[weakest] + "|" + fits[weakest]);
newpop[newPopCnt] = child2;
newPopCnt++;
}
//if new population is full, exit loop
if(newPopCnt == size)
newPopFull = true;
}
//the next generation has been created
indivs = newpop;
}*/
40
public String mutate(String indiv){
Random random = new Random(System.currentTimeMillis());
//mutation location
int rnd = random.nextInt(indiv.length());
//the mutation
int rnd2 = random.nextInt(NOTES.length());
String k = NOTES.substring(rnd2, rnd2 + 1);
return indiv.substring(0, rnd) + k + indiv.substring(rnd+1);
}
public void readPopulation(String filename) {
try {
BufferedReader input = new BufferedReader(new FileReader(filename));
try {
String line;
int linenum = 0;
while ((line = input.readLine()) != null) {
++linenum;
if (line.length() > 0) {
try {
RunInfo info = RunInfo.unmarshal(line);
Individual indiv = this.population.get(info.string);
//gets a string from pop
if (indiv == null) {
indiv = new Individual(info.string, null);
this.population.put(info.string, indiv);
}
indiv.runs.add(info);
} catch (RuntimeException e) {
System.out.println("Error on line " + linenum);
throw e;
}
}
}
} finally {
try {
input.close();
} catch (IOException e) {
throw new RuntimeException("Error closing file: " + filename);
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException("File not found: " + filename, e);
} catch (IOException e) {
throw new RuntimeException("Error reading file: " + filename, e);
}
}
}
package com.slowfrog.qwop;
import java.util.*;
/*
* This class describing a borderless "wrap-around" 2D array was modified from
*
http://stackoverflow.com/questions/9058217/2d-array-class-in-java-with-wrap-around-edges
41
*/
public class WrapGrid<T> {
ArrayList<T> array; // holds objects in grid
int rows; // number of rows in grid
int cols; // number of cols in grid
int length; // total number of objects in grid
int conNum; // number of connections for each point on grid (either 4 or 8)
// constructor
WrapGrid(int row, int col, int numCon)
{
rows = row;
cols = col;
length = rows * cols;
conNum = numCon;
array = new ArrayList<T>(length);
}
// returns total size of grid
public int len()
{
return length;
}
// returns number of rows
public int row()
{
return rows;
}
// returns number of columns
public int col()
{
return cols;
}
public void add(T t)
{
array.add(t);
}
// sets object i in flattened out array
public void set(int i, T t)
{
array.set(i, t);
}
// returns object i in flattened out array
// for faster access when user just needs to iterate through all objects
// in grid without respect to position in 2D grid
public T get(int i)
{
return array.get(i);
}
// returns the row position of i in grid - adjusted for warp around edges
private int modRow(int i)
{
if(i < 0) return i + rows;
else if(i >= rows) return i % rows;
else return i;
}
42
// returns the column position of j in grid - adjusted for wrap around edges
private int modCol(int j)
{
if(j < 0) return j + cols;
else if(j >= cols) return j % cols;
else return j;
}
// sets object at (i,j) value from store adjusted for wrap around edges
public void set(int i, int j, T t)
{
array.set(modRow(i) * cols + modCol(j), t);
}
// gets object at (i,j) value from store adjusted for wrap around edges
public T get(int i, int j)
{
return array.get(modRow(i) * cols + modCol(j));
}
// returns distance on the grid between two objects at (y1,x1) and (y2,x2)
public int dist(int y1, int x1, int y2, int x2)
{
int y = distFirst(y1, y2);
int x = distSecond(x1, x2);
if (conNum == 4) // taxicab distance
{
return y + x;
} else { //if(conNum == 8) supremum distance
return Math.max(y, x);
}
}
// returns distance on the grid between the first coordinates y1 & y2 of two objects
public int distFirst(int y1, int y2)
{
int dist = Math.abs(modRow(y2) - modRow(y1));
return Math.min(dist, rows - dist);
}
// returns distance on the grid between the second coordinates x1 & x2 of two objects
public int distSecond(int x1, int x2)
{
int dist = Math.abs(modCol(x2) - modCol(x1));
return Math.min(dist, cols - dist);
}
}
43
APPENDIX B. SAMPLE EVOLUTION LOG
//This log contains the first generation of evolution using Configuration 3 with an
//initial population of poor quality random runners. This run’s results can be seen in
//Fig. 12 as the plot labeled “Unfit”
########## Generation 0 ##########
0) DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
avgFitness: -0.3
1) LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC
avgFitness: 0.1
2) GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
avgFitness: 1.9
3) BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
avgFitness: -0.5
4) FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
avgFitness: 0.3
5) HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
avgFitness: 0.7
6) BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
avgFitness: 1.2
7) FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
avgFitness: -1.1
8) MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH
avgFitness: 0.9
9) JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
avgFitness: 1.3
10) PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB
avgFitness: 0.1
11) PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE
avgFitness: 0.0
12) GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
avgFitness: 1.4
13) ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
avgFitness: 0.2
14) FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA
avgFitness: 0.6
15) NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
avgFitness: 0.8
16) MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH
avgFitness: 0.0
17) GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
avgFitness: 0.4
18) LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD
avgFitness: 0.7
19) AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK
avgFitness: 0.3
20) HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
avgFitness: 1.4
21) HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
avgFitness: -1.1
22) MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
avgFitness: -0.1
23) LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
avgFitness: 0.3
24) PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO
avgFitness: 0.3
25) AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB
avgFitness: -0.3
26) KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
avgFitness: 0.3
27) AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
avgFitness: 0.3
28) EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA
avgFitness: 0.2
29) NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
avgFitness: 1.8
###################################
########## Generation 1 ##########
---------- Individual 1 ---------Ran -0.9m during 2766ms and crashed
RunInfo#1|DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH|150|-0.9|2766|C
1) -0.9 | DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
---------- Individual 2 ---------Ran 0.0m during 3450ms and crashed
RunInfo#1|LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC|150|0.0|3450|C
2) 0.0 | LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC
---------- Individual 3 ---------Ran -0.2m during 5590ms and crashed
RunInfo#1|GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC|150|-0.2|5590|C
3) -0.2 | GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
---------- Individual 4 ---------Ran -0.1m during 3297ms and crashed
RunInfo#1|BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH|150|-0.1|3297|C
4) -0.1 | BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
---------- Individual 5 ---------Ran 14.7m during 60194ms and was stopped
RunInfo#1|FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE|150|14.7|60194|S
5) 14.7 | FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
---------- Individual 6 ---------Ran 0.6m during 1951ms and crashed
RunInfo#1|HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF|150|0.6|1951|C
6) 0.6 | HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
----------
Individual 7
----------
44
Ran 0.8m during 3018ms and crashed
RunInfo#1|BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG|150|0.8|3018|C
7) 0.8 | BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
---------- Individual 8 ---------Ran 2.3m during 60080ms and was stopped
RunInfo#1|FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID|150|2.3|60080|S
8) 2.3 | FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
---------- Individual 9 ---------Ran 0.2m during 2568ms and crashed
RunInfo#1|MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH|150|0.2|2568|C
9) 0.2 | MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH
---------- Individual 10 ---------Ran 1.3m during 3066ms and crashed
RunInfo#1|JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI|150|1.3|3066|C
10) 1.3 | JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
---------- Individual 11 ---------Ran 0.3m during 2829ms and crashed
RunInfo#1|PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB|150|0.3|2829|C
11) 0.3 | PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB
---------- Individual 12 ---------Ran -0.5m during 2567ms and crashed
RunInfo#1|PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE|150|-0.5|2567|C
12) -0.5 | PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE
---------- Individual 13 ---------Ran 1.3m during 3785ms and crashed
RunInfo#1|GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG|150|1.3|3785|C
13) 1.3 | GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
---------- Individual 14 ---------Ran 0.2m during 2884ms and crashed
RunInfo#1|ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD|150|0.2|2884|C
14) 0.2 | ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
---------- Individual 15 ---------Ran 0.1m during 4079ms and crashed
RunInfo#1|FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA|150|0.1|4079|C
15) 0.1 | FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA
---------- Individual 16 ---------Ran 0.9m during 2278ms and crashed
RunInfo#1|NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI|150|0.9|2278|C
16) 0.9 | NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
---------- Individual 17 ---------Ran 0.8m during 3179ms and crashed
RunInfo#1|MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH|150|0.8|3179|C
17) 0.8 | MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH
---------- Individual 18 ---------Ran 0.6m during 2100ms and crashed
RunInfo#1|GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN|150|0.6|2100|C
18) 0.6 | GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
---------- Individual 19 ---------Ran 3.3m during 21604ms and crashed
RunInfo#1|LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD|150|3.3|21604|C
19) 3.3 | LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD
---------- Individual 20 ---------Ran 0.1m during 7706ms and crashed
RunInfo#1|AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK|150|0.1|7706|C
20) 0.1 | AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK
---------- Individual 21 ---------Ran 0.4m during 2583ms and crashed
RunInfo#1|HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN|150|0.4|2583|C
21) 0.4 | HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
---------- Individual 22 ---------Ran 1.6m during 4082ms and crashed
RunInfo#1|HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG|150|1.6|4082|C
22) 1.6 | HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
---------- Individual 23 ---------Ran 1.2m during 3179ms and crashed
45
RunInfo#1|MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI|150|1.2|3179|C
23) 1.2 | MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
---------- Individual 24 ---------Ran -0.6m during 2561ms and crashed
RunInfo#1|LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK|150|-0.6|2561|C
24) -0.6 | LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
---------- Individual 25 ---------Ran 0.7m during 2851ms and crashed
RunInfo#1|PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO|150|0.7|2851|C
25) 0.7 | PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO
---------- Individual 26 ---------Ran 0.1m during 2116ms and crashed
RunInfo#1|AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB|150|0.1|2116|C
26) 0.1 | AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB
---------- Individual 27 ---------Ran 7.4m during 40643ms and crashed
RunInfo#1|KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF|150|7.4|40643|C
27) 7.4 | KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
---------- Individual 28 ---------Ran 0.9m during 2583ms and crashed
RunInfo#1|AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP|150|0.9|2583|C
28) 0.9 | AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
---------- Individual 29 ---------Ran 0.5m during 2700ms and crashed
RunInfo#1|EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA|150|0.5|2700|C
29) 0.5 | EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA
---------- Individual 30 ---------Ran 1.2m during 2829ms and crashed
RunInfo#1|NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI|150|1.2|2829|C
30) 1.2 | NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
Generation 1 Average Fitness: 1.3066669
Crossover: Finding the fittest neighbor
Runner: DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH| fitness: -0.9
Fittest Neighbor: BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG| fitness:
Testing child: DLONAKFEKHAKFOEKNHMHIJNHFOPCOOJMPPODGJGH
Ran -0.3m during 3619ms and crashed
RunInfo#1|DLONAKFEKHAKFOEKNHMHIJNHFOPCOOJMPPODGJGH|150|-0.3|3619|C
Testing child: BOMPDJINICNLKLMPHDADBNOPOLJFBCFDPLMHLIDG
Ran -0.4m during 3464ms and crashed
RunInfo#1|BOMPDJINICNLKLMPHDADBNOPOLJFBCFDPLMHLIDG|150|-0.4|3464|C
Crossover: Finding the fittest neighbor
Runner: LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC| fitness: 0.0
Fittest Neighbor: FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID| fitness:
Testing child: LBBANMKDEJHNOKOJMKHFEAFMGLHFIOILAFPHDPIC
Ran 1.6m during 3034ms and crashed
RunInfo#1|LBBANMKDEJHNOKOJMKHFEAFMGLHFIOILAFPHDPIC|150|1.6|3034|C
Testing child: FMFDKJOPLKMFINFPDIEOOBIPAFPJFLJINCLEHJID
Ran -1.5m during 60166ms and was stopped
RunInfo#1|FMFDKJOPLKMFINFPDIEOOBIPAFPJFLJINCLEHJID|150|-1.5|60166|S
Crossover: Finding the fittest neighbor
Runner: GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC| fitness: -0.2
Fittest Neighbor: KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF| fitness:
Testing child: GBAAJGFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
Ran -0.2m during 2418ms and crashed
RunInfo#1|GBAAJGFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC|150|-0.2|2418|C
Testing child: KDKDPHDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
Ran -1.8m during 6039ms and crashed
RunInfo#1|KDKDPHDBEBLICDECGJONFNMIJOBKPELBPPDIMALF|150|-1.8|6039|C
Crossover: Finding the fittest neighbor
Runner: BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH| fitness: -0.1
Fittest Neighbor: FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE| fitness:
Testing child: BBNBGGGFEIEJPGHEIJFNNIFFHNHDNIPOAMOFKIJH
Ran -0.9m during 3068ms and crashed
RunInfo#1|BBNBGGGFEIEJPGHEIJFNNIFFHNHDNIPOAMOFKIJH|150|-0.9|3068|C
Testing child: FGBCHFCKDFNIFFAOOJMAKCKJKJCGCFLHDGJDAJLE
Ran 0.0m during 3031ms and crashed
0.8
2.3
7.4
14.7
46
RunInfo#1|FGBCHFCKDFNIFFAOOJMAKCKJKJCGCFLHDGJDAJLE|150|0.0|3031|C
Crossover: Finding the fittest neighbor
Runner: FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE| fitness: 14.7
Fittest Neighbor: HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF| fitness:
Testing child: FGBCHFGFEIEJIBHEPGMAKCKJKJCGCFLHDGJDAJLE
Ran 0.4m during 3184ms and crashed
RunInfo#1|FGBCHFGFEIEJIBHEPGMAKCKJKJCGCFLHDGJDAJLE|150|0.4|3184|C
Testing child: HCEJNGFOIIHMPGHEIJFJMLNIHKNIFPCDEHPGHEGF
Ran 0.3m during 3940ms and crashed
RunInfo#1|HCEJNGFOIIHMPGHEIJFJMLNIHKNIFPCDEHPGHEGF|150|0.3|3940|C
Crossover: Finding the fittest neighbor
Runner: HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF| fitness: 0.6
Fittest Neighbor: FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE| fitness:
Testing child: HCEJNGFOIIHMIBHEPGMAKCKJHKNIFPCDEHPGHEGF
Ran 0.5m during 9374ms and crashed
RunInfo#1|HCEJNGFOIIHMIBHEPGMAKCKJHKNIFPCDEHPGHEGF|150|0.5|9374|C
Testing child: FGBCHFGFEIEJPGHEIJFJMLNIKJCGCFLHDGJDAJLE
Ran 0.1m during 3652ms and crashed
RunInfo#1|FGBCHFGFEIEJPGHEIJFJMLNIKJCGCFLHDGJDAJLE|150|0.1|3652|C
Crossover: Finding the fittest neighbor
Runner: BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG| fitness: 0.8
Fittest Neighbor: FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID| fitness:
Testing child: BOONAKFELJAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
Ran 1.0m during 2843ms and crashed
RunInfo#1|BOONAKFELJAKFOEKNHADBNOPOLJFBCFDPLMHLIDG|150|1.0|2843|C
Testing child: FMFDKJOPKHHNOKOJMKHFEBIPAFPJFLJINCLEHJID
Ran 0.6m during 28440ms and crashed
RunInfo#1|FMFDKJOPKHHNOKOJMKHFEBIPAFPJFLJINCLEHJID|150|0.6|28440|C
Crossover: Finding the fittest neighbor
Runner: FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID| fitness: 2.3
Fittest Neighbor: BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG| fitness:
Testing child: FMFDKJOPLJHNOOEKNHAFEBIPAFPJFLJINCLEHJID
Ran -1.2m during 28657ms and crashed
RunInfo#1|FMFDKJOPLJHNOOEKNHAFEBIPAFPJFLJINCLEHJID|150|-1.2|28657|C
Testing child: BOONAKFEKHAKFKOJMKHDBNOPOLJFBCFDPLMHLIDG
Ran 1.1m during 3028ms and crashed
RunInfo#1|BOONAKFEKHAKFKOJMKHDBNOPOLJFBCFDPLMHLIDG|150|1.1|3028|C
Crossover: Finding the fittest neighbor
Runner: MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH| fitness: 0.2
Fittest Neighbor: FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID| fitness:
Testing child: MMFDKJOPLJHNOKOJMKHFBLDPMBOAFNECIIFEDDIH
Ran -0.4m during 6522ms and crashed
RunInfo#1|MMFDKJOPLJHNOKOJMKHFBLDPMBOAFNECIIFEDDIH|150|-0.4|6522|C
Testing child: FHFAMAGMGFDAIDHFBOFAEBIPAFPJFLJINCLEHJID
Ran 0.5m during 3000ms and crashed
RunInfo#1|FHFAMAGMGFDAIDHFBOFAEBIPAFPJFLJINCLEHJID|150|0.5|3000|C
Crossover: Finding the fittest neighbor
Runner: JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI| fitness: 1.3
Fittest Neighbor: NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI| fitness:
Testing child: JBBBKGEJCHNGBAEGLFFMENJKILOAECDFCPPHNHCI
Ran 1.1m during 3936ms and crashed
RunInfo#1|JBBBKGEJCHNGBAEGLFFMENJKILOAECDFCPPHNHCI|150|1.1|3936|C
Testing child: NCMDJBBOMPECHCDNFNFCOBDJIKAMJIMMPODIKHKI
Ran 0.7m during 2718ms and crashed
RunInfo#1|NCMDJBBOMPECHCDNFNFCOBDJIKAMJIMMPODIKHKI|150|0.7|2718|C
Crossover: Finding the fittest neighbor
Runner: PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB| fitness: 0.3
Fittest Neighbor: FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE| fitness:
Testing child: PJCAMLJLIAJHNFHFIJMAKCKJKJCGCFLHDGLFDAGB
Ran 0.6m during 3345ms and crashed
RunInfo#1|PJCAMLJLIAJHNFHFIJMAKCKJKJCGCFLHDGLFDAGB|150|0.6|3345|C
Testing child: FGBCHFGFEIEJPGHEIAMEJCOJHILDHPMGBIJDAJLE
Ran 4.6m during 55042ms and crashed
RunInfo#1|FGBCHFGFEIEJPGHEIAMEJCOJHILDHPMGBIJDAJLE|150|4.6|55042|C
Crossover: Finding the fittest neighbor
Runner: PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE| fitness: -0.5
0.6
14.7
2.3
0.8
2.3
0.9
14.7
47
Fittest Neighbor: BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG| fitness:
Testing child: PDDGIFELMCOPFOEKICAPAJOGHMEFLPIPFGIFPKEE
Ran 0.0m during 2280ms and crashed
RunInfo#1|PDDGIFELMCOPFOEKICAPAJOGHMEFLPIPFGIFPKEE|150|0.0|2280|C
Testing child: BOONAKFEKHAKCAJHNHADBNOPOLJFBCFDPLMHLIDG
Ran 0.8m during 2851ms and crashed
RunInfo#1|BOONAKFEKHAKCAJHNHADBNOPOLJFBCFDPLMHLIDG|150|0.8|2851|C
Crossover: Finding the fittest neighbor
Runner: GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG| fitness: 1.3
Fittest Neighbor: LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD| fitness:
Testing child: GHOPIHFBMLEGGJEIMFMEIOLGHHDDLAFPHKMKPENG
Ran 1.5m during 4352ms and crashed
RunInfo#1|GHOPIHFBMLEGGJEIMFMEIOLGHHDDLAFPHKMKPENG|150|1.5|4352|C
Testing child: LNICNHMBBJKMJOLICDAIKCJFMALNEKGHIDKHPMBD
Ran 1.4m during 3469ms and crashed
RunInfo#1|LNICNHMBBJKMJOLICDAIKCJFMALNEKGHIDKHPMBD|150|1.4|3469|C
Crossover: Finding the fittest neighbor
Runner: ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD| fitness: 0.2
Fittest Neighbor: FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID| fitness:
Testing child: ODFPGMPHNHPGODGFLPHFEBIPAFPJFLJPCHIOIALD
Ran 0.2m during 2584ms and crashed
RunInfo#1|ODFPGMPHNHPGODGFLPHFEBIPAFPJFLJPCHIOIALD|150|0.2|2584|C
Testing child: FMFDKJOPLJHNOKOJMKNDIBFONDOBDPBINCLEHJID
Ran 0.9m during 2546ms and crashed
RunInfo#1|FMFDKJOPLJHNOKOJMKNDIBFONDOBDPBINCLEHJID|150|0.9|2546|C
Crossover: Finding the fittest neighbor
Runner: FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA| fitness: 0.1
Fittest Neighbor: NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI| fitness:
Testing child: FOFBBIGGMPECHCBHEEALBPIEEMCALBLMDLEIIOPA
Ran -0.4m during 5738ms and crashed
RunInfo#1|FOFBBIGGMPECHCBHEEALBPIEEMCALBLMDLEIIOPA|150|-0.4|5738|C
Testing child: NCMDJBBODAHKKKDNFNFMENJKILOAECDFCPPHKHKI
Ran 0.9m during 3184ms and crashed
RunInfo#1|NCMDJBBODAHKKKDNFNFMENJKILOAECDFCPPHKHKI|150|0.9|3184|C
Crossover: Finding the fittest neighbor
Runner: NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI| fitness: 0.9
Fittest Neighbor: HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG| fitness:
Testing child: NCMDJBBLBNJEHNLNNKFFFDDMJBOAECDFCPPHKHKI
Ran 0.4m during 2728ms and crashed
RunInfo#1|NCMDJBBLBNJEHNLNNKFFFDDMJBOAECDFCPPHKHKI|150|0.4|2728|C
Testing child: HMLIIKHOMPECHCDNFNFMENJKILGPEOJBIKOKFHPG
Ran 0.6m during 7123ms and crashed
RunInfo#1|HMLIIKHOMPECHCDNFNFMENJKILGPEOJBIKOKFHPG|150|0.6|7123|C
Crossover: Finding the fittest neighbor
Runner: MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH| fitness: 0.8
Fittest Neighbor: MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI| fitness:
Testing child: MKIGDONODMMKLLPKPNEGMFMJCBLHBNFKEDPHJODH
Ran -0.3m during 2584ms and crashed
RunInfo#1|MKIGDONODMMKLLPKPNEGMFMJCBLHBNFKEDPHJODH|150|-0.3|2584|C
Testing child: MAIKPBHCMONBCLOIIBLFEDLCONEONEOGBIMADIKI
Ran 1.7m during 4669ms and crashed
RunInfo#1|MAIKPBHCMONBCLOIIBLFEDLCONEONEOGBIMADIKI|150|1.7|4669|C
Crossover: Finding the fittest neighbor
Runner: GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN| fitness: 0.6
Fittest Neighbor: GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG| fitness:
Testing child: GHOPIKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
Ran 0.4m during 6188ms and crashed
RunInfo#1|GHOPIKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN|150|0.4|6188|C
Testing child: GLEGEHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
Ran 0.5m during 1950ms and crashed
RunInfo#1|GLEGEHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG|150|0.5|1950|C
Crossover: Finding the fittest neighbor
Runner: LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD| fitness: 3.3
Fittest Neighbor: GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG| fitness:
Testing child: LNICNHFBMLEGGOLICDAIKCJFMALNEKGHIDKHPMBD
Ran 0.1m during 3184ms and crashed
0.8
3.3
2.3
0.9
1.6
1.2
1.3
1.3
48
RunInfo#1|LNICNHFBMLEGGOLICDAIKCJFMALNEKGHIDKHPMBD|150|0.1|3184|C
Testing child: GHOPIHMBBJKMJJEIMFMEIOLGHHDDLAFPHKMKPENG
Ran 1.6m during 3034ms and crashed
RunInfo#1|GHOPIHMBBJKMJJEIMFMEIOLGHHDDLAFPHKMKPENG|150|1.6|3034|C
Crossover: Finding the fittest neighbor
Runner: AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK| fitness: 0.1
Fittest Neighbor: LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD| fitness:
Testing child: AHNOGEBHEAOJNGIKBFMIKCJFMALNEKGHIDOIBMEK
Ran -0.1m during 5732ms and crashed
RunInfo#1|AHNOGEBHEAOJNGIKBFMIKCJFMALNEKGHIDOIBMEK|150|-0.1|5732|C
Testing child: LNICNHMBBJKGGOLICDAPANNFDBEGJADOBJKHPMBD
Ran 2.1m during 8117ms and crashed
RunInfo#1|LNICNHMBBJKGGOLICDAPANNFDBEGJADOBJKHPMBD|150|2.1|8117|C
Crossover: Finding the fittest neighbor
Runner: HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN| fitness: 0.4
Fittest Neighbor: KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF| fitness:
Testing child: HLEPGHBFBPHIKHFOGJONFNMIJPKIMMACNLPHFFBN
Ran 1.4m during 3452ms and crashed
RunInfo#1|HLEPGHBFBPHIKHFOGJONFNMIJPKIMMACNLPHFFBN|150|1.4|3452|C
Testing child: KDAAJGDBEBLICDECLFCILJHPJOBKPELBPPDIMALF
Ran 0.5m during 2417ms and crashed
RunInfo#1|KDAAJGDBEBLICDECLFCILJHPJOBKPELBPPDIMALF|150|0.5|2417|C
Crossover: Finding the fittest neighbor
Runner: HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG| fitness: 1.6
Fittest Neighbor: MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI| fitness:
Testing child: HMLIPBHCMNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
Ran 0.5m during 3945ms and crashed
RunInfo#1|HMLIPBHCMNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG|150|0.5|3945|C
Testing child: MAIKIKHLBONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
Ran 0.1m during 2545ms and crashed
RunInfo#1|MAIKIKHLBONBCLOIIBEGMFMJCBLHNEOGBIMADIKI|150|0.1|2545|C
Crossover: Finding the fittest neighbor
Runner: MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI| fitness: 1.2
Fittest Neighbor: HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG| fitness:
Testing child: MAIKPBHCMONBCLOIIKFFFDDMJBGPNEOGBIMADIKI
Ran 1.3m during 3936ms and crashed
RunInfo#1|MAIKPBHCMONBCLOIIKFFFDDMJBGPNEOGBIMADIKI|150|1.3|3936|C
Testing child: HMLIIKHLBNJEHNLNNBEGMFMJCBLHEOJBIKOKFHPG
Ran 0.3m during 4536ms and crashed
RunInfo#1|HMLIIKHLBNJEHNLNNBEGMFMJCBLHEOJBIKOKFHPG|150|0.3|4536|C
Crossover: Finding the fittest neighbor
Runner: LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK| fitness: -0.6
Fittest Neighbor: LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD| fitness:
Testing child: LDGCPHPNKBJGGOLIHBPBCJMPFNBAAMIMAFOLHNFK
Ran -0.5m during 2161ms and crashed
RunInfo#1|LDGCPHPNKBJGGOLIHBPBCJMPFNBAAMIMAFOLHNFK|150|-0.5|2161|C
Testing child: LNICNHMBBJKIBGNHCDAIKCJFMALNEKGHIDKHPMBD
Ran 0.4m during 5288ms and crashed
RunInfo#1|LNICNHMBBJKIBGNHCDAIKCJFMALNEKGHIDKHPMBD|150|0.4|5288|C
Crossover: Finding the fittest neighbor
Runner: PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO| fitness: 0.7
Fittest Neighbor: LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD| fitness:
Testing child: PAJOHCDCALGEHOLICDAIKCJFMAPBCGDDINOEKNIO
Ran 0.7m during 3182ms and crashed
RunInfo#1|PAJOHCDCALGEHOLICDAIKCJFMAPBCGDDINOEKNIO|150|0.7|3182|C
Testing child: LNICNHMBBJKGGJOAMLOGOANGLKLNEKGHIDKHPMBD
Ran 0.3m during 6508ms and crashed
RunInfo#1|LNICNHMBBJKGGJOAMLOGOANGLKLNEKGHIDKHPMBD|150|0.3|6508|C
Crossover: Finding the fittest neighbor
Runner: AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB| fitness: 0.1
Fittest Neighbor: KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF| fitness:
Testing child: AFLDPICDABLICDNAEHGBEBMHJFBCPFKAHKOLNGKB
Ran 0.2m during 2584ms and crashed
RunInfo#1|AFLDPICDABLICDNAEHGBEBMHJFBCPFKAHKOLNGKB|150|0.2|2584|C
Testing child: KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
Ran 7.3m during 60197ms and was stopped
3.3
7.4
1.2
1.6
3.3
3.3
7.4
49
RunInfo#1|KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF|150|7.3|60197|S
Child 2 fit enough to join next generation: KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF|7.3
Replacing: AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB|0.1
Crossover: Finding the fittest neighbor
Runner: KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF| fitness: 7.4
Fittest Neighbor: AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP| fitness: 0.9
Testing child: KDAAJGDILCOFKPECGJONFNMIJOBKPELBPPDIMALF
Ran 0.3m during 3485ms and crashed
RunInfo#1|KDAAJGDILCOFKPECGJONFNMIJOBKPELBPPDIMALF|150|0.3|3485|C
Testing child: AIACHFMBEBLICDACJGNDGHBDJOALDPJCMJMMLPBP
Ran 0.7m during 2428ms and crashed
RunInfo#1|AIACHFMBEBLICDACJGNDGHBDJOALDPJCMJMMLPBP|150|0.7|2428|C
Crossover: Finding the fittest neighbor
Runner: AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP| fitness: 0.9
Fittest Neighbor: KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF| fitness: 7.4
Testing child: AIACJGDBEBLICDECJGNDGHBDJOALDPJCMJMMLPBP
Ran 1.3m during 11008ms and crashed
RunInfo#1|AIACJGDBEBLICDECJGNDGHBDJOALDPJCMJMMLPBP|150|1.3|11008|C
Testing child: KDAAHFMILCOFKPACGJONFNMIJOBKPELBPPDIMALF
Ran 0.5m during 2167ms and crashed
RunInfo#1|KDAAHFMILCOFKPACGJONFNMIJOBKPELBPPDIMALF|150|0.5|2167|C
Crossover: Finding the fittest neighbor
Runner: EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA| fitness: 0.5
Fittest Neighbor: FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE| fitness: 14.7
Testing child: EMEIBHBHOAPFNGJCLHMAKCKJKJCGCFLHKFIMDFNA
Ran 0.2m during 2718ms and crashed
RunInfo#1|EMEIBHBHOAPFNGJCLHMAKCKJKJCGCFLHKFIMDFNA|150|0.2|2718|C
Testing child: FGBCHFGFEIEJPGHEIJEDBOBMHKMKKBLCDGJDAJLE
Ran 0.3m during 3653ms and crashed
RunInfo#1|FGBCHFGFEIEJPGHEIJEDBOBMHKMKKBLCDGJDAJLE|150|0.3|3653|C
Crossover: Finding the fittest neighbor
Runner: NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI| fitness: 1.2
Fittest Neighbor: PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO| fitness: 0.7
Testing child: NNGFPMOLIKMEHJOAMLOGOANGLKPBCGOOFNJEKPBI
Ran 1.4m during 2733ms and crashed
RunInfo#1|NNGFPMOLIKMEHJOAMLOGOANGLKPBCGOOFNJEKPBI|150|1.4|2733|C
Testing child: PAJOHCDCALGEMHNINGAEMCLMHNACKFDDINOEKNIO
Ran 0.5m during 3351ms and crashed
RunInfo#1|PAJOHCDCALGEMHNINGAEMCLMHNACKFDDINOEKNIO|150|0.5|3351|C
########## Generation 2 ##########
…
// log continues through 79 generations
50
APPENDIX C. SAMPLE GENERATION SUMMARY LOG
//This log contains the first 10 generations of the Configuration 3 run shown in Figure
//12 and featured in Appendix B
##########
1 ) -0.9
2 )
0.0
3 ) -0.2
4 ) -0.1
5 ) 14.7
6 )
0.6
7 )
0.8
8 )
2.3
9 )
0.2
10)
1.3
11)
0.3
12) -0.5
13)
1.3
14)
0.2
15)
0.1
16)
0.9
17)
0.8
18)
0.6
19)
3.3
20)
0.1
21)
0.4
22)
1.6
23)
1.2
24) -0.6
25)
0.7
26)
0.1
27)
7.4
28)
0.9
29)
0.5
30)
1.2
Generation
##########
1 )
2 )
3 )
4 )
5 )
6 )
7 )
8 )
9 )
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
23)
24)
-0.9
0.0
-0.2
-0.1
14.7
0.6
0.8
2.3
0.2
1.3
0.3
-0.5
1.3
0.2
0.1
0.9
0.8
0.6
3.3
0.1
0.4
1.6
1.2
-0.6
Generation 1
##########
| DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
| LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC
| GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
| BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
| FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
| HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
| BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
| FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
| MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH
| JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
| PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB
| PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE
| GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
| ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
| FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA
| NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
| MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH
| GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
| LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD
| AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK
| HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
| LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
| PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO
| AFLDPICDAMCALMNAEHGBEBMHJFBCPFKAHKOLNGKB
| KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA
| NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
1 Average Fitness: 1.3066669
Generation 2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########
DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
LBBANMKDEKMFINFPDIEOOAFMGLHFIOILAFPHDPIC
GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
MHFAMAGMGFDAIDHFBOFABLDPMBOAFNECIIFEDDIH
JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB
PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE
GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA
NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH
GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD
AHNOGEBHEAOJNGIKBFMPANNFDBEGJADOBJOIBMEK
HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
51
25)
0.7
26)
7.3
27)
7.4
28)
0.9
29)
0.5
30)
1.2
Generation
##########
1 ) -0.9
2 )
9.7
3 ) -0.2
4 ) -0.1
5 ) 14.7
6 )
0.6
7 )
0.8
8 )
2.3
9 )
1.1
10)
1.3
11)
0.3
12) -0.5
13)
1.3
14)
0.2
15)
0.1
16)
0.9
17)
0.8
18)
0.6
19)
3.3
20)
5.1
21)
0.4
22)
1.6
23)
1.2
24) -0.6
25) 12.8
26)
7.3
27)
7.4
28)
0.9
29) 12.6
30)
1.2
Generation
##########
1 )
2 )
3 )
4 )
5 )
6 )
7 )
8 )
9 )
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
21)
22)
-0.9
10.6
-0.2
-0.1
14.7
0.6
0.8
2.3
1.1
1.3
9.6
3.9
1.3
0.2
2.3
0.9
7.3
5.5
8.1
10.9
0.4
1.6
| PAJOHCDCALGEHJOAMLOGOANGLKPBCGDDINOEKNIO
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| EMEIBHBHOAPFNGJCLHEDBOBMHKMKKBLCKFIMDFNA
| NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
2 Average Fitness: 1.5466669
Generation 3
##########
| DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
| KDAAJGDBEMCALMECGJEOOAFMGLHFIOILAFPHDPIC
| GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
| BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
| FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
| HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
| BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
| FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
| FMFAMAGMGFDAIDHJMKHFEBIPAFPJFLJINCLEHJID
| JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
| PJCAMLJLIAJHNFHFIAMEJCOJHILDHPMGBILFDAGB
| PDDGIFELMCOPCAJHICAPAJOGHMEFLPIPFGIFPKEE
| GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
| ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
| FOFBBIGGDAHKKKBHEEALBPIEEMCALBLMDLEIIOPA
| NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
| MKIGDONODMMKLLPKPNLFEDLCONEOBNFKEDPHJODH
| GLEGEKMLIGAGMLLNAAAOPFOOKMKMKBNOIDHOAGMN
| LNICNHMBBJKGGOLICDAIKCJFMALNEKGHIDKHPMBD
| ADAAJGDBEMCALMECGFMPANNFDBEGJADOBJOIBMEK
| HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
| LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
| KDAAJGDBEMCALMOAMLOGOANGLKPBCELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| FGBCHFGFEIPFNGJCLHEDKCKJKJCGCFLHDGJDAJLE
| NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
3 Average Fitness: 2.8733332
Generation 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########
DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
HCEJNGFOIIHMIBHEPGFJMLNIHKNIFPCDEHPGHEGF
BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
FMFDKJOPLJHNOKOJMKHFEBIPAFPJFLJINCLEHJID
FMFAMAGMGFDAIDHJMKHFEBIPAFPJFLJINCLEHJID
JBBBKGEJCHNGBAEGLFFCOBDJIKAMJIMMPODINHCI
FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
MKIGDONODMMKLLPKPNLGMFMJCBEOBNFKEDPHJODH
GHOPEKMLIGEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
KDAAJGDBEMCALMOAMLOIKCJFMALNEKGHIDKIMALF
KDAAJGDBEMCALMECGFMNFNMIJOBKPELBPPDIMALF
HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
52
23)
1.2
24) -0.6
25) 12.8
26) 10.7
27)
7.4
28)
0.9
29) 15.5
30)
1.2
Generation
##########
1 ) -0.9
2 ) 10.6
3 ) -0.2
4 ) -0.1
5 ) 16.1
6 ) 13.1
7 )
0.8
8 )
8.5
9 )
5.3
10) 14.5
11) 15.8
12)
3.9
13)
1.3
14)
0.2
15)
2.3
16)
0.9
17)
7.3
18)
5.5
19)
8.1
20) 10.9
21)
0.4
22)
1.6
23)
1.2
24)
6.9
25) 12.8
26) 10.7
27) 11.6
28)
0.9
29) 15.5
30) 14.2
Generation
##########
1 )
2 )
3 )
4 )
5 )
6 )
7 )
8 )
9 )
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
20)
-0.9
10.6
-0.2
16.1
16.1
16.0
0.8
8.5
5.7
14.5
15.8
3.9
7.0
0.2
2.3
0.9
7.3
12.4
11.3
10.9
| MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
| LDGCPHPNKBJIBGNHHBPBCJMPFNBAAMIMAFOLHNFK
| KDAAJGDBEMCALMOAMLOGOANGLKPBCELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| KDAAJGDBEBLICDECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| FGBCHFGFEIEFNGJCLHEDKCKJKJCGCFLHDGJDAJLE
| NNGFPMOLIKMEMHNINGAEMCLMHNACKFOOFNJEKPBI
4 Average Fitness: 4.3766665
Generation 5
##########
| DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
| BBNBGGCKDFNIFFAOOJFNNIFFHNHDNIPOAMOFKIJH
| FGBCHFGFEIEFNGJCLHMDKCKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEJPGHEIJFJMLKJKJCGCFLHDGJDAJLE
| BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
| KDAAJGDBEMCALMECMKHNFNMIJOBKPELBPPDIMALF
| FMFAMAGMGFDAIKBJMKHFEBIPAFPJFLJINCLEHJID
| FGBCHFGFEIEJPGHEIFFCOBDJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
| BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
| GHOPIHFBMLEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
| ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
| FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
| NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
| MKIGDONODMMKLLPKPNLGMFMJCBEOBNFKEDPHJODH
| GHOPEKMLIGEMJJEIMFMEIOLGHHDDLAFPHKMKPENG
| KDAAJGDBEMCALMOAMLOIKCJFMALNEKGHIDKIMALF
| KDAAJGDBEMCALMECGFMNFNMIJOBKPELBPPDIMALF
| HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| MAIKPBHCMONBCLOIIBEGMFMJCBLHNEOGBIMADIKI
| KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
| KDAAJGDBEMCALMOAMLOGOANGLKPBCELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| FGBCHFGFEIEFNGJCLHEDKCKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJINGAEMCLJKJCGCFLHDGJDAJLE
5 Average Fitness: 6.6566668
Generation 6
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########
DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
FGBCHFGFEIEFNGJCLHMNKCKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHMDKCKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHMDKCKJKJCGCFLHDGJDAJLE
BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
KDAAJGDBEMCALMECMKHNFNMIJOBKPELBPPDIMALF
FMFAMAGMGFEJPGHEIFFFEBIPAFPJFLJINCLEHJID
FGBCHFGFEIEJPGHEIFFCOBDJKJCGCFLHDGJDAJLE
FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
KDAAJGDBEMEMJJEIMFMEIOLFMALNEKGHIDKIMALF
ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
MKIGDONODMMKLLPKPNLGMFMJCBEOBNFKEDPHJODH
GHOPEKMLIMMKLLPKPNLEIOLGHHDDLAFPHKMKPENG
KDAAJGDBEMCALMOAMLOGKCJFMALNEKGHIDKIMALF
KDAAJGDBEMCALMECGFMNFNMIJOBKPELBPPDIMALF
53
21)
0.4
22)
1.6
23)
7.9
24)
6.9
25) 12.8
26) 11.5
27) 11.6
28)
0.9
29) 15.5
30) 21.0
Generation
##########
1 ) -0.9
2 ) 10.6
3 ) -0.2
4 ) 16.1
5 ) 16.1
6 ) 20.2
7 )
0.8
8 )
8.5
9 )
5.7
10) 17.9
11) 15.8
12)
3.9
13) 12.0
14)
0.2
15)
2.3
16)
0.9
17)
9.8
18) 13.5
19) 11.3
20) 10.9
21)
9.8
22)
1.6
23) 11.1
24)
6.9
25) 16.4
26) 11.5
27) 11.6
28)
0.9
29) 20.3
30) 21.0
Generation
##########
1 )
2 )
3 )
4 )
5 )
6 )
7 )
8 )
9 )
10)
11)
12)
13)
14)
15)
16)
17)
18)
16.1
10.6
14.9
18.9
16.1
20.2
7.7
8.5
12.8
17.9
15.8
3.9
12.0
0.2
2.3
0.9
16.3
13.5
| HLEPGHBFBPHIKHFOLFCILJHPJPKIMMACNLPHFFBN
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| FGBCHFGFEIEFNGJCIBEGMFMJCBLHNEOGBIMDAJLE
| KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
| KDAAJGDBEMCALMOAMLOGOANGLKPBCELBPPDIMALF
| KDAAJGDBEMCALMEAMLOGOANGLKPBPELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| FGBCHFGFEIEFNGJCLHEDKCKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
6 Average Fitness: 8.309999
Generation 7
##########
| DLMPDJINICNLKLMPHDMHIJNHFOPCOOJMPPODGJGH
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| GBKDPHFADPDJFNNMGINMJCJIEJDOLHLLFEBOAAMC
| FGBCHFGFEIEFNGJCLHMNKCKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHMDKCKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| BOONAKFEKHAKFOEKNHADBNOPOLJFBCFDPLMHLIDG
| KDAAJGDBEMCALMECMKHNFNMIJOBKPELBPPDIMALF
| FMFAMAGMGFEJPGHEIFFFEBIPAFPJFLJINCLEHJID
| FGBCHFGFEIEFNGJCLFFCOBDJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
| BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
| GHOPEKMLEMEMJJEIMFMEIOLFMALNEKGHIDKIMALF
| ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
| FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
| NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
| FGBCHFGFEIEJPGHKPNLGMFMJCBEOBNFHDGJDAJLE
| GHOPEKNODMMKLLPKPNLGMFMGHHDDLAFPHKMKPENG
| KDAAJGDBEMCALMOAMLOGKCJFMALNEKGHIDKIMALF
| KDAAJGDBEMCALMECGFMNFNMIJOBKPELBPPDIMALF
| KDAAJGDBEMCALMECGJCILJHPJOBKPELBPPDIMALF
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| FGBCHFGFEIEFNGJCIBEGMFMJCBLHNFLHDGJDAJLE
| KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
| FGBCHFGBEMCALGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMEAMLOGOANGLKPBPELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| AIACHFMILCOFKPACJGNDGHBDJOALDPJCMJMMLPBP
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
7 Average Fitness: 9.55
Generation 8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########
FGBCHFGFEIEFNGMPHDEEMCLJKJCGCFLHDGJDAJLE
KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
FGBCHFGFEIEFNNNMGHMNKCKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHMDKCKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
GHOPEKMEKHAKFOEIMFMEIOLFMALNEKGHIDKIMALF
KDAAJGDBEMCALMECMKHNFNMIJOBKPELBPPDIMALF
FGBCHFGMGFEJPGHEIFFFEBIPKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLFFCOBDJKJCGCFLHDGJDAJLE
FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
GHOPEKMLEMEMJJEIMFMEIOLFMALNEKGHIDKIMALF
ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
FGBCHFGFEIEJPGHKPNLAKCKJKJCGCFLHDGJDAJLE
GHOPEKNODMMKLLPKPNLGMFMGHHDDLAFPHKMKPENG
54
19) 15.1
20) 10.9
21) 10.3
22)
1.6
23) 18.6
24)
6.9
25) 16.4
26) 11.5
27) 11.6
28) 17.1
29) 20.3
30) 21.0
Generation
##########
1 ) 19.2
2 ) 12.3
3 ) 18.0
4 ) 18.9
5 ) 22.4
6 ) 20.2
7 ) 10.1
8 )
8.5
9 ) 12.8
10) 18.3
11) 15.8
12)
3.9
13) 12.0
14)
0.2
15)
2.3
16)
0.9
17) 20.2
18) 17.2
19) 16.0
20) 14.0
21) 10.3
22)
1.6
23) 21.0
24)
6.9
25) 19.1
26) 11.5
27) 11.9
28) 17.5
29) 20.6
30) 21.0
Generation
##########
1 )
2 )
3 )
4 )
5 )
6 )
7 )
8 )
9 )
10)
11)
12)
13)
14)
15)
16)
21.9
13.3
19.6
22.1
22.4
20.2
20.4
14.8
12.8
18.4
18.4
3.9
12.2
0.2
2.3
0.9
| KDAAJGDBEMCALGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMECGFMNFNMIJOBKPELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
| FGBCHFGBEMCALGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMEAMLOGOANGLKPBPELBPPDIMALF
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| FGBCHFGFEIOFKPACJHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
8 Average Fitness: 12.33
Generation 9
##########
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGMPHDEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| GHOPEKMEKHEKFOEIMFMEIOLFMALNEKGHIDKIMALF
| KDAAJGDBEMCALMECMKHNFNMIJOBKPELBPPDIMALF
| FGBCHFGMGFEJPGHEIFFFEBIPKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEJPGHEIJMAKCKJKJCGCFLHDGJDAJLE
| BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
| GHOPEKMLEMEMJJEIMFMEIOLFMALNEKGHIDKIMALF
| ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
| FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
| NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEJPGHKPNLAKCKJKJCGCFLHDGJDAJLE
| FGBCHFGBEMCALGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALGJCLFMNFNMIKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
| HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| KDAAJGDBEMCALMEAMLOGOANGLKPBPELBPPDIMALF
| FGBCHFGFEMCALMECJHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
| FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
9 Average Fitness: 13.486667
Generation 10
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJPHDEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEIOLFMALNEKGHDGJDAJLE
KDAAJFGMGFEJPGECMKHNFNMIJOBKPELBPPDIMALF
FGBCHFGMGFEJPGHEIFFFEBIPKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLFFCOBKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
BOONAKELMCOPCAJHICAPBNOPOLJFBCFDPLMHLIDG
GHOPHFGFEIEMJJEIMFMEIOLFMALNEKGHIDKIMALF
ODFPGMPHNHPGODGFLPNDIBFONDOBDPBPCHIOIALD
FOFBBIGGDAHKKKBJMKHFEBIPAFPALBLMDLEIIOPA
NCMDJBBOMPECHCDNFNFMENJKILOAECDFCPPHKHKI
55
17) 20.2
18) 17.2
19) 19.3
20) 14.0
21) 10.3
22)
1.6
23) 21.0
24)
6.9
25) 19.1
26) 14.9
27) 11.9
28) 20.4
29) 20.6
30) 21.0
Generation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEJPGHKPNLAKCKJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
KDAAJGDBEMCALGJCLFMNFNMIKJCGCFLHDGJDAJLE
KDAAJGDBEMCALMECGJONFNMIJOBKPELBPPDIMALF
HMLIIKHLBNJEHNLNNKFFFDDMJBGPEOJBIKOKFHPG
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
KDAAJGDBEMCALMOAMBPBCJJFMALNEKGHIDKIMALF
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
KGBCHFGFEIEALMEAMLOGOANGLKPBPELBPPDIMALF
FGBCHFGFEMCALMECJHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
FGBCHFGFEIEFNGJCLHEEMCLJKJCGCFLHDGJDAJLE
Average Fitness: 14.739999
56
BIBLIOGRAPHY
[1]
B. Foddy. QWOP [Flash Game] (2008). Retrieved 6 November 2013 from
http://www.foddy.net/Athletics.html
[2]
C. Wheeler. QWOP and Simulation Design, Pt. 2. The Rules on the Field blog. Posted on
10 July 2012. Retrieved 6 November 2013 from
http://therulesonthefield.com/2012/07/10/qwop-and-simulation-design-pt-2/
[3]
T. Jakobsen. Advanced Character Physics. IO Interactive, Denmark. Posted on 10 April
2008. Retrieved 6 November 2013 from
http://web.archive.org/web/20080410171619/http://www.teknikus.dk/tj/gdc2001.htm
[4]
G. Brodman and R. Volstad. QWOP Learning. Department of Computer Science,
Stanford University, 2012. Retrieved 6 November 2013 from
http://cs229.stanford.edu/proj2012/BrodmanVoldstad-QWOPLearning.pdf
[5]
L. Vaucher. Genetically Engineered QWOP (Part 1). Slow Frog blog. Posted on 31
March 2011. Retrieved 6 November 2013 from
http://slowfrog.blogspot.com/2011/03/genetically-engineered-qwop-part-1.html
[6]
D. Whitley and J. Kauth. GENITOR: A Different Genetic Algorithm. Department of
Computer Science, Colorado State University, 1988.
[7]
H. Muhlenbein and T. Mahnig. A comparison of stochastic local search and population
based search. Proceedings of the Congress on Evolutionary Computation (CEC ‘02),
1:255-260, May 2002.
[8]
G. Parker, D. Braun, and I. Cyliax. Evolving Hexapod Gaits Using a Cyclic Genetic
Algorithm. In Proceedings of the IASTED International Conference on Artificial
Intelligence and Soft Computing, 1997.
57
[9]
J. Clune, B. Beckmann, C. Ofria, and R. Pennock. Evolving Coordinated Quadruped
Gaits with the HyperNEAT Generative Encoding. In Proceedings of the 2009 IEEE
Congress on Evolutionary Computation (CEC ‘09). May 2009.
[10]
K. Wolff and P. Nordin. Evolution of Efficient Gait With An Autonomous Biped Robot
Using Visual Feedback. 2001 Genetic and Evolutionary Computation Conference Late
Breaking Papers, page 482—489. San Francisco, California, September 2001
[11]
R. Ramachandra. Fastest 100m run, QWOP (flash game). Guinnes World Records.
Retrieved 6 November 2013 from
http://challengers.guinnessworldrecords.com/challenges/160-fastest-100m-run-qwopflash-game