diff --git a/assets/ui/payoffs_ui.png b/assets/ui/payoffs_ui.png new file mode 100644 index 0000000..2569ddd Binary files /dev/null and b/assets/ui/payoffs_ui.png differ diff --git a/assets/ui/sandbox_tabs.png b/assets/ui/sandbox_tabs.png index 20544fa..e73c587 100644 Binary files a/assets/ui/sandbox_tabs.png and b/assets/ui/sandbox_tabs.png differ diff --git a/css/slides.css b/css/slides.css index 9709694..7c45e68 100644 --- a/css/slides.css +++ b/css/slides.css @@ -35,6 +35,9 @@ body{ height: 60px; background: #222; } +s{ + text-decoration: line-through; +} /*************************/ /******* SLIDESHOW *******/ @@ -85,6 +88,13 @@ body{ /********* Button ********/ +.no-select{ + -webkit-user-select: none; /* Chrome all / Safari all */ + -moz-user-select: none; /* Firefox all */ + -ms-user-select: none; /* IE 10+ */ + user-select: none; + cursor: default; +} .button{ z-index: 0; -webkit-user-select: none; /* Chrome all / Safari all */ @@ -151,6 +161,8 @@ body{ } .button[size=short] #text{ width:105px; + font-size: 18px; + top: 18px; } .button[size=short] #hitbox{ width:115px; @@ -251,6 +263,14 @@ body{ width:30px; height:30px; background: url(../assets/ui/slider_knob.png); background-size: 100% 100%; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; +} +.slider > .slider_knob:active{ + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; } .sandbox_pop{ diff --git a/index.html b/index.html index 5c8d43e..e2b8223 100644 --- a/index.html +++ b/index.html @@ -42,6 +42,7 @@ + @@ -87,7 +88,7 @@ window.onload = function(){ // First slide! //slideshow.nextSlide(); - slideshow.gotoSlide("evolution"); + slideshow.gotoSlide("distrust"); }); diff --git a/js/core/IncDecNumber.js b/js/core/IncDecNumber.js index 6185d31..84d4985 100644 --- a/js/core/IncDecNumber.js +++ b/js/core/IncDecNumber.js @@ -36,7 +36,7 @@ function IncDecNumber(config){ // Value & UI self.value = value; - num.innerHTML = self.value; + num.innerHTML = (self.value>0) ? "+"+self.value : self.value; }; self.setValue(config.value); diff --git a/js/core/PayoffsUI.js b/js/core/PayoffsUI.js new file mode 100644 index 0000000..09810fe --- /dev/null +++ b/js/core/PayoffsUI.js @@ -0,0 +1,78 @@ +function PayoffsUI(config){ + + var self = this; + self.id = config.id; + self.slideshow = config.slideshow; + + // Create DOM + self.dom = document.createElement("div"); + self.dom.className = "object"; + var dom = self.dom; + _configText(config, dom); + if(config.scale){ + dom.style.transform = "scale("+config.scale+","+config.scale+")"; + } + + // Add Image Background + var bg = new ImageBox({ + src: "assets/ui/payoffs_ui.png", + x:0, y:0, width:300, height:300 + }); + dom.appendChild(bg.dom); + + // Labels + dom.appendChild(_makeLabel("label_cooperate", {x:148, y:17, rotation:45, align:"center", color:"#cccccc"})); + dom.appendChild(_makeLabel("label_cooperate", {x:52, y:17, rotation:-45, align:"center", color:"#cccccc"})); + dom.appendChild(_makeLabel("label_cheat", {x:245, y:90, rotation:45, align:"center", color:"#cccccc"})); + dom.appendChild(_makeLabel("label_cheat", {x:6, y:90, rotation:-45, align:"center", color:"#cccccc"})); + + // Inc(rement) De(crement) Numbers + // which are symmetrical, and update each other! + var numbers = []; + var _makeIncDec = function(letter,x,y){ + (function(letter,x,y){ + + var number = new IncDecNumber({ + x:x, y:y, max:5, min:-5, + value: PD.PAYOFFS[letter], + onchange: function(value){ + publish("pd/editPayoffs/"+letter,[value]); + publish("payoffs/onchange"); + } + }); + listen(self, "pd/editPayoffs/"+letter,function(value){ + number.setValue(value); + }); + number.slideshow = self.slideshow; + dom.appendChild(number.dom); + numbers.push(number); + + })(letter,x,y); + }; + + _makeIncDec("R", 191-64, 127-47); + _makeIncDec("R", 233-64, 127-47); + + _makeIncDec("T", 121-64, 197-47); + _makeIncDec("S", 161-64, 197-47); + + _makeIncDec("S", 263-64, 197-47); + _makeIncDec("T", 306-64, 197-47); + + _makeIncDec("P", 192-64, 268-47); + _makeIncDec("P", 232-64, 268-47); + + // Add & Remove + self.add = function(){ _add(self); }; + self.remove = function(){ + unlisten(self); + for(var i=0;i"+words+""); + }; + listen(_.misc, "rules/turns", function(value){ + _updateLabel(value); + o.tournament.reset(); + }); + o.roundsSlider.setValue(10); + _updateLabel(10); + _hide(o.roundsLabel); _fadeIn(o.roundsLabel, 500); + _hide(o.roundsSlider); _fadeIn(o.roundsSlider, 500); + + // Continue... + listen(_.misc, "tournament/autoplay/start",function(){ + if(_showContinue) _showContinue(); + }); + var _showContinue = function(){ + _showContinue = null; + var x = 125; + var y = 430; + self.add({ + id:"continueLabel", type:"TextBox", + x:x, y:y+5, width:200, height:50, + align:"right", color:"#aaa", size:17, + text_id:"distrust_2_end" + }); + self.add({ + id:"continueButton", type:"Button", + x:x+215, y:y, size:"short", + text_id:"distrust_2_btn", + message: "slideshow/next" + }); + _hide(o.continueLabel); _fadeIn(o.continueLabel, 100); + _hide(o.continueButton); _fadeIn(o.continueButton, 100); + }; + + }, + onend: function(self){ + unlisten(_.misc); + self.remove("roundsLabel"); + self.remove("roundsSlider"); + self.remove("continueLabel"); + self.remove("continueButton"); + } +}); + +// Explain that... +SLIDES.push({ + onstart: function(self){ + + var o = self.objects; + + // Words + o.text.setTextID("distrust_3"); + _hide(o.text); _fadeIn(o.text, 100); + + // Worse... + self.add({ + id:"next", type:"Button", + x:0, y:450, size:"long", + text_id:"distrust_3_btn", + message: "slideshow/next" + }); + _hide(o.next); _fadeIn(o.next, 400); + + }, + onend: function(self){ + self.remove("text"); + self.remove("next"); + } +}); + +// Change PAYOFFS +SLIDES.push({ + onstart: function(self){ + + var o = self.objects; + _.misc = {}; + + // Words + self.add({ + id:"text", type:"TextBox", + x:0, y:0, width:450, height:500, + text_id:"distrust_4" + }); + _hide(o.text); _fadeIn(o.text, 100); + + // PAYOFFS + self.add({ + id:"payoffs", type:"PayoffsUI", + x:105, y:73, scale:0.8, slideshow:self + }); + _hide(o.payoffs); _fadeIn(o.payoffs, 300); + listen(_.misc, "payoffs/onchange", function(value){ + o.tournament.reset(); + }); + + // More words + self.add({ + id:"text2", type:"TextBox", + x:0, y:320, width:450, height:500, + text_id:"distrust_4_2" + }); + _hide(o.text2); _fadeIn(o.text2, 500); + + // Note 1 + var _showContinue = function(){ + _showContinue = null; + self.add({ + id:"continueLabel", type:"TextBox", + x:0, y:480, width:320, + align:"right", color:"#aaa", size:17, + text_id:"distrust_4_note" + }); + self.add({ + id:"continueButton", type:"Button", + x:340, y:471, size:"short", + text_id:"distrust_2_btn", + message: "slideshow/next" + }); + _hide(o.continueLabel); _fadeIn(o.continueLabel, 100); + _hide(o.continueButton); _fadeIn(o.continueButton, 100); + }; + listen(_.misc, "tournament/autoplay/start",function(){ + if(_showContinue) _showContinue(); + }); + + // Note 2 + self.add({ + id:"note2", type:"TextBox", + x:583, y:510, width:300, height:50, + align:"center", color:"#aaa", size:17, + text_id:"distrust_4_note_2" + }); + _hide(o.note2); _fadeIn(o.note2, 500); + + // TOURNAMENT + Tournament.resetGlobalVariables(); + Tournament.INITIAL_AGENTS = [ + {strategy:"all_c", count:23}, + {strategy:"all_d", count:1}, + {strategy:"tft", count:1} + ]; + Tournament.NUM_TURNS = 10; + o.tournament.reset(); + + }, + onend: function(self){ + unlisten(_.misc); + self.remove("text"); + self.remove("payoffs"); + self.remove("text2"); + self.remove("note2"); + self.remove("continueLabel"); + self.remove("continueButton"); + } +}); + +// Explain that... +SLIDES.push({ + onstart: function(self){ + + var o = self.objects; + + // Words + self.add({ + id:"text", type:"TextBox", + x:0, y:30, width:450, height:500, + text_id:"distrust_5" + }); + _hide(o.text); _fadeIn(o.text, 100); + + // Worse... + self.add({ + id:"next", type:"Button", + x:0, y:410, size:"long", + text_id:"distrust_5_btn", + message: "slideshow/next" + }); + _hide(o.next); _fadeIn(o.next, 400); + + }, + onend: function(self){ + self.remove("text"); + self.remove("next"); + } +}); + +// Play with BOTH +SLIDES.push({ + onstart: function(self){ + + var o = self.objects; + _.misc = {}; + + // TOURNAMENT + Tournament.resetGlobalVariables(); + Tournament.INITIAL_AGENTS = [ + {strategy:"all_c", count:23}, + {strategy:"all_d", count:1}, + {strategy:"tft", count:1} + ]; + PD.PAYOFFS.P = -4; + PD.PAYOFFS.S = -1; + PD.PAYOFFS.R = 1; + PD.PAYOFFS.T = 3; + o.tournament.reset(); + + // Words + self.add({ + id:"text", type:"TextBox", + x:0, y:0, width:450, height:500, + text_id:"distrust_6" + }); + _hide(o.text); _fadeIn(o.text, 100); + listen(_.misc, "payoffs/onchange", function(value){ + o.tournament.reset(); + }); + + // SLIDER + // HAX - COPY PASTE CODE WHATEVER + var x = 0; + var y = 95; + self.add({ + id:"roundsLabel", type:"TextBox", + x:0, y:y, width:450, size:25, noSelect:true + }); + self.add({ + id:"roundsSlider", type:"Slider", + x:0, y:y+30, width:450, + min:1, max:20, step:1, + message: "rules/turns" + }); + var _updateLabel = function(value){ + var words = (value==1) ? Words.get("sandbox_rules_1_single") : Words.get("sandbox_rules_1"); // plural? + words = words.replace(/\[N\]/g, value+""); // replace [N] with the number value + o.roundsLabel.setText(""+words+""); + }; + listen(_.misc, "rules/turns", function(value){ + _updateLabel(value); + o.tournament.reset(); + }); + o.roundsSlider.setValue(10); + _updateLabel(10); + _hide(o.roundsLabel); _fadeIn(o.roundsLabel, 300); + _hide(o.roundsSlider); _fadeIn(o.roundsSlider, 300); + + // PAYOFFS + self.add({ + id:"payoffs", type:"PayoffsUI", + x:105, y:170, scale:0.8, slideshow:self + }); + _hide(o.payoffs); _fadeIn(o.payoffs, 300); + + // Words + self.add({ + id:"text2", type:"TextBox", + x:0, y:410, width:450, height:500, + text_id:"distrust_6_end" + }); + _hide(o.text2); _fadeIn(o.text2, 500); + + // FINALLY. + self.add({ + id:"next", type:"Button", + x:0, y:475, size:"long", + text_id:"distrust_6_btn", + message: "slideshow/scratch" + }); + _hide(o.next); _fadeIn(o.next, 700); + }, onend: function(self){ + unlisten(_); + unlisten(_.misc); + self.clear(); } -}); \ No newline at end of file +}); diff --git a/lang/en.html b/lang/en.html index 3afdeac..18d2dff 100644 --- a/lang/en.html +++ b/lang/en.html @@ -498,79 +498,80 @@ What could lead to...

-Before everything goes to heck: let's start with something nice. -A world, mostly populated by nice Copycats, -with only one each of a -mean Always Cheat, -naive Always Cooperate, -unforgiving Grudger, and -manipulative Detective. +Before everything goes to heck, let's start with something nice! +Here's a world filled entirely with Always Cooperates, +except for one Always Cheat and one Copycat.

-Use the buttons on the right to start the simulation, -go through it step-by-step, or restart it. → +Use the buttons on the right to start the sim, +go through it step-by-step, or reset it. →

-Under our current rules, Copycat wins easily. +As you already know, Copycat wins handily in the long run, +under our current rules!

But that's under our current rules, which say that -players play against each other 10 rounds per match. -What if players had to play 20 rounds? 5 rounds? 3 rounds? 1 round? -Use the slider below to change this rule, start the simulation, -and see what happens – then repeat this for as many numbers as you'd like to experiment with: +players play against each other for 10 rounds per match. +Does Copycat still win at 7 rounds? 5 rounds? 3? 2? 1? +

+Change the number of rounds with the slider below, +start the sim, and see what happens. +Feel free to experiment as much as you'd like!

-(when you're done, press:) +once you're done playing around, click: +

+

+continue

-As you just saw, if you play enough rounds, Copycat still wins... -but when people play with each other less and less... suddenly, // HOW MUCH? -ALWAYS CHEAT dominates once again. +As you saw, when people play below some number of rounds, +ALWAYS CHEAT dominates.

In 1985, when Americans were asked how many close friends they had, the most common answer was "three". In 2004, the most common answer was "zero". -Furthermore, we're also (relatively) less likely to -get married, volunteer, go to church, join organizations, or participate in local politics. -We're losing our "social capital". -And as you discovered for yourself just now, +We now have fewer friends across class, racial, economic, and political lines, +because we have fewer friends -- period. +And as you just discovered for yourself, the fewer "repeat interactions" there are, the more distrust will spread.

-(and no, mass media doesn't count: -it has to be repeat two-way interactions between specific individuals.) +(no, mass media doesn't count: +it must be two-way interactions between specific individuals.)

-oh, it gets worse... → +and oh, it gets worse... →

-There's another way to breed distrust. -Here are the "payoffs" for a single round of the trust game: -

-

-Note: although the reward for mutual trust (+2) is less than the temptation to exploit (+3), -with enough repeat interaction, trust can still win! -But now, click the arrows above to change the reward from +2 to +1, -then click "start". -Even though +1 is still more than the punishment for mutual distrust (0)... +There's another way to breed distrust. +Here are the "payoffs" for the trust game: +

+

+Let's start with a mostly-Copycat world. Normally, they'd win. +But now, change the "trust" reward from +2 to +1, +then click start. → +Even though +1 is still more than the punishment for mutual distrust (0)... what happens? -

-(after you try that, feel free to play around with different "payoff" combinations! -once you're done experimenting, hit:)

-(simulating: 5 rounds per match) +feel free to play around with different payoffs! +once you're done, click: +

+

+(simulating: 10 rounds per match)

+The same thing happens: Always Cheat dominates. So even if the reward for getting a "win-win" is still more than the punishment for a "lose-lose"... if the reward for mutual trust is too low, distrust evolves.

I think, as a culture, we're losing the value of finding "win-wins". We're more interested in "win-lose", because viciousness gets views, conflict gets clicks. -We'd rather live and let die. +It's live and let die. Maybe I'm just overthinking things, maybe I'm just old and shaking my fist at a cloud... but don't you feel it? That we've forgotten something?...

@@ -579,18 +580,16 @@ but don't you feel it? That we've forgotten something?...

-Aaaaanyway, you can now play with both the number of rounds and the payoffs! -These two things interact with each other a lot. -For example, even though a low +1 reward creates distrust with 5 rounds per match, -trust can still win with 10 rounds per match! (Click START to simulate this) +Aaaaanyway, now you can change both rules! +(click start to see how, with weird payoffs, the sim +"swings" between Cheats & Cooperates...)

-Once you're done experimenting, -(and there'll be a much bigger "sandbox" to play around with at the end) -let's take a look at our final, most interesting barrier to trust... +Once you're done experimenting with this, +let's look at our final barrier to trust...

-Misteaks Mistakes. → +Misteaks Mistakes. →

@@ -696,7 +695,7 @@ Start off with this distribution of players: The payoffs in a one-on-one game are:

-reset payoffs +set default

-Play [N] rounds per one-on-one game +Play [N] rounds per match:

-Play [N] round per one-on-one game +Play [N] round per match:

-After each tournament, eliminate the bottom [N] players & reproduce the top [N] players +After each tournament, eliminate the bottom [N] players & reproduce the top [N] players:

-After each tournament, eliminate the bottom [N] player & reproduce the top [N] player +After each tournament, eliminate the bottom [N] player & reproduce the top [N] player:

-In each round of a one-on-one game, there's a [N]% chance a player makes a mistake +During each round, there's a [N]% chance a player makes a mistake:

@@ -886,6 +885,10 @@ cheat play

+

+start +

+

stop