const ALLC = function allwaysCooperate(foeHistory) { return true; } const ALLD = function allwaysDefect(foeHistory) { return false; } const RAND = function randomChoice(foeHistory) { if (Math.random() > 0.5) { return true; } return false; } const TFT = function titForThat(foeHistory) { if (foeHistory.length === 0) { return true; } return foeHistory[foeHistory.length - 1]; } const STFT = function suspiciousTitForTat(foeHistory) { if (foeHistory.length === 0) { return false; } return foeHistory[foeHistory.length - 1]; } const GRIM = function grimTrigger(foeHistory) { if (foeHistory.some(e => e === false)) { return false; } return true; } const MAJ = function majority(foeHistory) { let nbTrue = 0; let nbFalse = 0; for (const valeur of foeHistory) { if (valeur) { nbTrue++; } else { nbFalse++; } } if (nbTrue < nbFalse) { return false; } return true; } class Party { constructor(length, functions) { this.length = length; // if a list of active strategies is provided, use it, // otherwise fall back to all seven by default this.functions = (functions && functions.length > 0) ? functions : [ALLC, ALLD, RAND, TFT, STFT, GRIM, MAJ]; this.grid = []; for (let i = 0; i < this.length; i++) { this.grid[i] = []; for (let j = 0; j < this.length; j++) { const index = Math.floor(Math.random() * this.functions.length); this.grid[i][j] = this.functions[index]; } } } reset(functions) { // if a new list of active strategies is passed, update it; // otherwise keep the current selection if (functions && functions.length > 0) { this.functions = functions; } this.grid = []; for (let i = 0; i < this.length; i++) { this.grid[i] = []; for (let j = 0; j < this.length; j++) { const index = Math.floor(Math.random() * this.functions.length); this.grid[i][j] = this.functions[index]; } } } step(T = 5, R = 3, P = 1, S = 0) { const nbRound = 50; let scores = []; for (let i = 0; i < this.length; i++) { scores[i] = []; for (let j = 0; j < this.length; j++) { scores[i][j] = 0; } } // computing scores for (let i = 0; i < this.length; i++) { for (let j = 0; j < this.length; j++) { for (let di = -1; di < 2; di++) { for (let dj = -1; dj < 2; dj ++) { if (di !== 0 || dj !== 0) { const ni = (i + di + this.length) % this.length; const nj = (j + dj + this.length) % this.length; let playerHist = []; let playerStrat = this.grid[i][j]; let foeHist = []; let foeStrat = this.grid[ni][nj]; for (let k = 0; k < nbRound; k++) { let playerMove = playerStrat(foeHist); let foeMove = foeStrat(playerHist); playerHist.push(playerMove); foeHist.push(foeMove); if (playerMove && foeMove) { // both shared scores[i][j] += R; scores[ni][nj] += R; } else if (playerMove && !foeMove) { // player lose scores[i][j] += S; scores[ni][nj] += T; } else if (!playerMove && foeMove) { // foe lose scores[i][j] += T; scores[ni][nj] += S; } else { // both lose scores[i][j] += P; scores[ni][nj] += P; } } } } } } } let newGrid = []; for (let i = 0; i < this.length; i++) { newGrid[i] = []; for (let j = 0; j < this.length; j++) { newGrid[i][j] = 0; } } // changing strats for (let i = 0; i < this.length; i++) { for (let j = 0; j < this.length; j++) { let bestScore = scores[i][j]; newGrid[i][j] = this.grid[i][j]; for (let di = -1; di < 2; di++) { for (let dj = -1; dj < 2; dj ++) { if (di !== 0 || dj !== 0) { const ni = (i + di + this.length) % this.length; const nj = (j + dj + this.length) % this.length; if (scores[ni][nj] > bestScore) { // someone has a better strategy newGrid[i][j] = this.grid[ni][nj]; bestScore = scores[ni][nj]; } } } } } } this.grid = newGrid; } }