deontologician / evofighters Goto Github PK
View Code? Open in Web Editor NEWGenetic evolution of little fighting AI's
Genetic evolution of little fighting AI's
So if one thought step took 100 instructions, and the other took 90, the 90 guy goes first. This would allow removing the -1 life for every so many instructions executed.
Mostly, I don't actually care what the all-time total of statistics are. What I really want is to track statistics over time.
The idea is that we have the saver thread from #47 that we'll dump these stats to, and it can write them to disk in some format that allows us to save every data point (probably should be efficient, append-only and be cap-able in size.
So at the beginning of an encounter, the generator is initialized with cycle(self.dna). In this way, we can avoid having to reinitialize the self.dna_cycler every fight (which I wanted to do), and also allow a more natural and encapsulated way to generate the next action of a guy. Also, we could pickle the creature directly, since it won't contain a cycle object!
This could also be used in conjunction with the fight context manager I want to make in issue #9
If they're hashable, we can keep them in a hashmap to memoize them. Obviously only thoughts that are compiled/reduced should be hashed. This would serve two purposes:
Does Rust have a weak hashmap? I could probably make one if not
Currently, mating is outside the purview of natural selection. It happens randomly and the only increased access to mating comes from being alive when the mating happens. This doesn't encourage competition, as all of the creatures tend to just stop fighting each other so they can soak up the sweet sweet rewards of living forever.
This enhancement would move mating from a separate phase into a single "encounter" phase, where creatures would encounter another creature and then decide whether to fight or mate (or both). I'd like to not program in rape explicitly, but at the same time, I don't think these creatures will be able to decide mutually to mate in their initial random states. Eventually they would be able to agree to a "mating ritual" etc, but initially we'll be counting on one of them having the idea to mate, and it being very unlikely the other one has the same idea at the same time.
Maybe a prisoner's dilemma tradeoff for mating?
Agree on mating: both share costs equally
One mates, the other does not mate: one who does not mate takes entire cost of mating
One mates, the other fights: Roll to see who wins?
Both don't mate: no mating happens
No more 22's and -14s
Also, fix gene_primer so that it splits on -1's again
I want to try doing arena allocations, or possibly sharing references to genes if possible (parent would pass an Rc pointer to children)
DNA = Vec(Gene)
Mutations would need to be rethought since not all genes are copied, new genes can be created.
Currently, the command line loop is a bit of a hack, it needs to be a list of commands and callbacks, rather than a massive elif tree.
-- Needs to support a help function
-- Needs to share common functionality in the same command (i.e. show this
and show that
should not have duplicated show code)
-- Needs to use readline so that we can press up and down and use regular line editing tricks
Currently using tuples. Timeit has indicated arrays are faster for what we're doing parsing dna
Right now everything is at the parent level in the creature struct, it should be nested for tidiness
Right now in the main sim loop we don't check time every round because it's a system call and is pretty slow. So as a guess, we wait 1000 events or so before checking the time. This may or may not be right, but in any case it should be smarter.
Basically, use shell output colors to show each element, rather than showing the number directly. This will give an easier visual inspection of the genome.
This is the main blocking requirement for Release 1.0.
All other issues have to be in service of this goal.
This involves both simplifying, and cycle detection, so we can pre-evaluate thoughts, and not have to parse them from scratch each time.
This should make it
Possible downsides:
Right now everyone uses the worst item (value 1). We need a way for a creature to combine his own items into a more energy dense item form.
Ideas:
Currently, the way I've been running the program has been to activate the virtualenv and then go into the EvoFighters directory and do python Arena.py
. This is less than optimal, as Arena.py doesn't stand out in any way and isn't very user friendly.
Best thing to do is modify setup.py to create an EvoFighters executable/script
Currently, the savefile is hardcoded, there are several improvements that need to be made:
Basically, we're polluting the module namespace by putting a bunch of variables in the main section.
Currently, the parsing code is really really repetitive and has lots of copy + pasting. This needs to be rectified.
Add more functions to reduce duplicated code in the parser
In order to get feeding into the adaptation, add a creature who is just a stand in to provide food with the following properties:
Killing the creature allows the creature to get the item, or the creature can just "take" the item during the encounter.
This should be an elegant solution to allowing the creatures to have heritable control over feeding behavior, but not distract them from their main goal of fighting! (Alternatives could have been some harvesting phase or something else)
Will need to do some checking to ensure it's never negative
Just need some unique id tag. Probably just use uuid for that
Looks like this isn't super feasible right now, but to track what kinds of options are out there:
I think if these projects get off the ground, it could be very feasible to move the main simulation code into a gpu kernel. The main issue at the moment is:
Essentially, a gene would have two versions, one from each parent, and when it simulates a thought, it would run "next valid" on both of them, returning the first valid value.
If two valid responses, we could come up with some non-commutative function to calculate which value wins
If they are the same response, obviously that would be returned.
Might want to be able to have the master thread control the feeder supply (not simply being max - real creatures). This would correspond to like "famine times" etc, in which things "get malthusian bruh"
use that for something more useful
Since live viewing of the simulation isn't currently possible in the Rust version (owing to poor signal handling libraries). We just save the state periodically.
What we need are tools to rip through the json file of the state and get stats the way the original python version did. It can even be written in python since it's just doing analytics and not the simulation
Describing how to run the program, and the commands that are available, as well as a rough overview of the application
Basic idea:
In the future, I may add a thread for a webserver
Creating initial population
Created 120001 creatures
Creatures: 118479thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', /checkout/src/liballoc/vec.rs:1561:14S: 5.0
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::print
at libstd/sys_common/backtrace.rs:68
at libstd/sys_common/backtrace.rs:57
2: std::panicking::default_hook::{{closure}}
at libstd/panicking.rs:380
3: std::panicking::rust_panic_with_hook
at libstd/panicking.rs:396
at libstd/panicking.rs:576
4: std::panicking::begin_panic
at libstd/panicking.rs:537
5: std::panicking::begin_panic_fmt
at libstd/panicking.rs:521
6: core::panicking::panic_fmt
at libstd/panicking.rs:497
at libcore/panicking.rs:71
7: core::panicking::panic_bounds_check
at libcore/panicking.rs:58
8: evofighters::dna::DNA::combine
9: evofighters::creatures::try_to_mate
10: evofighters::arena::do_round
11: evofighters::arena::simulate
12: evofighters::run_simulation
13: evofighters::main
14: std::rt::lang_start::{{closure}}
15: std::panicking::try::do_call
at libstd/rt.rs:59
at libstd/panicking.rs:479
16: std::rt::lang_start_internal
at libpanic_unwind/lib.rs:102
at libstd/panicking.rs:458
at libstd/panic.rs:358
at libstd/rt.rs:58
17: main
18: __libc_start_main
19: _start
Creatures: 30663, Feeders: 89337, F/C: 2.914, Mutations: 3039, Events: 3508611, Born: 30679, Eaten: 218597, kills: 62881, eps: 473102, err: -91.5%, FPS: 2.6
Currently, mating has a fixed cost in terms of items and/or life. I'd like it to be a bit more sophisticated along these lines:
mating_cost = 10
while mating_cost > 0 and self.alive:
if self.inv:
item = self.inv.pop()
mating_cost -= item + 1
else:
self.energy -= mating_cost
And if you kill yourself, you don't have a child.
Originally, the plan was for damage types to have a rock/paper/scissors scheme in terms of attack versus defense. Once the attack/defend/mate matrix was put in place, however, this plan fell by the wayside. That needs to be implemented again, taking into account attack vs. defense only.
|-------------+------+------+-------------|
| | fire | ice | electricity |
|-------------+------+------+-------------|
| fire | 0.33 | 0.66 | 1.0 |
| ice | 1.0 | 0.33 | 0.66 |
| electricity | 0.66 | 1.0 | 0.33 |
|-------------+------+------+-------------|
_______ _______ _ _
(_______) (_______|_) | | _
_____ _ _ ___ _____ _ ____| | _ | |_ ____ ____ ___
| ___) | | / _ \| ___) | |/ _ | || \| _)/ _ )/ ___)___)
| |____\ V / |_| | | | ( ( | | | | | |_( (/ /| | |___ |
|_______)_/ \___/|_| |_|\_|| |_| |_|\___)____)_| (___/
(_____|
Once issue #2 is completed, add a few more actions and triggers like:
random - generates a random number between -1 and 9
flee - escape the fight (whether fleeing works is a random roll weighted by respective energy levels)
mate - attempt to mate with the opponent
Once the simulation is multithreaded, we can decide to mix populations every so often with a concept of "epochs". Keeping them isolated and co-evolving, then mixing some together
No save file found, creating a new generation!
command> simulate
Traceback (most recent call last):
File "Arena.py", line 330, in <module>
sd.progress)
TypeError: generationer() takes at least 4 arguments (3 given)
Currently, the population goes off the rails once creatures realize they need to make love and not war. Mating needs to cost something so that there is a tradeoff and not an "always best" strategy of not fighting.
Thinking mating could cost one food or 5 life if there is no food.
This will be useful for almost nothing, but might make the code cleaner. The object of the with statement should be a newly initialized next_action generator from issue #8
I really don't want to make higher numbers than 9, so there'll need to be an 'extension' digit that means the next number signifies the actual code is in a second lookup table.
This will allow more conditions like:
Right now it is hell bent on making absolutely massive genes.
It should have a heuristic like "after 5 bases, there's a 1 in 10 chance it'll split the gene after each base. If it sees a -1, always split"
This should cut down on the "whole genome is one gene" problem that currently plagues the system.
Subcondition(Always(X))
->X
Currently, attributes are compared against absolute numbers in the dna, but comparisons could be changed to allow specification of attributes to compare against instead of a number. This would probably be most easily changed in the Compare non-terminal.
Really rich comparisons could work by adding a new non-terminal to comparisons that allows an attribute to be specified
Probably, instead of exhaustively listing attributes, we could do something along the lines of:
COMPARE :: inrange VAL VAL | lessthan VAL | greaterthan VAL | equalto VAL | notequalto VAL
VAL :: int (INT) | me ATTR | you ATTR
ATTR :: generation | kills | survived | matings | energy | signal
Settings need to stop being globally static, since we have to be able to save and load them from a file (currently they're being saved but being ignored when they're loaded again).
I think it's fine not to have a config file for this, but we should at least take command line args.
Probably should use lazy_static
or something? Maybe not.
Phases just artificially restrict how the selection process can occur. If feeding is integrated into encounters (#14), and fighting and mating are integrated (#5), then there is no real reason to maintain the phase distinction. Because of this, several things need to change:
Won: Encounters need not be "won" in the traditional sense if one is mating. Better to keep track of Kills directly.
Age: No longer means anything without distinct phases. We could add an "every X fights, increment all of the ages", but that is pretty superfluous. Keeping track of kills and encounters survived should serve any purpose age served.
Generation: This should now be a property of each individual creature, which is equivalent to the maximum generation of the parents plus one. Arguably, this change should have been made before, since all creatures in "a generation" are not necessarily the same number of descendants from the the first generation.
Currently, mating is the most effective way to kill another creature. There needs to be a cost to mating that doesn't involve killing the opponent so they are forced to actually use their attacks.
I am thinking if one does not have enough food, mating doesn't occur, but it doesn't damage anyone either
Currently, how many fights to have depends on the population size before the fights start occurring. I think the estimated number of fights needs to go down as the population goes down. So conceptually, we would have a percentage variable that always tells you how far along the fights are. Then every X deaths or so, the number of fights total is recalculated, and then the percentage is taken out of that. In this way, the percentage till done is always known, but the actual number of fights to have goes down and doesn't risk the current "catastrophic loss" situation, where fighters are very effective an quickly whittle down a huge population to a small one, but the total fights number keeps pitting them against each other.
This would also allow removal of the "10 population or less" failsafe, which is actually a terrible failsafe since the population is already dangerously low on genetic diversity at that point.
As part of timeline statistics:
This should give a good view over time of how genes change, when genes become more successful, and when they die out.
Currently, the parser spends a lot of time creating massive trees of contingencies that never get evaluated because an if branch goes another way higher up in the tree. It might make sense (and allow more flexible bots), for evaluation to occur at parse time, since that information is known. In this way, we could prune parse trees that aren't followed early on.
Right now, Arena.py is a big spaghetti mess due to it being the main script. It needs to be split off into separate functionalities before adding any further features.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.