EVERYTHING
BIN
assets/all_c.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
assets/all_d.png
Normal file
After Width: | Height: | Size: 395 B |
BIN
assets/bun.png
Normal file
After Width: | Height: | Size: 449 B |
BIN
assets/grim.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
assets/prober.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
assets/tft.png
Normal file
After Width: | Height: | Size: 416 B |
BIN
css/FuturaHandwritten.ttf
Executable file
BIN
css/paper@2x.png
Normal file
After Width: | Height: | Size: 14 KiB |
67
css/slides.css
Normal file
|
@ -0,0 +1,67 @@
|
|||
body{
|
||||
margin:0;
|
||||
overflow: hidden;
|
||||
|
||||
background: url('paper@2x.png');
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: calc(100% - 60px);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
#footer{
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background: #222;
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/******* SLIDESHOW *******/
|
||||
/*************************/
|
||||
|
||||
#slideshow{
|
||||
/*background: #bada55;*/
|
||||
border: 1px solid rgba(0,0,0,0.2);
|
||||
width:960px;
|
||||
height:540px;
|
||||
|
||||
/* Center this thing */
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top:0; left:0; right:0; bottom:0;
|
||||
|
||||
}
|
||||
#slideshow .object{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.fader{
|
||||
-webkit-transition: opacity 0.3s ease-in-out;
|
||||
-mos-transition: opacity 0.3s ease-in-out;
|
||||
-ms-transition: opacity 0.3s ease-in-out;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/*************************/
|
||||
/***** SLIDE SELECT ******/
|
||||
/*************************/
|
||||
|
||||
#select{
|
||||
width:100%;
|
||||
text-align: center;
|
||||
padding-top: 15px;
|
||||
}
|
||||
#select .dot{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 40px;
|
||||
border: 1px solid #fff;
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#select .dot[selected]{
|
||||
background: #fff;
|
||||
}
|
56
index.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!doctype>
|
||||
<html>
|
||||
<head>
|
||||
<title>The Evolution of Trust</title>
|
||||
<link rel="stylesheet" href="css/slides.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="slideshow"></div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="select"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- Libraries -->
|
||||
<script src="js/lib/helpers.js"></script>
|
||||
<script src="js/lib/minpubsub.src.js"></script>
|
||||
<script src="js/lib/q.js"></script>
|
||||
<script src="js/lib/pixi.min.js"></script>
|
||||
|
||||
<!-- Core Engine -->
|
||||
<script src="js/core/Slideshow.js"></script>
|
||||
<script src="js/core/SlideSelect.js"></script>
|
||||
<script src="js/core/Button.js"></script>
|
||||
<script src="js/core/WordBox.js"></script>
|
||||
|
||||
<!-- Simulations -->
|
||||
<script src="js/sims/SillyPixi.js"></script>
|
||||
<script src="js/sims/TournamentSim.js"></script>
|
||||
|
||||
<!-- Main Code -->
|
||||
<script src="js/main.js"></script>
|
||||
<script>
|
||||
var slideshow, slideSelect;
|
||||
window.onload = function(){
|
||||
|
||||
// Slideshow
|
||||
slideshow = new Slideshow({
|
||||
dom: $("#slideshow"),
|
||||
slides: slides
|
||||
});
|
||||
|
||||
// Slide Select
|
||||
slideSelect = new SlideSelect({
|
||||
dom: $("#select"),
|
||||
slides: slides
|
||||
});
|
||||
|
||||
// First slide!
|
||||
slideshow.nextSlide();
|
||||
//slideshow.gotoSlide("intro3");
|
||||
|
||||
};
|
||||
</script>
|
32
js/core/Button.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
function Button(config){
|
||||
|
||||
var self = this;
|
||||
self.id = config.id;
|
||||
|
||||
// Create DOM
|
||||
var button = document.createElement("button");
|
||||
button.className = "object";
|
||||
button.classList.add("fader");
|
||||
self.dom = button;
|
||||
|
||||
// Customize DOM
|
||||
button.style.left = config.x+"px";
|
||||
button.style.top = config.y+"px";
|
||||
button.innerHTML = config.text;
|
||||
|
||||
// On click...
|
||||
button.onclick = function(){
|
||||
publish(config.message);
|
||||
};
|
||||
|
||||
// Add...
|
||||
self.add = function(INSTANT){
|
||||
return _addFade(self, INSTANT);
|
||||
};
|
||||
|
||||
// Remove...
|
||||
self.remove = function(INSTANT){
|
||||
return _removeFade(self, INSTANT);
|
||||
};
|
||||
|
||||
}
|
46
js/core/SlideSelect.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
function SlideSelect(config){
|
||||
|
||||
var self = this;
|
||||
self.config = config;
|
||||
|
||||
// DOM
|
||||
self.dom = config.dom;
|
||||
|
||||
// Slides
|
||||
self.slides = config.slides;
|
||||
|
||||
// Create a dot, and onclick
|
||||
self.addDot = function(slide){
|
||||
var dot = new SlideSelectDot(slide);
|
||||
self.dom.appendChild(dot.dom);
|
||||
};
|
||||
|
||||
// Populate dots
|
||||
for(var i=0; i<slides.length; i++) self.addDot(slides[i]);
|
||||
|
||||
}
|
||||
|
||||
function SlideSelectDot(slide){
|
||||
|
||||
var self = this;
|
||||
self.slide = slide;
|
||||
|
||||
// DOM
|
||||
self.dom = document.createElement("div");
|
||||
self.dom.className = "dot";
|
||||
|
||||
// On Click
|
||||
self.dom.onclick = function(){
|
||||
publish("slideshow/goto", [slide.id]);
|
||||
};
|
||||
|
||||
// Listen to when the slide changes
|
||||
subscribe("slideshow/slideChange", function(id){
|
||||
if(id==slide.id){
|
||||
self.dom.setAttribute("selected","yes");
|
||||
}else{
|
||||
self.dom.removeAttribute("selected");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
105
js/core/Slideshow.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
function Slideshow(config){
|
||||
|
||||
var self = this;
|
||||
self.config = config;
|
||||
|
||||
// DOM
|
||||
self.dom = config.dom;
|
||||
|
||||
// Slide information
|
||||
self.slides = config.slides;
|
||||
|
||||
// Reset: INITIAL VARIABLES
|
||||
self.reset = function(){
|
||||
self.dom.innerHTML = "";
|
||||
self.slideIndex = -1;
|
||||
self.currentSlide = null;
|
||||
};
|
||||
self.reset();
|
||||
|
||||
// Go to next slide
|
||||
self.nextSlide = function(INSTANT){
|
||||
|
||||
// Update the information
|
||||
if(self.slideIndex >= self.slides.length-1) return;
|
||||
self.slideIndex++;
|
||||
self.currentSlide = self.slides[self.slideIndex];
|
||||
|
||||
// Remove whatever
|
||||
var remove = self.currentSlide.remove || [];
|
||||
var promisesToRemove = [];
|
||||
for(var i=0; i<remove.length; i++){
|
||||
var promiseToRemove = self.removeObject(remove[i], INSTANT);
|
||||
if(promiseToRemove) promisesToRemove.push(promiseToRemove);
|
||||
}
|
||||
|
||||
// After removing, add whatever
|
||||
var addObjects = function(){
|
||||
var add = self.currentSlide.add || [];
|
||||
for(var i=0; i<add.length; i++) self.addObject(add[i], INSTANT);
|
||||
};
|
||||
if(INSTANT || promisesToRemove.length==0) addObjects();
|
||||
else Q.all(promisesToRemove).then(addObjects);
|
||||
|
||||
// Send out message!
|
||||
publish("slideshow/slideChange", [self.currentSlide.id]);
|
||||
|
||||
};
|
||||
|
||||
// Subscribe to "next slide" message...
|
||||
subscribe("slideshow/next", function(){
|
||||
self.nextSlide();
|
||||
});
|
||||
|
||||
// FORCE go to a certain slide
|
||||
self.gotoSlide = function(id){
|
||||
|
||||
// Go ALL the way to the past
|
||||
self.reset();
|
||||
|
||||
// And just move all the way forward, what a hack.
|
||||
// TODO: a more efficient one that looks at id's FIRST.
|
||||
self.nextSlide(true);
|
||||
while(self.currentSlide.id != id){
|
||||
self.nextSlide(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Subscribe to the "force goto" message...
|
||||
subscribe("slideshow/goto", function(id){
|
||||
self.gotoSlide(id);
|
||||
});
|
||||
|
||||
// Objects!
|
||||
self.objects = {};
|
||||
|
||||
// Add Object
|
||||
self.addObject = function(objectConfig, INSTANT){
|
||||
|
||||
// Create object
|
||||
var Classname = window[objectConfig.type];
|
||||
var obj = new Classname(objectConfig);
|
||||
obj.slideshow = self;
|
||||
|
||||
// Remember it
|
||||
self.objects[objectConfig.id] = obj;
|
||||
|
||||
// Add it for real!
|
||||
return obj.add(INSTANT); // return a possible promise
|
||||
|
||||
};
|
||||
|
||||
// Remove Object
|
||||
self.removeObject = function(objectConfig, INSTANT){
|
||||
|
||||
// Find it...
|
||||
var obj = self.objects[objectConfig.id];
|
||||
|
||||
// Remove from memory & DOM
|
||||
delete self.objects[objectConfig.id];
|
||||
return obj.remove(INSTANT); // return a possible promise
|
||||
|
||||
};
|
||||
|
||||
}
|
29
js/core/WordBox.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
function WordBox(config){
|
||||
|
||||
var self = this;
|
||||
self.id = config.id;
|
||||
|
||||
// Create DOM
|
||||
var words = document.createElement("div");
|
||||
words.className = "object";
|
||||
words.classList.add("fader");
|
||||
self.dom = words;
|
||||
|
||||
// Customize DOM
|
||||
words.style.left = config.x+"px";
|
||||
words.style.top = config.y+"px";
|
||||
words.style.width = config.width+"px";
|
||||
words.style.height = config.height+"px";
|
||||
words.innerHTML = config.text;
|
||||
|
||||
// Add...
|
||||
self.add = function(INSTANT){
|
||||
return _addFade(self, INSTANT);
|
||||
};
|
||||
|
||||
// Remove...
|
||||
self.remove = function(INSTANT){
|
||||
return _removeFade(self, INSTANT);
|
||||
};
|
||||
|
||||
}
|
42
js/lib/helpers.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
// Pi is for unwashed plebians
|
||||
Math.TAU = 2*Math.PI;
|
||||
|
||||
// The poor man's jQuery
|
||||
var $ = function(query){
|
||||
return document.querySelector(query);
|
||||
};
|
||||
|
||||
// Add & Remove INSTANTLY
|
||||
var _add = function(self){
|
||||
self.slideshow.dom.appendChild(self.dom);
|
||||
};
|
||||
var _remove = function(self){
|
||||
self.slideshow.dom.removeChild(self.dom);
|
||||
};
|
||||
|
||||
// Add & Remove... with FADE
|
||||
var _addFade = function(self, INSTANT){
|
||||
if(INSTANT){
|
||||
_add(self);
|
||||
}else{
|
||||
self.dom.style.opacity = 0;
|
||||
_add(self);
|
||||
setTimeout(function(){
|
||||
self.dom.style.opacity = 1;
|
||||
},10);
|
||||
}
|
||||
};
|
||||
var _removeFade = function(self, INSTANT){
|
||||
if(INSTANT){
|
||||
_remove(self);
|
||||
}else{
|
||||
var deferred = Q.defer();
|
||||
self.dom.style.opacity = 0;
|
||||
setTimeout(function(){
|
||||
_remove(self);
|
||||
deferred.resolve();
|
||||
},300);
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
95
js/lib/minpubsub.src.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*!
|
||||
* MinPubSub
|
||||
* Copyright(c) 2011 Daniel Lamb <daniellmb.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
(function (context) {
|
||||
var MinPubSub = {};
|
||||
|
||||
// the topic/subscription hash
|
||||
var cache = context.c_ || {}; //check for 'c_' cache for unit testing
|
||||
|
||||
MinPubSub.publish = function ( /* String */ topic, /* Array? */ args) {
|
||||
// summary:
|
||||
// Publish some data on a named topic.
|
||||
// topic: String
|
||||
// The channel to publish on
|
||||
// args: Array?
|
||||
// The data to publish. Each array item is converted into an ordered
|
||||
// arguments on the subscribed functions.
|
||||
//
|
||||
// example:
|
||||
// Publish stuff on '/some/topic'. Anything subscribed will be called
|
||||
// with a function signature like: function(a,b,c){ ... }
|
||||
//
|
||||
// publish('/some/topic', ['a','b','c']);
|
||||
|
||||
var subs = cache[topic],
|
||||
len = subs ? subs.length : 0;
|
||||
|
||||
//can change loop or reverse array if the order matters
|
||||
while (len--) {
|
||||
subs[len].apply(context, args || []);
|
||||
}
|
||||
};
|
||||
|
||||
MinPubSub.subscribe = function ( /* String */ topic, /* Function */ callback) {
|
||||
// summary:
|
||||
// Register a callback on a named topic.
|
||||
// topic: String
|
||||
// The channel to subscribe to
|
||||
// callback: Function
|
||||
// The handler event. Anytime something is publish'ed on a
|
||||
// subscribed channel, the callback will be called with the
|
||||
// published array as ordered arguments.
|
||||
//
|
||||
// returns: Array
|
||||
// A handle which can be used to unsubscribe this particular subscription.
|
||||
//
|
||||
// example:
|
||||
// subscribe('/some/topic', function(a, b, c){ /* handle data */ });
|
||||
|
||||
if (!cache[topic]) {
|
||||
cache[topic] = [];
|
||||
}
|
||||
cache[topic].push(callback);
|
||||
return [topic, callback]; // Array
|
||||
};
|
||||
|
||||
MinPubSub.unsubscribe = function ( /* Array */ handle, /* Function? */ callback) {
|
||||
// summary:
|
||||
// Disconnect a subscribed function for a topic.
|
||||
// handle: Array
|
||||
// The return value from a subscribe call.
|
||||
// example:
|
||||
// var handle = subscribe('/some/topic', function(){});
|
||||
// unsubscribe(handle);
|
||||
|
||||
var subs = cache[callback ? handle : handle[0]],
|
||||
callback = callback || handle[1],
|
||||
len = subs ? subs.length : 0;
|
||||
|
||||
while (len--) {
|
||||
if (subs[len] === callback) {
|
||||
subs.splice(len, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// UMD definition to allow for CommonJS, AMD and legacy window
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
// CommonJS, just export
|
||||
module.exports = exports = MinPubSub;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
// AMD support
|
||||
define(function () {
|
||||
return MinPubSub;
|
||||
});
|
||||
} else if (typeof context === 'object') {
|
||||
// If no AMD and we are in the browser, attach to window
|
||||
context.publish = MinPubSub.publish;
|
||||
context.subscribe = MinPubSub.subscribe;
|
||||
context.unsubscribe = MinPubSub.unsubscribe;
|
||||
}
|
||||
|
||||
})(this.window);
|
21
js/lib/pixi.min.js
vendored
Normal file
2076
js/lib/q.js
Normal file
68
js/main.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
var slides = [
|
||||
|
||||
// SIM
|
||||
{
|
||||
id: "sim",
|
||||
add:[
|
||||
{id:"tournament", type:"TournamentSim", x:0, y:20}
|
||||
]
|
||||
},
|
||||
|
||||
// Intro
|
||||
{
|
||||
id: "intro0",
|
||||
add:[
|
||||
{id:"button", type:"Button", x:550, y:200, width:100, height:100, text:"NEXT SLIDE", message:"slideshow/next"},
|
||||
]
|
||||
},
|
||||
|
||||
// Intro 1
|
||||
{
|
||||
id: "intro1",
|
||||
add:[
|
||||
{id:"wordbox1", type:"WordBox", x:500, y:0, width:100, height:200, text:"foo bar foo bar foo bar"},
|
||||
]
|
||||
},
|
||||
|
||||
// Intro 2
|
||||
{
|
||||
id: "intro2",
|
||||
add:[
|
||||
{id:"wordbox2", type:"WordBox", x:500, y:100, width:100, height:200, text:"even more foo bar"},
|
||||
{id:"silly", type:"SillyPixi", x:700, y:50, width:200, height:200}
|
||||
]
|
||||
},
|
||||
|
||||
// Intro 3
|
||||
{
|
||||
id: "intro3",
|
||||
remove:[
|
||||
{id:"wordbox1"},
|
||||
{id:"wordbox2"}
|
||||
],
|
||||
add:[
|
||||
{id:"wordbox3", type:"WordBox", x:500, y:0, width:100, height:200, text:"aaAAAAHHHHhhh"}
|
||||
]
|
||||
},
|
||||
|
||||
// Intro 4
|
||||
{
|
||||
id: "intro4",
|
||||
remove:[
|
||||
{id:"wordbox3"}
|
||||
]
|
||||
},
|
||||
|
||||
// Intro 5
|
||||
{
|
||||
id: "intro5",
|
||||
remove:[
|
||||
{id:"button"},
|
||||
{id:"silly"}
|
||||
],
|
||||
add:[
|
||||
{id:"the_end", type:"WordBox", x:600, y:300, width:100, height:200, text:"THE END"}
|
||||
]
|
||||
}
|
||||
|
||||
];
|
38
js/sims/SillyPixi.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
function SillyPixi(config){
|
||||
|
||||
var self = this;
|
||||
self.id = config.id;
|
||||
|
||||
// APP
|
||||
var app = new PIXI.Application(config.width, config.height);
|
||||
self.dom = app.view;
|
||||
|
||||
// DOM
|
||||
self.dom.className = "object";
|
||||
self.dom.classList.add("fader");
|
||||
self.dom.style.left = config.x+"px";
|
||||
self.dom.style.top = config.y+"px";
|
||||
|
||||
// BUNNY
|
||||
var bunny = PIXI.Sprite.fromImage("assets/bun.png")
|
||||
bunny.anchor.set(0.5);
|
||||
bunny.x = app.renderer.width/2;
|
||||
bunny.y = app.renderer.height/2;
|
||||
app.stage.addChild(bunny);
|
||||
|
||||
// ANIMATE
|
||||
app.ticker.add(function(delta) {
|
||||
bunny.rotation += 0.1 * delta;
|
||||
});
|
||||
|
||||
// Add...
|
||||
self.add = function(INSTANT){
|
||||
return _addFade(self, INSTANT);
|
||||
};
|
||||
|
||||
// Remove...
|
||||
self.remove = function(INSTANT){
|
||||
return _removeFade(self, INSTANT);
|
||||
};
|
||||
|
||||
}
|
320
js/sims/TournamentSim.js
Normal file
|
@ -0,0 +1,320 @@
|
|||
function TournamentSim(config){
|
||||
|
||||
var self = this;
|
||||
self.id = config.id;
|
||||
|
||||
// APP
|
||||
var app = new PIXI.Application(500, 500, {transparent:true});
|
||||
self.dom = app.view;
|
||||
|
||||
// DOM
|
||||
self.dom.className = "object";
|
||||
//self.dom.classList.add("fader");
|
||||
self.dom.style.left = config.x+"px";
|
||||
self.dom.style.top = config.y+"px";
|
||||
self.dom.style.border = "1px solid rgba(0,0,0,0.2)";
|
||||
|
||||
// CREATE A RING OF AGENTS
|
||||
var AGENTS = [
|
||||
{strategy:"all_c", count:20},
|
||||
{strategy:"all_d", count:5},
|
||||
{strategy:"grim", count:2},
|
||||
{strategy:"tft", count:2},
|
||||
];
|
||||
|
||||
var _convertCountToArray = function(countList){
|
||||
var array = [];
|
||||
for(var i=0; i<AGENTS.length; i++){
|
||||
var A = AGENTS[i];
|
||||
var strategy = A.strategy;
|
||||
var count = A.count;
|
||||
for(var j=0; j<count; j++){
|
||||
array.push(strategy);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
self.populateAgents = function(){
|
||||
|
||||
// Clear EVERYTHING
|
||||
app.stage.removeChildren();
|
||||
|
||||
// Convert to an array
|
||||
self.agents = _convertCountToArray(AGENTS);
|
||||
|
||||
// Put 'em in a ring
|
||||
var count = 0;
|
||||
for(var i=0; i<self.agents.length; i++){
|
||||
|
||||
// Position
|
||||
var angle = (i/self.agents.length)*Math.TAU - Math.TAU/4;
|
||||
var x = Math.cos(angle)*200 + 250;
|
||||
var y = Math.sin(angle)*200 + 250;
|
||||
|
||||
// What kind of agent?
|
||||
var strategy = self.agents[i];
|
||||
var agent = new TournamentAgent({x:x, y:y, strategy:strategy});
|
||||
app.stage.addChild(agent.graphics);
|
||||
|
||||
// Remember me!
|
||||
self.agents[i] = agent;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
self.populateAgents();
|
||||
|
||||
////////////////////////////////////
|
||||
// EVOLUTION ///////////////////////
|
||||
////////////////////////////////////
|
||||
|
||||
// Play one tournament
|
||||
self.playOneTournament = function(){
|
||||
PD.playOneTournament(self.agents, 10);
|
||||
self.agents.sort(function(a,b){
|
||||
if(a.coins==b.coins) return (Math.random()<0.5); // if equal, random
|
||||
return a.coins-b.coins; // otherwise, sort as per usual
|
||||
});
|
||||
};
|
||||
|
||||
// Get rid of X worst
|
||||
self.eliminateBottom = function(X){
|
||||
|
||||
// The worst X
|
||||
var worst = self.agents.slice(0,X);
|
||||
|
||||
// For each one, subtract from AGENTS count, and KILL.
|
||||
for(var i=0; i<worst.length; i++){
|
||||
var badAgent = worst[i];
|
||||
var config = AGENTS.find(function(config){
|
||||
return config.strategy==badAgent.strategyName;
|
||||
});
|
||||
config.count--; // remove one
|
||||
app.stage.removeChild(badAgent.graphics); // get rid of this // TODO: KILL?
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Reproduce the top X
|
||||
self.reproduceTop = function(X){
|
||||
|
||||
// The top X
|
||||
var best = self.agents.slice(self.agents.length-X, self.agents.length);
|
||||
|
||||
// For each one, add to AGENTS count
|
||||
for(var i=0; i<best.length; i++){
|
||||
var goodAgent = best[i];
|
||||
var config = AGENTS.find(function(config){
|
||||
return config.strategy==goodAgent.strategyName;
|
||||
});
|
||||
config.count++; // ADD one
|
||||
}
|
||||
|
||||
// ...and REPOPULATE THE THING
|
||||
self.populateAgents();
|
||||
|
||||
};
|
||||
|
||||
// HACK: ALL AT ONCE
|
||||
self.ALL_AT_ONCE = function(){
|
||||
self.playOneTournament();
|
||||
self.eliminateBottom(5);
|
||||
self.reproduceTop(5);
|
||||
};
|
||||
setInterval(self.ALL_AT_ONCE, 100);
|
||||
|
||||
// ANIMATE
|
||||
/*app.ticker.add(function(delta) {
|
||||
bunny.rotation += 0.1 * delta;
|
||||
});*/
|
||||
|
||||
// Add...
|
||||
self.add = function(INSTANT){
|
||||
return _add(self);
|
||||
};
|
||||
|
||||
// Remove...
|
||||
self.remove = function(INSTANT){
|
||||
return _remove(self);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function TournamentAgent(config){
|
||||
|
||||
var self = this;
|
||||
self.strategyName = config.strategy;
|
||||
|
||||
// Number of coins
|
||||
self.coins = 0;
|
||||
self.addPayoff = function(payoff){
|
||||
self.coins += payoff;
|
||||
self.updateScore();
|
||||
};
|
||||
|
||||
// What's the image?
|
||||
var g = new PIXI.Container();
|
||||
g.x = config.x;
|
||||
g.y = config.y;
|
||||
self.graphics = g;
|
||||
|
||||
// Body!
|
||||
var body = PIXI.Sprite.fromImage("assets/"+self.strategyName+".png");
|
||||
body.anchor.set(0.5);
|
||||
g.addChild(body);
|
||||
|
||||
// Score!
|
||||
var textStyle = new PIXI.TextStyle({
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 16,
|
||||
});
|
||||
var scoreText = new PIXI.Text("", textStyle);
|
||||
scoreText.anchor.x = 0.5;
|
||||
scoreText.x = 0;
|
||||
scoreText.y = -40;
|
||||
g.addChild(scoreText);
|
||||
self.updateScore = function(){
|
||||
scoreText.text = self.coins;
|
||||
};
|
||||
self.updateScore();
|
||||
|
||||
// What's the play logic?
|
||||
var LogicClass = window["Logic_"+self.strategyName];
|
||||
self.logic = new LogicClass();
|
||||
self.play = function(){
|
||||
return self.logic.play();
|
||||
};
|
||||
self.remember = function(other){
|
||||
self.logic.remember(other);
|
||||
};
|
||||
|
||||
// Reset!
|
||||
self.resetCoins = function(){
|
||||
self.coins = 0; // reset coins;
|
||||
self.updateScore();
|
||||
}
|
||||
self.resetLogic = function(){
|
||||
self.logic = new LogicClass(); // reset logic
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
var PD = {};
|
||||
PD.COOPERATE = "COOPERATE";
|
||||
PD.CHEAT = "CHEAT";
|
||||
|
||||
PD.P = 0; // punishment: neither of you get anything
|
||||
PD.S = -1; // sucker: you put in coin, other didn't.
|
||||
PD.R = 2; // reward: you both put 1 coin in, both got 3 back
|
||||
PD.T = 3; // temptation: you put no coin, got 3 coins anyway
|
||||
|
||||
PD.getPayoffs = function(move1, move2){
|
||||
if(move1==PD.CHEAT && move2==PD.CHEAT) return [PD.P, PD.P]; // both punished
|
||||
if(move1==PD.COOPERATE && move2==PD.CHEAT) return [PD.S, PD.T]; // sucker - temptation
|
||||
if(move1==PD.CHEAT && move2==PD.COOPERATE) return [PD.T, PD.S]; // temptation - sucker
|
||||
if(move1==PD.COOPERATE && move2==PD.COOPERATE) return [PD.R, PD.R]; // both rewarded
|
||||
};
|
||||
|
||||
PD.playOneGame = function(playerA, playerB){
|
||||
|
||||
var A = playerA.play();
|
||||
var B = playerB.play();
|
||||
|
||||
var payoffs = PD.getPayoffs(A,B);
|
||||
|
||||
playerA.remember(B);
|
||||
playerB.remember(A);
|
||||
|
||||
playerA.addPayoff(payoffs[0]);
|
||||
playerB.addPayoff(payoffs[1]);
|
||||
|
||||
};
|
||||
|
||||
PD.playRepeatedGame = function(playerA, playerB, turns){
|
||||
|
||||
// I've never met you before, let's pretend
|
||||
playerA.resetLogic();
|
||||
playerB.resetLogic();
|
||||
|
||||
// Play N turns
|
||||
for(var i=0; i<turns; i++){
|
||||
PD.playOneGame(playerA, playerB);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PD.playOneTournament = function(agents, turns){
|
||||
|
||||
// Reset everyone's coins
|
||||
for(var i=0; i<agents.length; i++){
|
||||
agents[i].resetCoins();
|
||||
}
|
||||
|
||||
// Round robin!
|
||||
for(var i=0; i<agents.length; i++){
|
||||
var playerA = agents[i];
|
||||
for(var j=i+1; j<agents.length; j++){
|
||||
var playerB = agents[j];
|
||||
PD.playRepeatedGame(playerA, playerB, turns);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
function Logic_tft(){
|
||||
var self = this;
|
||||
var otherMove = PD.COOPERATE;
|
||||
self.play = function(){
|
||||
return otherMove;
|
||||
};
|
||||
self.remember = function(other){
|
||||
otherMove = other;
|
||||
};
|
||||
}
|
||||
function Logic_grim(){
|
||||
var self = this;
|
||||
var everCheatedMe = false;
|
||||
self.play = function(){
|
||||
if(everCheatedMe) return PD.CHEAT;
|
||||
return PD.COOPERATE;
|
||||
};
|
||||
self.remember = function(other){
|
||||
if(other==PD.CHEAT) everCheatedMe=true;
|
||||
};
|
||||
}
|
||||
function Logic_all_d(){
|
||||
var self = this;
|
||||
self.play = function(){
|
||||
return PD.CHEAT;
|
||||
};
|
||||
self.remember = function(other){
|
||||
// nah
|
||||
};
|
||||
}
|
||||
function Logic_all_c(){
|
||||
var self = this;
|
||||
self.play = function(){
|
||||
return PD.COOPERATE;
|
||||
};
|
||||
self.remember = function(other){
|
||||
// nah
|
||||
};
|
||||
}
|
||||
/*
|
||||
function Logic_prober(){
|
||||
var self = this;
|
||||
self.play = function(){
|
||||
};
|
||||
self.remember = function(other){
|
||||
};
|
||||
}
|
||||
*/
|