Commit | Line | Data |
---|---|---|
932d367f | 1 | const nChoice = 3; //fixed for this game |
977c11c8 BA |
2 | |
3 | // Rewards matrix. Order: rock, lizard, Spock, scissors, paper | |
4 | const rewards = Array.from(Array(nChoice)).map( (e,i) => { //lines | |
5 | return Array.from(Array(nChoice)).map( (f,j) => { //columns | |
6 | // i against j: gain from i viewpoint | |
932d367f | 7 | if (j == (i+1) % nChoice)// || j == (i+3) % nChoice) |
977c11c8 | 8 | return 1; //I win :) |
932d367f | 9 | else if (i != j) |
977c11c8 | 10 | return -1; //I lose :( |
932d367f | 11 | else //i == j |
977c11c8 BA |
12 | return 0; |
13 | }); | |
14 | }); | |
15 | ||
16 | const symbols = [ "Rock", "Lizard", "Spock", "Scissors", "Paper" ]; | |
17 | ||
18 | new Vue({ | |
19 | el: "#rpsls", | |
20 | data: { | |
21 | humanMove: -1, //integer in 0...nChoice-1 | |
22 | nInput: 5, //default | |
23 | humanHistory: [ ], //your nInput last moves, stored (oldest first) | |
24 | gameState: 0, //total points of the computer | |
25 | drawIsLost: false, //normal (or true: draw is considered loss) | |
26 | rewards: [ ], //initialized at first human move with new nInput | |
27 | weights: [ ], //same as above | |
28 | }, | |
29 | created: function() { | |
30 | this.reinitialize(); | |
31 | }, | |
32 | methods: { | |
33 | // Called on nInput change | |
34 | reinitialize: function() { | |
35 | // weights[i][j][k]: output i -- input j/choice k | |
36 | this.weights = Array.from(Array(nChoice)).map( i => { | |
37 | return Array.from(Array(this.nInput)).map( j => { | |
38 | return Array.from(Array(nChoice)).map( k => { | |
39 | return 0; | |
40 | }); | |
41 | }) | |
42 | }); | |
43 | if (this.humanHistory.length > this.nInput) | |
44 | this.humanHistory.splice(this.nInput); | |
45 | }, | |
46 | // Play a move given current data (*after* human move: trigger onChange) | |
47 | play: function() { | |
48 | let candidates = [ ]; | |
49 | Array.from(Array(nChoice)).forEach( (e,i) => { | |
50 | // Sum all weights from an activated input to this output | |
51 | let sumWeights = this.weights[i].reduce( (acc,input,j) => { | |
52 | if (this.humanHistory.length <= j) | |
53 | return 0; | |
54 | return input[ this.humanHistory[j] ]; | |
55 | }, 0 ); | |
56 | let currentValue = { | |
57 | val: sumWeights, | |
58 | index: i | |
59 | }; | |
60 | if (candidates.length == 0 || sumWeights > candidates[0].val) | |
61 | candidates = [ currentValue ]; | |
62 | else if (sumWeights == candidates[0].val) | |
63 | candidates.push(currentValue); | |
64 | }); | |
65 | // Pick a choice at random in maxValue (total random for first move) | |
66 | let randIdx = Math.floor((Math.random() * candidates.length) + 1); | |
932d367f | 67 | this.updateGameState(candidates[randIdx].index); |
977c11c8 | 68 | }, |
932d367f BA |
69 | updateGameState: function(index) { |
70 | let reward = rewards[index][this.humanMove]; //viewpoint of computer | |
977c11c8 | 71 | this.gameState += reward; |
932d367f | 72 | this.updateWeights(reward, index); |
977c11c8 BA |
73 | }, |
74 | updateWeights: function(reward, index) { | |
75 | let delta = Math.sign(reward); | |
76 | if (this.drawIsLost && reward == 0) | |
77 | delta = -1; | |
78 | this.weights[index].forEach( (input,i) => { | |
79 | if (i < this.humanHistory.length) | |
80 | input[ this.humanHistory[i] ] += delta; | |
81 | }); | |
82 | this.postUpdate(); | |
83 | }, | |
84 | // Finalize weights update | |
85 | postUpdate: function() { | |
86 | // Re-center the weights | |
87 | let sumAllWeights = this.weights.reduce( (a,output) => { | |
88 | return a + output.reduce( (b,input) => { | |
89 | return b + input.reduce( (c,choiceWeight) => { | |
90 | return c + choiceWeight; | |
91 | }, 0); | |
92 | }, 0); | |
93 | }, 0); | |
94 | let meanWeight = sumAllWeights / (this.nInput * nChoice * nChoice); | |
95 | this.weights.forEach( output => { | |
96 | output.forEach( input => { | |
97 | for (let i=0; i<input.length; i++) | |
98 | input[i] -= meanWeight; | |
99 | }); | |
100 | }); | |
101 | // Update human moves history | |
102 | this.humanHistory.push(this.humanMove); | |
932d367f BA |
103 | if (this.humanHistory.length > this.nInput) |
104 | this.humanHistory.shift(); | |
977c11c8 BA |
105 | }, |
106 | }, | |
107 | }); |