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){
|
||||||
|
};
|
||||||
|
}
|
||||||
|
*/
|