Created
July 6, 2013 06:42
-
-
Save drusepth/5938924 to your computer and use it in GitHub Desktop.
Non-iterative prisoner's dilemma simulated with a basic genetic algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Generation 1 | |
Alice: 0.5 | |
Bob: 0.5 | |
Generation 2 | |
Alice: 0.9136221749087309 | |
Bob: 0.9048452243325479 | |
Generation 3 | |
Alice: 0.7525407199758025 | |
Bob: 0.7001147600768378 | |
Generation 4 | |
Alice: 0.6023520588331079 | |
Bob: 0.6319019029736853 | |
Generation 5 | |
Alice: 0.37688867843857393 | |
Bob: 0.5681285046340958 | |
Generation 6 | |
Alice: 0.3239342915239891 | |
Bob: 0.014626085061660354 | |
Generation 7 | |
Alice: 0 | |
Bob: 0 | |
Generation 8 | |
Alice: 0 | |
Bob: 0 | |
[...snip...] | |
Generation 997 | |
Alice: 0 | |
Bob: 0 | |
Generation 998 | |
Alice: 0 | |
Bob: 0 | |
Generation 999 | |
Alice: 0 | |
Bob: 0 | |
Generation 1000 | |
Alice: 0 | |
Bob: 0 | |
So... world peace? | |
--- | |
First encountered optimal solution at generation 2 | |
Stopped evolving at generation 7 | |
Final genes: | |
Alice decided to cooperate 0% of the time. | |
Bob decided to cooperate 0% of the time. | |
And faith in humanity is lost! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simulates the prisoner's dilemma with aa genetic algorithm powering the prisoner | |
// decision making, with the intent of evolving harmony and world peace. | |
// PRISONER'S DILEMMA: | |
// | |
// Create a prisoner who can make a decision based on a genetic trait. | |
var prisoner = function () { | |
var _public = {}, _protected = {}; | |
_public.genes = { | |
cooperation_likeliness: 0.50 // % | |
}; | |
_public.fitness = function (years_in_jail) { | |
return (1 / years_in_jail); // Less years in jail the better, of course | |
}; | |
// Make a decision on whether to cooperate (true) or defect (false) | |
_public.decision = function () { | |
return Math.random() <= _public.genes.cooperation_likeliness; | |
}; | |
// Breed with another prisoner (assuming the guards allow that kind of thing) | |
// and produce a new one | |
_public.breed_with = function(other_prisoner) { | |
var breed_type = Math.floor(Math.random() * 7); | |
// Sum and difference of parent cooperation likelinesses | |
var sum = _public.genes.cooperation_likeliness + other_prisoner.genes.cooperation_likeliness; | |
var delta = Math.abs(_public.genes.cooperation_likeliness - other_prisoner.genes.cooperation_likeliness); | |
var new_likeliness = 0.5; // Default value | |
switch (breed_type) { | |
case 0: // Average cooperation likeliness | |
new_likeliness = sum / 2; | |
break; | |
case 1: // Increase dad likeliness by delta | |
new_likeliness = _public.genes.cooperation_likeliness + delta; | |
break; | |
case 2: // Increase mom likeliness by delta | |
new_likeliness = other_prisoner.genes.cooperation_likeliness + delta; | |
break; | |
case 3: // Increase average likeliness by delta | |
new_likeliness = sum + delta; | |
break; | |
case 4: // Decrease dad likeliness by delta | |
new_likeliness = _public.genes.cooperation_likeliness - delta; | |
break; | |
case 5: // Decrease mom likeliness by delta | |
new_likeliness = other_prisoner.genes.cooperation_likeliness - delta; | |
break; | |
case 6: // Decrease average likeliness by delta | |
new_likeliness = sum - delta; | |
break; | |
default: // Disregard parents, go purely random | |
new_likeliness = Math.random(); | |
break; | |
} | |
// Go ahead and throw in some random fuzzing for funsies | |
new_likeliness += (Math.random(2) - 1) / 5; // [-0.2, 0.2) | |
// And lastly, bound on [0, 1] | |
new_likeliness = Math.min(new_likeliness, 1); | |
new_likeliness = Math.max(new_likeliness, 0); | |
var child = prisoner(); | |
child.genes.cooperation_likeliness = new_likeliness; | |
return child; // lol | |
}; | |
return _public; | |
}; | |
// Create a 0-player representation of the game that can be set up and played out | |
// without any further interaction. | |
var prisoners_dilemma = function(alice, bob) { | |
var _public = {}, _protected = {}; | |
_protected.alice = alice; | |
_protected.bob = bob; | |
_protected.game_result = function () { | |
return { | |
alice_cooperates: _protected.alice.decision(), | |
bob_cooperates: _protected.bob.decision() | |
}; | |
}; | |
_public.total_years_served = function () { | |
var years_served = { alice: 0, bob: 0 }; | |
var result = _protected.game_result(); | |
if (result.alice_cooperates) { | |
years_served.alice = (result.bob_cooperates ? 1 : 3); | |
years_served.bob = (result.bob_cooperates ? 1 : 0); | |
} else { | |
years_served.alice = (result.bob_cooperates ? 0 : 2); | |
years_served.bob = (result.bob_cooperates ? 3 : 2); | |
} | |
return years_served; | |
}; | |
return _public; | |
}; | |
var num_generations = 1000; | |
// Create some initial prisoners | |
var alice = prisoner(); | |
var bob = prisoner(); | |
var best_alice = alice; | |
var best_bob = bob; | |
// We're optimizing for *least* amount of years in prison here, so lets just | |
// assume we can do better than ten thousand years of incarceration. | |
var best_alice_score = 10000; // years | |
var best_bob_score = 10000; // years | |
// What generation we reached the peak of evolution | |
var generation_down_the_drain = -1; | |
// What generation we first hit the optimal solution | |
var generation_in_the_sky = -1; | |
for (var g = 0; g < num_generations; g++) { | |
print("Generation " + (g + 1)); | |
print("Alice: " + alice.genes.cooperation_likeliness); | |
print("Bob: " + bob.genes.cooperation_likeliness); | |
// Lets interrogate the prisoners 10 times (in different dimensions, | |
// of course), because while the genes guide their decisions, there is still | |
// some randomness in what they will actually say (because they're only human, | |
// after all!) | |
for (var i = 0; i < 10; i++) { | |
var interrogation = prisoners_dilemma(alice, bob); | |
var alice_score = alice.fitness(interrogation.total_years_served().alice); | |
var bob_score = bob.fitness(interrogation.total_years_served().bob); | |
// If Alice did her best this time... | |
if (alice_score < best_alice_score) { | |
best_alice_score = alice_score; | |
best_alice = alice; | |
} | |
// If Bob did his best this time... | |
if (bob_score < best_bob_score) { | |
best_bob_score = bob_score; | |
best_bob = bob; | |
} | |
// If we're at the optimal solution, make a note | |
if (alice_score == 1 && bob_score == 1 && generation_in_the_sky == -1) { | |
generation_in_the_sky = g + 1; | |
} | |
// Mark what generation it took to get to the "worst" situation (best for each party) | |
if (alice.genes.cooperation_likeliness == 0 && bob.genes.cooperation_likeliness == 0 && generation_down_the_drain == -1) { | |
generation_down_the_drain = g + 1; | |
} | |
} | |
// Otherwise, lets breed some new prisoners from the best dimension and spawn | |
// a new generation from them. | |
var child_alice = alice.breed_with(bob); | |
var child_bob = bob.breed_with(alice); | |
// Look at them, all grow'd up! | |
alice = child_alice; | |
bob = child_bob; | |
} | |
print("So... world peace?"); | |
print("---"); | |
print("First encountered optimal solution at " + (generation_in_the_sky == -1 ? "NEVER!" : "generation " + generation_in_the_sky)); | |
print("Stopped evolving at generation " + generation_down_the_drain); | |
print("Final genes:"); | |
print("Alice decided to cooperate " + (alice.genes.cooperation_likeliness * 100) + "% of the time."); | |
print("Bob decided to cooperate " + (bob.genes.cooperation_likeliness * 100) + "% of the time."); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment