661e31cfd0d234e2f79d47f4bc7534afc8e7244d
1 const nChoice
= 3; //fixed for this game
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
7 if (j
== (i
+1) % nChoice
)// || j == (i+3) % nChoice)
10 return -1; //I lose :(
16 const symbols
= [ "Rock", "Lizard", "Spock", "Scissors", "Paper" ];
21 humanMove: -1, //integer in 0...nChoice-1
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
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
=> {
43 if (this.humanHistory
.length
> this.nInput
)
44 this.humanHistory
.splice(this.nInput
);
46 // Play a move given current data (*after* human move: trigger onChange)
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
)
54 return input
[ this.humanHistory
[j
] ];
60 if (candidates
.length
== 0 || sumWeights
> candidates
[0].val
)
61 candidates
= [ currentValue
];
62 else if (sumWeights
== candidates
[0].val
)
63 candidates
.push(currentValue
);
65 // Pick a choice at random in maxValue (total random for first move)
66 let randIdx
= Math
.floor((Math
.random() * candidates
.length
) + 1);
67 this.updateGameState(candidates
[randIdx
].index
);
69 updateGameState: function(index
) {
70 let reward
= rewards
[index
][this.humanMove
]; //viewpoint of computer
71 this.gameState
+= reward
;
72 this.updateWeights(reward
, index
);
74 updateWeights: function(reward
, index
) {
75 let delta
= Math
.sign(reward
);
76 if (this.drawIsLost
&& reward
== 0)
78 this.weights
[index
].forEach( (input
,i
) => {
79 if (i
< this.humanHistory
.length
)
80 input
[ this.humanHistory
[i
] ] += delta
;
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
;
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
;
101 // Update human moves history
102 this.humanHistory
.push(this.humanMove
);
103 if (this.humanHistory
.length
> this.nInput
)
104 this.humanHistory
.shift();