freeCodeCamp/curriculum/challenges/italian/10-coding-interview-prep/project-euler/problem-84-monopoly-odds.md

11 KiB

id title challengeType forumTopicId dashedName
5900f3c11000cf542c50fed3 Problema 84: probabilità del Monopoli 5 302198 problem-84-monopoly-odds

--description--

Nel gioco, Monopoly, il tabellone standard è sistemato in questo modo:

VIA A1 CC1 A2 T1 R1 B1 CH1 B2 B3 PRIGIONE
H2   C1
T2   U1
H1   C2
CH3   C3
R4   R2
G3   D1
CC3   CC2
G2   D2
G1   D3
G2J F3 U2 F2 F1 R3 E3 E2 CH2 E1 FP

Il giocatore inizia nella cella del VIA e somma il risultato di due dadi a sei facce per determinare il numero di caselle di cui avanzano in senso orario. Senza regole aggiuntive ci aspetteremmo di visitare ogni casella con la stessa probabilità: 2,5%. Invece, finire su G2J (Go to jail - vai in prigione), CC (community chest - imprevisto), e CH (chance - probabilità) cambia questa distribuzione.

In aggiunta a G2J e una carta ciascuno per CC e CH che ordina al giocatore di andare direttamente in prigione, se un giocatore tira tre doppi consecutivi questo non avanza del risultato del loro terzo tiro. Invece va direttamente in prigione.

All'inizio del gioco, le carte CC e CH sono mescolate. Quando un giocatore finisce su una carta CC o CH questo prende una carta dalla cima del rispettivo mazzo e, dopo aver seguito le istruzioni, è rimessa al fondo della pila. Ci sono sedici carte in ogni mazzo, ma per l'obbiettivo di questo problema ci interessano solo le carte che dicono di muoversi; qualsiasi istruzione non legata con il movimento sarà ignorata e il giocatore rimarrà sulla casella CC/CH.

  • Imprevisto (2/16 carte):
    1. Vai al VIA
    2. Vai in PRIGIONE
  • Probabilità (10/16 carte):
    1. Vai al VIA
    2. Vai in PRIGIONE
    3. Vai a C1
    4. Vai a E3
    5. Vai ad H2
    6. Vai a R1
    7. Vai al R successivo (stazione ferroviaria)
    8. Vai al R successivo
    9. Vai al U successivo (compagnia elettrica/dell'acqua)
    10. Indietreggia di 3 caselle.

Il cuore di questo problema si incentra sulla probabilità di visitare una certa casella. Cioè, la probabilità di finire su quella casella dopo un tiro di dado. Per questa ragione dovrebbe essere chiaro che, con l'eccezzione di G2J per cui la probabilità di finire un movimento su di esso è zero, le caselle CH hanno la probabilità minore, visto che 5/8 carte dicono di muoversi su un'altra casella, e quella è la casella finale su cui il giocatore finisce il movimento per ogni tiro a cui siamo interessati. Non facciamo alcuna distinzione tra "Visita alla prigione" e venir mandati in prigione, e ignoriamo la regola che richiede un doppio per uscire di prigione, assumendo che il giocatore paga al turno successivo per uscire di prigione.

Iniziando al VIA e numerando le celle sequenzialmente da 00 a 39 possiamo concatenare questi numeri a due cifre per produrre stringhe che corrispondono a set di celle.

Statisticamente si può mostrare che le tre celle più popolari sono, in ordine, PRIGIONE (6.24%) = cella 10, E3 (3.18%) = cella 24 e VIA (3.09%) = square 00. Queste tre celle più popolari possono essere elencate con la stringa a sei cifre 102400.

Trova la stringa a sei cifre che si ottiene sostituendo i due dadi a 6 facce con due dadi ad n facce.

--hints--

monopolyOdds(8) dovrebbe restituire una stringa.

assert(typeof monopolyOdds(8) === 'string');

monopolyOdds(8) dovrebbe restituire la stringa 102400.

assert.strictEqual(monopolyOdds(8), '102400');

monopolyOdds(10) dovrebbe restituire la stringa 100024.

assert.strictEqual(monopolyOdds(10), '100024');

monopolyOdds(20) dovrebbe restituire la stringa 100005.

assert.strictEqual(monopolyOdds(20), '100005');

monopolyOdds(4) dovrebbe restituire la stringa 101524.

assert.strictEqual(monopolyOdds(4), '101524');

--seed--

--seed-contents--

function monopolyOdds(n) {

  return true;
}

monopolyOdds(8);

--solutions--

function monopolyOdds(n) {
  function chanceCard(position, chanceCardPosition) {
    chanceCardPosition = (chanceCardPosition + 1) % 16;
    if (chanceCardPosition < 6) {
      position = chanceCardsMoves[chanceCardPosition];
    } else if (chanceCardPosition === 6 || chanceCardPosition === 7) {
      position = nextMovesFromR[position];
    } else if (chanceCardPosition === 8) {
      position = nextMovesFromU[position];
    } else if (chanceCardPosition === 9) {
      position -= 3;
    }
    return [position, chanceCardPosition];
  }

  function chestCard(position, chestPosition) {
    chestPosition = (chestPosition + 1) % 16;
    if (chestPosition < 2) {
      position = chestCardsMoves[chestPosition];
    }
    return [position, chestPosition];
  }

  function isChest(position) {
    return position === 2 || position === 17 || position === 33;
  }

  function isChance(position) {
    return position === 7 || position === 22 || position === 36;
  }

  function isJail(position) {
    return position === 30;
  }

  function roll(dice) {
    return Math.floor(Math.random() * dice) + 1;
  }

  function getTopThree(board) {
    return sortByVisits(board)
      .slice(0, 3)
      .map(elem => elem[0].toString().padStart(2, '0'))
      .join('');
  }

  function sortByVisits(board) {
    return board
      .map((element, index) => [index, element])
      .sort((a, b) => a[1] - b[1])
      .reverse();
  }

  const rounds = 2000000;
  const chestCardsMoves = [0, 10];
  const chanceCardsMoves = [0, 10, 11, 24, 39, 5];
  const nextMovesFromR = { 7: 15, 22: 25, 36: 5 };
  const nextMovesFromU = { 7: 12, 36: 12, 22: 28 };

  const board = new Array(40).fill(0);
  let doubleCount = 0;
  let curPosition = 0;
  let curChestCard = 0;
  let curChanceCard = 0;

  for (let i = 0; i < rounds; i++) {
    const dice1 = roll(n);
    const dice2 = roll(n);

    if (dice1 === dice2) {
      doubleCount++;
    } else {
      doubleCount = 0;
    }

    if (doubleCount > 2) {
      curPosition = 10;
      doubleCount = 0;
    } else {
      curPosition = (curPosition + dice1 + dice2) % 40;

      if (isChance(curPosition)) {
        [curPosition, curChanceCard] = chanceCard(curPosition, curChanceCard);
      } else if (isChest(curPosition)) {
        [curPosition, curChestCard] = chestCard(curPosition, curChestCard);
      } else if (isJail(curPosition)) {
        curPosition = 10;
      }
    }
    board[curPosition]++;
  }
  return getTopThree(board);
}