How to resolve the algorithm 100 prisoners step by step in the JavaScript programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm 100 prisoners step by step in the JavaScript programming language

Table of Contents

Problem Statement

Show and compare the computed probabilities of success for the two strategies, here, on this page.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm 100 prisoners step by step in the JavaScript programming language

The provided code is a JavaScript simulation of a game where 100 prisoners are each assigned a number from 1 to 100. The prisoners are placed in a room with 100 drawers, each containing a card with a number from 1 to 100. The prisoners can open up to 50 drawers, and if they find their own number, they are pardoned. If any prisoner fails to find their number, all prisoners are sentenced.

The code simulates two strategies:

  1. Optimal Play: In this strategy, prisoners start by opening the drawer with their own number. If they don't find their number, they open the drawer with the number that was in the drawer they just opened. They continue this process until they find their own number or have opened 50 drawers. This strategy is based on a mathematical analysis and is proven to have the highest probability of success.

  2. Random Play: In this strategy, prisoners randomly open drawers until they find their own number or have opened 50 drawers. This strategy is used as a baseline for comparison.

The code runs both strategies multiple times (100,000 times by default) and calculates the percentage of times the prisoners were successful in finding their numbers.

Here is a step-by-step explanation of the code:

  1. The code uses the lodash library to shuffle the order of the cards in the drawers. This ensures that the cards are randomly distributed.

  2. The playOptimal function simulates the optimal play strategy. It iterates through each prisoner and simulates their attempts to find their number. If a prisoner finds their number within 50 attempts, the function returns true; otherwise, it returns false.

  3. The playRandom function simulates the random play strategy. It iterates through each prisoner and randomly selects drawers until they find their number or have opened 50 drawers. If a prisoner finds their number within 50 attempts, the function returns true; otherwise, it returns false.

  4. The execOptimal function runs the optimal play strategy multiple times and calculates the percentage of times the prisoners were successful. It returns the success rate as a percentage.

  5. The execRandom function runs the random play strategy multiple times and calculates the percentage of times the prisoners were successful. It returns the success rate as a percentage.

  6. The code prints the number of executions (100,000) and the success rates for both the optimal play and random play strategies.

Additional Code (not shown in the original code block):

The provided code also includes additional functions and variables that are used to simulate a different version of the game:

  1. playGame: This function simulates a game where prisoners randomly open drawers. It takes the number of games to play as an argument and returns an array of boolean values indicating whether the prisoners were successful in each game.

  2. find: This function simulates a prisoner's attempts to find their number. It takes the prisoner's number, the array of drawers, and the number of their last opened drawer as arguments and returns true if the prisoner found their number; otherwise, it returns false.

  3. randomStrategy: This function simulates the random play strategy. It takes the prisoner's number, the array of drawers, and the number of their last opened drawer as arguments and returns the number of the next drawer to open.

  4. optimalStrategy: This function simulates the optimal play strategy. It takes the prisoner's number, the array of drawers, and the number of their last opened drawer as arguments and returns the number of the next drawer to open.

  5. initDrawers: This function initializes the array of drawers with the numbers from 1 to 100. It shuffles the order of the numbers and returns the shuffled array.

  6. shuffle: This function shuffles an array of numbers.

  7. draw: This function generates a random number between a given minimum and maximum value.

  8. computeProbability: This function calculates the probability of success based on the results of a game. It takes an array of boolean values indicating whether the prisoners were successful in each game and the total number of games played as arguments. It returns the probability as a percentage.

The additional code simulates a different version of the game where prisoners randomly open drawers and uses the optimal strategy mentioned in the Wikipedia article. It also calculates the probability of success for each strategy based on multiple simulated games. The output of this code should look similar to the following:

Games count: 2000
Probability of success with "random" strategy: 30.35
Probability of success with "optimal" strategy: 99.0

Source code in the javascript programming language

const _ = require('lodash');

const numPlays = 100000;

const setupSecrets = () => {
	// setup the drawers with random cards
	let secrets = [];

	for (let i = 0; i < 100; i++) {
		secrets.push(i);
	}

	return _.shuffle(secrets);
}

const playOptimal = () => {
	
	let secrets = setupSecrets();
	

	// Iterate once per prisoner
	loop1:
	for (let p = 0; p < 100; p++) {
		
		// whether the prisoner succeedss
		let success = false;
		
		// the drawer number the prisoner chose
		let choice = p;
		
		
		// The prisoner can choose up to 50 cards
		loop2:
		for (let i = 0; i < 50; i++) {
			
			// if the card in the drawer that the prisoner chose is his card
			if (secrets[choice] === p){
				success = true;
				break loop2;
			}

			// the next drawer the prisoner chooses will be the number of the card he has.
			choice = secrets[choice];
		
		}	// each prisoner gets 50 chances

		
		if (!success) return false;

	} // iterate for each prisoner 

	return true;
}

