diff --git a/TODO.md b/TODO.md index 001e76a..bcbd8fa 100644 --- a/TODO.md +++ b/TODO.md @@ -13,4 +13,6 @@ MINOR SHTUFF - Word box class less annoying - Refactoring, ugh - Draw: Pavlov, TF2T, Random -- a better handwritten font, with REAL bold & italics??? \ No newline at end of file +- a better handwritten font, with REAL bold & italics??? +- rename Tit For Tat, so it FEELS nicer??? also block peeps who already know the answer... // Copycat Copykitten +- rename all of 'em, really? \ No newline at end of file diff --git a/assets/sandbox_hats.png b/assets/sandbox_hats.png new file mode 100644 index 0000000..80a8548 Binary files /dev/null and b/assets/sandbox_hats.png differ diff --git a/assets/slider_bg.png b/assets/slider_bg.png new file mode 100644 index 0000000..fa49b3d Binary files /dev/null and b/assets/slider_bg.png differ diff --git a/assets/slider_knob.png b/assets/slider_knob.png new file mode 100644 index 0000000..ac22c7b Binary files /dev/null and b/assets/slider_knob.png differ diff --git a/css/slides.css b/css/slides.css index d45d1a0..e00a4fe 100644 --- a/css/slides.css +++ b/css/slides.css @@ -74,6 +74,10 @@ body{ .button{ z-index: 0; + -webkit-user-select: none; /* Chrome all / Safari all */ + -moz-user-select: none; /* Firefox all */ + -ms-user-select: none; /* IE 10+ */ + user-select: none; } .button #background{ position: absolute; @@ -177,6 +181,44 @@ body{ .incdec > .incdec_control[arrow=down]{ bottom:-35px; background-position:-40px 0px; } .incdec > .incdec_control[arrow=down]:hover{ background-position:-60px 0px; } +.slider{ + position: absolute; + height: 40px; +} +.slider > div{ + position: absolute; +} +.slider > .slider_bg{ + top:0; + width:100%; height:30px; + background: url(../assets/slider_bg.png); + background-size: auto 100%; +} +.slider > .slider_knob{ + top:0; + width:30px; height:30px; + background: url(../assets/slider_knob.png); + background-size: 100% 100%; +} + +.sandbox_pop{ + position: absolute; +} +.sandbox_pop>div{ + position: absolute; +} +.sandbox_pop_icon{ + width: 40px; + height: 40px; + background: url(../assets/sandbox_hats.png); + background-size: auto 100%; +} +.sandbox_pop_label{ + font-size: 18px; + width: 150px; + top: 8px; + left: 50px; +} /*************************/ /***** SLIDE SELECT ******/ diff --git a/index.html b/index.html index 4c0bc97..558995e 100644 --- a/index.html +++ b/index.html @@ -32,6 +32,7 @@ + diff --git a/js/core/Slider.js b/js/core/Slider.js new file mode 100644 index 0000000..b55a354 --- /dev/null +++ b/js/core/Slider.js @@ -0,0 +1,113 @@ +/************************************** +{ + x:0, y:0, width:433, + min:1, max:25, step:1, + message: "rules/turns" +} +**************************************/ +function Slider(config){ + + var self = this; + self.id = config.id; + + // Create DOM + var dom = document.createElement("div"); + dom.className = "slider"; + dom.style.left = config.x+"px"; + dom.style.top = config.y+"px"; + dom.style.width = config.width+"px"; + self.dom = dom; + + // Background + var bg = document.createElement("div"); + bg.className = "slider_bg"; + dom.appendChild(bg); + + // Knob + var knob = document.createElement("div"); + knob.className = "slider_knob"; + dom.appendChild(knob); + + // Set value + self.value = 0; + var _paramToValue = function(param){ + var value = config.min + (config.max-config.min)*param; + value = Math.round(value/config.step)*config.step; + return value; + }; + var _valueToParam = function(value){ + var param = (value-config.min)/(config.max-config.min); // to (0-1) + return param; + }; + self.setParam = function(param){ + + // Bounds + var value = config.min + (config.max-config.min)*param; + value = Math.round(value/config.step)*config.step; + self.value = value; + + // DOM + knob.style.left = self.value*config.width-15; + + }; + self.setValue = function(value){ + + // Set + self.value = value; + + // DOM with param + var param = _valueToParam(self.value); + knob.style.left = param*(config.width-30); + + }; + if(config.message) subscribe(config.message, self.setValue); + + // Mouse events + var _isDragging = false; + var _offsetX = 0; + var _mouseToParam = function(event){ + + // Mouse to Param to Value + var param = (event.clientX - _offsetX - dom.getBoundingClientRect().left - 8)/(config.width-30); + if(param<0) param=0; + if(param>1) param=1; + var value = _paramToValue(param); + + // Publish these changes! (only if ACTUALLY changed) + if(self.value != value){ + if(config.message) publish(config.message, [value]); + if(config.onchange) config.onchange(value); + } + + }; + dom.addEventListener("mousedown",function(event){ + if(config.onselect) config.onselect(); + _mouseToParam(event); + _isDragging = true; + _offsetX = 0; + },false); + knob.addEventListener("mousedown",function(event){ + _isDragging = true; + if(config.onselect) config.onselect(); + _offsetX = event.clientX - knob.getBoundingClientRect().left; + },false); + window.addEventListener("mousemove",function(event){ + if(_isDragging) _mouseToParam(event); + },false); + window.addEventListener("mouseup",function(){ + _isDragging = false; + },false); + + //////////////////////////////////////// + + // Add... + self.add = function(INSTANT){ + return _add(self, INSTANT); + }; + + // Remove... + self.remove = function(INSTANT){ + return _remove(self, INSTANT); + }; + +} diff --git a/js/sims/PD.js b/js/sims/PD.js index e3e9932..eb1c992 100644 --- a/js/sims/PD.js +++ b/js/sims/PD.js @@ -30,6 +30,9 @@ subscribe("pd/defaultPayoffs", function(){ }); PD.NOISE = 0; +subscribe("rules/noise",function(value){ + PD.NOISE = value; +}); PD.getPayoffs = function(move1, move2){ var payoffs = PD.PAYOFFS; diff --git a/js/sims/SandboxUI.js b/js/sims/SandboxUI.js index 9b79120..e1db2e7 100644 --- a/js/sims/SandboxUI.js +++ b/js/sims/SandboxUI.js @@ -97,6 +97,193 @@ function SandboxUI(config){ // PAGE 0: POPULATION /////////////////// ///////////////////////////////////////// + var page = pages[0]; + + // Labels + page.appendChild(_makeLabel("sandbox_population", {x:0, y:0, w:433})); + + // Create an icon, label, and slider... that all interact with each other. + var _makePopulationControl = function(x, y, peepID, defaultValue){ + + // DOM + var popDOM = document.createElement("div"); + popDOM.className = "sandbox_pop"; + popDOM.style.left = x; + popDOM.style.top = y; + page.appendChild(popDOM); + + // Message + var message = "sandbox/pop/"+peepID; + + // Icon + var popIcon = document.createElement("div"); + popIcon.className = "sandbox_pop_icon"; + popIcon.style.backgroundPosition = (-PEEP_METADATA[peepID].frame*40)+"px 0px"; + popDOM.appendChild(popIcon); + + // Label: Name + var popName = document.createElement("div"); + popName.className = "sandbox_pop_label"; + popName.innerHTML = Words.get("label_short_"+peepID).toUpperCase(); + popName.style.color = PEEP_METADATA[peepID].color; + popDOM.appendChild(popName); + + // Label: Amount + var popAmount = document.createElement("div"); + popAmount.className = "sandbox_pop_label"; + popAmount.style.textAlign = "right"; + popAmount.style.color = PEEP_METADATA[peepID].color; + popDOM.appendChild(popAmount); + subscribe(message, function(value){ + popAmount.innerHTML = value; + }); + + // Slider + (function(peepID){ + var popSlider = new Slider({ + x:0, y:35, width:200, + min:0, max:25, step:1, + message: message, + onselect: function(){ + _anchorPopulation(peepID); + }, + onchange: function(value){ + _adjustPopulation(peepID, value); + } + }); + popDOM.appendChild(popSlider.dom); + })(peepID); + + // Default value! + publish(message, [defaultValue]); + + }; + var xDiff = 220; + var yDiff = 80; + var yOff = 40; + _makePopulationControl( 0, yOff+0, "tft", 5); + _makePopulationControl(xDiff, yOff+0, "all_d", 5); + _makePopulationControl( 0, yOff+yDiff, "all_c", 15); + _makePopulationControl(xDiff, yOff+yDiff, "grudge", 0); + _makePopulationControl( 0, yOff+yDiff*2, "prober", 0); + _makePopulationControl(xDiff, yOff+yDiff*2, "tf2t", 0); + _makePopulationControl( 0, yOff+yDiff*3, "pavlov", 0); + _makePopulationControl(xDiff, yOff+yDiff*3, "random", 0); + + // Adjust the WHOLE population... + /****************************** + + Adjust by SCALING. (and in the edge case of "all zero", scale equally) + Round to integers. (if above or below 25 in total, keep adding/subtracting 1 down the line) + + ******************************/ + var _population; + var _remainder; + var _anchoredIndex; + var _anchorPopulation = function(peepID){ + + // Which index should be anchored? + _anchoredIndex = Tournament.INITIAL_AGENTS.findIndex(function(config){ + return config.strategy==peepID; + }); + var initValue = Tournament.INITIAL_AGENTS[_anchoredIndex].count; + + // SPECIAL CASE: THIS IS ALREADY FULL + if(initValue==25){ + + // Pretend it was 1 for all seven others, 25-7 for this. + _population = []; + for(var i=0; i=0 && diff<0; i--){ + // do NOT adjust anchor. + var conf = Tournament.INITIAL_AGENTS[i]; + if(conf.strategy==peepID) continue; + conf.count--; // REMOVE + diff++; // yay + } + } + // If positive, add one starting from top, skipping anchor. + if(diff>0){ + for(var i=0; i0; i++){ + // do NOT adjust anchor. + var conf = Tournament.INITIAL_AGENTS[i]; + if(conf.strategy==peepID) continue; + conf.count++; // ADD + diff--; // yay + } + } + + // NOW adjust UI + for(var i=0; i