const playRandom = () => {

	let secrets = setupSecrets();

	// iterate for each prisoner 
	for (let p = 0; p < 100; p++) {

		let choices = setupSecrets();
		
		let success = false;
		
		for (let i = 0; i < 50; i++) {

			if (choices[i] === p) {
				success = true;
				break;
			}
		}

		if (!success) return false;
	}

	return true;
}

const execOptimal = () => {

	let success = 0;
	
	for (let i = 0; i < numPlays; i++) {

		if (playOptimal()) success++;
			
	}

	return 100.0 * success / 100000;
}

const execRandom = () => {

	let success = 0;

	for (let i = 0; i < numPlays; i++) {

		if (playRandom()) success++;

	}

	return 100.0 * success / 100000;
}

console.log("# of executions: " + numPlays);
console.log("Optimal Play Success Rate: " + execOptimal());
console.log("Random Play Success Rate: " + execRandom());


"use strict";

// Simulate several thousand instances of the game:
const gamesCount = 2000;

// ...where the prisoners randomly open drawers.
const randomResults = playGame(gamesCount, randomStrategy);

// ...where the prisoners use the optimal strategy mentioned in the Wikipedia article.
const optimalResults = playGame(gamesCount, optimalStrategy);

// Show and compare the computed probabilities of success for the two strategies.
console.log(`Games count: ${gamesCount}`);
console.log(`Probability of success with "random" strategy: ${computeProbability(randomResults, gamesCount)}`);
console.log(`Probability of success with "optimal" strategy: ${computeProbability(optimalResults, gamesCount)}`);

function playGame(gamesCount, strategy, prisonersCount = 100) {
    const results = new Array();

    for (let game = 1; game <= gamesCount; game++) {
        // A room having a cupboard of 100 opaque drawers numbered 1 to 100, that cannot be seen from outside.
        // Cards numbered 1 to 100 are placed randomly, one to a drawer, and the drawers all closed; at the start.
        const drawers = initDrawers(prisonersCount);

        // A prisoner tries to find his own number.
        // Prisoners start outside the room.
        // They can decide some strategy before any enter the room.
        let found = 0;
        for (let prisoner = 1; prisoner <= prisonersCount; prisoner++, found++)
            if (!find(prisoner, drawers, strategy)) break;

        // If all 100 findings find their own numbers then they will all be pardoned. If any don't then all sentences stand.
        results.push(found == prisonersCount);
    }

    return results;
}

function find(prisoner, drawers, strategy) {
    // A prisoner can open no more than 50 drawers.
    const openMax = Math.floor(drawers.length / 2);

    // Prisoners start outside the room.
    let card;
    for (let open = 0; open < openMax; open++) {
        // A prisoner tries to find his own number.
        card = strategy(prisoner, drawers, card);

        // A prisoner finding his own number is then held apart from the others.
        if (card == prisoner)
            break;
    }

    return (card == prisoner);
}

function randomStrategy(prisoner, drawers, card) {
    // Simulate the game where the prisoners randomly open drawers.

    const min = 0;
    const max = drawers.length - 1;

    return drawers[draw(min, max)];
}

function optimalStrategy(prisoner, drawers, card) {
    // Simulate the game where the prisoners use the optimal strategy mentioned in the Wikipedia article.

    // First opening the drawer whose outside number is his prisoner number.
    // If the card within has his number then he succeeds...
    if (typeof card === "undefined")
        return drawers[prisoner - 1];
   
    // ...otherwise he opens the drawer with the same number as that of the revealed card.
    return drawers[card - 1];
}

function initDrawers(prisonersCount) {
    const drawers = new Array();
    for (let card = 1; card <= prisonersCount; card++)
        drawers.push(card);

    return shuffle(drawers);
}

function shuffle(drawers) {
    const min = 0;
    const max = drawers.length - 1;
    for (let i = min, j; i < max; i++)     {
        j = draw(min, max);
        if (i != j)
            [drawers[i], drawers[j]] = [drawers[j], drawers[i]];
    }

    return drawers;
}

function draw(min, max) {
    // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function computeProbability(results, gamesCount) {
    return Math.round(results.filter(x => x == true).length * 10000 / gamesCount) / 100;
}


  

You may also check:How to resolve the algorithm Range expansion step by step in the PicoLisp programming language
You may also check:How to resolve the algorithm Sort disjoint sublist step by step in the Standard ML programming language
You may also check:How to resolve the algorithm Thiele's interpolation formula step by step in the C programming language
You may also check:How to resolve the algorithm URL encoding step by step in the Lua programming language
You may also check:How to resolve the algorithm Case-sensitivity of identifiers step by step in the Nemerle programming language