-Start the simulation with this distribution of players: +Start off with this distribution of players:

@@ -45,6 +45,9 @@ In each round of a one-on-one game, there's a [N]% chance a player makes a mista

Tit For Tat

+

+copycat +

I Cooperate on the first round. Then, I just do whatever you did the last round. @@ -55,6 +58,9 @@ but if you Cooperate, I'll forgive you immediately!

Always Cheat

+

+sinner +

Ain't I a stinker?

@@ -62,6 +68,9 @@ Ain't I a stinker?

Always Cooperate

+

+saint +

💖 💖 💖

@@ -69,6 +78,9 @@ Always Cooperate

Grudger

+

+grudger +

I'll always Cooperate... until you Cheat me even once. Then, I'll always Cheat you back. NO FORGIVENESS. @@ -77,6 +89,9 @@ Then, I'll always Cheat you back. NO FORGIVENESS.

Prober

+

+detective +

First: I analyze you. I start: Cooperate, Cheat, Cooperate, Cooperate. @@ -88,6 +103,9 @@ My dear Watson: elementary.

Tit For Two Tats

+

+copykitten +

I Cooperate on the first round. After that, if you Cheat me... well, I'll forgive you once. @@ -98,6 +116,9 @@ However, if you Cheat me twice in a row, then I'll Cheat back.

Pavlov's Dog

+

+pavlov +

I Cooperate on the first round. After that, if you Cooperated in the previous round, @@ -109,6 +130,9 @@ I'll do the opposite of what I did last time (even if it was a mistake).

Lol So Random

+

+random +

monkey tacos! robot ninja bacon pirate! i randomly play Cheat or Cooperate coz lol i'm so random