100 prisoners: Difference between revisions

Add Ecstasy example
m (syntax highlighting fixup automation)
(Add Ecstasy example)
 
(28 intermediate revisions by 16 users not shown)
Line 34:
{{trans|Python}}
 
<syntaxhighlight lang="11l">F play_random(n)
V pardoned = 0
V in_drawer = Array(0.<100)
Line 89:
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang=AArch64"aarch64 Assemblyassembly">
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program prisonniex64.s */
Line 353:
</pre>
 
=={{header|ABC}}==
<syntaxhighlight lang="ABC">HOW TO FILL drawers:
PUT {} IN drawers
FOR i IN {1..100}: PUT i IN drawers[i]
FOR i IN {1..100}:
PUT choice {i..100} IN j
PUT drawers[i], drawers[j] IN drawers[j], drawers[i]
 
HOW TO REPORT prisoner random.strat drawers:
PUT {1..100} IN available
FOR turn IN {1..50}:
PUT choice available IN drawer
IF drawers[drawer] = prisoner: SUCCEED
REMOVE drawer FROM available
FAIL
 
HOW TO REPORT prisoner optimal.strat drawers:
PUT prisoner IN drawer
FOR turn IN {1..50}:
IF drawers[drawer] = prisoner: SUCCEED
PUT drawers[drawer] IN drawer
FAIL
 
HOW TO REPORT simulate strategy:
FILL drawers
FOR prisoner IN {1..100}:
SELECT:
strategy = "Random":
IF NOT prisoner random.strat drawers: FAIL
strategy = "Optimal":
IF NOT prisoner optimal.strat drawers: FAIL
SUCCEED
 
HOW TO RETURN n.sim chance.of.success strategy:
PUT 0 IN success
FOR n IN {1..n.sim}:
IF simulate strategy: PUT success+1 IN success
RETURN success * 100 / n.sim
 
FOR strategy IN {"Random"; "Optimal"}:
WRITE strategy, ": ", 10000 chance.of.success strategy, '%'/</syntaxhighlight>
{{out}}
<pre>Optimal: 32.01 %
Random: 0 %</pre>
=={{header|Ada}}==
<syntaxhighlight lang=Ada"ada">
package Prisoners is
 
Line 379 ⟶ 423:
end Prisoners;
</syntaxhighlight>
<syntaxhighlight lang=Ada"ada">
pragma Ada_2012;
with Ada.Numerics.Discrete_Random;
Line 509 ⟶ 553:
end Prisoners;
</syntaxhighlight>
<syntaxhighlight lang=Ada"ada">
with Prisoners; use Prisoners;
with Ada.Text_IO; use Ada.Text_IO;
Line 533 ⟶ 577:
Random Strategy = 0.00%
</pre>
 
=={{header|APL}}==
{{works with|GNU APL|1.8}}
 
<syntaxhighlight lang=Ada"ada">
∇ R ← random Nnc; N; n; c
(N n c) ← Nnc
Line 560 ⟶ 605:
 
⎕TS
5000 timesSimPrisoners 100 50
'>>>>>'
1000 timesSimPrisoners 100 50
'>>>>>'
⎕TS
 
</syntaxhighlight>
 
{{out}}
<pre>
2023 3 26 17 43 32 983
>>>>>
0 0.307
>>>>>
2023 3 26 17 53 48 531
</pre>
 
=={{header|Applesoft BASIC}}==
Line 588 ⟶ 646:
Actual test of 4000 trials for each method were run on the KEGSMAC emulator with MHz set to No Limit.
 
<syntaxhighlight lang="gwbasic">0 GOTO 9
 
1 FOR X = 0 TO N:J(X) = X: NEXT: FOR I = 0 TO N:FOR X = 0 TO N:T = J(X):NP = INT ( RND (1) * H):J(X) = J(NP):J(NP) = T: NEXT :FOR G = 1 TO W:IF D(J(G)) = I THEN IP = IP + 1: NEXT I: RETURN
Line 640 ⟶ 698:
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang=ARM"arm Assemblyassembly">
/* ARM assembly Raspberry PI */
/* program prisonniers.s */
Line 880 ⟶ 938:
Optimal strategie : 303 sur 1000
</pre>
=={{header|Arturo}}==
 
<syntaxhighlight lang="arturo">unplanned: function [][
drawers: shuffle @1..100
every? 1..100 'x -> some? 1..50 => [x = sample drawers]
]
 
planned: function [][
drawers: shuffle @1..100
every? 1..100 'x [
next: x
some? 1..50 => [x = next: <= drawers\[next-1]]
]
]
 
test: function [f][
count: enumerate 10000 => [call f []]
print [f ~"|mul fdiv count 10000 100|%"]
]
 
test 'unplanned
test 'planned</syntaxhighlight>
 
{{out}}
 
<pre>unplanned 0.0%
planned 31.43%</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang=AutoHotkey"autohotkey">NumOfTrials := 20000
randomFailTotal := 0, strategyFailTotal := 0
prisoners := [], drawers := [], Cards := []
Line 942 ⟶ 1,028:
Random Trials : 0.000000 % success rate</pre>
 
=={{header|BASIC256BASIC}}==
==={{header|BASIC256}}===
{{works with|BASIC256|2.0.0.11}}
<syntaxhighlight lang=BASIC256"basic256">
O = 50
N = 2*O
Line 1,032 ⟶ 1,119:
Observed ratio: 0.3052, expected ratio with N=2*O: greater than about 0.30685
</pre>
 
==={{header|True BASIC}}===
{{trans|Yabasic}}
<syntaxhighlight lang="qbasic">FUNCTION trials(prisoners, iterations, optimal)
DIM drawers(100)
FOR i = 1 TO prisoners
LET drawers(i) = i
NEXT i
FOR i = 1 TO iterations
FOR k = 1 TO prisoners
LET x = RND+1
LET p = drawers(x)
LET drawers(x) = drawers(k)
LET drawers(k) = p
NEXT k
FOR prisoner = 1 TO prisoners
LET found = false
IF optimal<>0 THEN LET drawer = prisoner ELSE LET drawer = RND+1
FOR j = 1 TO prisoners/2
LET drawer = drawers(drawer)
IF drawer = prisoner THEN
LET found = true
EXIT FOR
END IF
IF (NOT optimal<>0) THEN LET drawer = RND+1
NEXT j
IF (NOT found<>0) THEN EXIT FOR
NEXT prisoner
LET pardoned = pardoned+found
NEXT i
LET trials = (100*pardoned/iterations)
END FUNCTION
 
LET false = 0
LET true = 1
LET iterations = 10000
PRINT "Simulation count: "; iterations
FOR prisoners = 10 TO 100 STEP 90
LET randon = trials(prisoners,iterations,false)
LET optimal = trials(prisoners,iterations,true)
PRINT "Prisoners: "; prisoners; ", random: "; randon; ", optimal: "; optimal
NEXT prisoners
END</syntaxhighlight>
 
=={{header|BCPL}}==
<syntaxhighlight lang="bcpl">get "libhdr"
 
manifest $(
Line 1,112 ⟶ 1,242:
 
=={{header|C}}==
<syntaxhighlight lang=C"c">
#include<stdbool.h>
#include<stdlib.h>
Line 1,270 ⟶ 1,400:
=={{header|C sharp|C#}}==
{{trans|D}}
<syntaxhighlight lang="csharp">using System;
using System.Linq;
 
Line 1,344 ⟶ 1,474:
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <cstdlib> // for rand
#include <algorithm> // for random_shuffle
#include <iostream> // for output
Line 1,425 ⟶ 1,555:
 
=={{header|Clojure}}==
<syntaxhighlight lang=Clojure"clojure">(ns clojure-sandbox.prisoners)
 
(defn random-drawers []
Line 1,498 ⟶ 1,628:
 
=={{header|CLU}}==
<syntaxhighlight lang="clu">% This program needs to be merged with PCLU's "misc" library
% to use the random number generator.
%
Line 1,618 ⟶ 1,748:
The key here is avoiding the use of GOTO as a means of exiting a loop early.
 
<syntaxhighlight lang="gwbasic">
10 rem 100 prisoners
20 rem set arrays
Line 1,701 ⟶ 1,831:
{{trans|Racket}}
 
<syntaxhighlight lang="lisp">
(defparameter *samples* 10000)
(defparameter *prisoners* 100)
Line 1,760 ⟶ 1,890:
=={{header|Cowgol}}==
 
<syntaxhighlight lang="cowgol">include "cowgol.coh";
include "argv.coh";
 
Line 1,919 ⟶ 2,049:
Based on the Ruby implementation
 
<syntaxhighlight lang="crystal">prisoners = (1..100).to_a
N = 100_000
generate_rooms = ->{ (1..100).to_a.shuffle }
Line 1,947 ⟶ 2,077:
=={{header|D}}==
{{trans|Kotlin}}
<syntaxhighlight lang="d">import std.array;
import std.random;
import std.range;
Line 2,004 ⟶ 2,134:
Optimal play success rate: 31.16100000%
Random play success rate: 0.00000000%</pre>
 
=={{header|Dart}}==
{{trans|Python}}
<syntaxhighlight lang="Dart">
import 'dart:math';
 
int playRandom(int n) {
var rnd = Random();
int pardoned = 0;
List<int> inDrawer = List<int>.generate(100, (i) => i);
List<int> sampler = List<int>.generate(100, (i) => i);
for (int round = 0; round < n; round++) {
inDrawer.shuffle();
bool found = false;
for (int prisoner = 0; prisoner < 100; prisoner++) {
found = false;
sampler.shuffle(rnd);
for (int i = 0; i < 50; i++) {
int reveal = sampler[i];
int card = inDrawer[reveal];
if (card == prisoner) {
found = true;
break;
}
}
if (!found) {
break;
}
}
if (found) {
pardoned++;
}
}
return (pardoned / n * 100).round();
}
 
int playOptimal(int n) {
var rnd = Random();
int pardoned = 0;
bool found = false;
List<int> inDrawer = List<int>.generate(100, (i) => i);
for (int round = 0; round < n; round++) {
inDrawer.shuffle(rnd);
for (int prisoner = 0; prisoner < 100; prisoner++) {
int reveal = prisoner;
found = false;
for (int go = 0; go < 50; go++) {
int card = inDrawer[reveal];
if (card == prisoner) {
found = true;
break;
}
reveal = card;
}
if (!found) {
break;
}
}
if (found) {
pardoned++;
}
}
return (pardoned / n * 100).round();
}
 
void main() {
int n = 100000;
print(" Simulation count: $n");
print(" Random play wins: ${playRandom(n).toStringAsFixed(2)}% of simulations");
print("Optimal play wins: ${playOptimal(n).toStringAsFixed(2)}% of simulations");
}
</syntaxhighlight>
{{out}}
<pre>
Simulation count: 100000
Random play wins: 0.00% of simulations
Optimal play wins: 31.00% of simulations
 
</pre>
 
 
=={{header|Delphi}}==
See [[#Pascal]].
 
=={{header|EasyLang}}==
<syntaxhighlight lang=EasyLang>for i range 100
for i = 1 to 100
drawer[] &= i
sampler drawer[] &= i
sampler[] &= i
.
subr shuffle_drawer
for i = len drawer[] downto 2
r = randomrandint i
swap drawer[r] drawer[i - 1]
.
.
subr play_random
call shuffle_drawer
found for prisoner = 1 to 100
prisoner found = 0
while prisoner < 100 andfor foundi = 1 to 50
found r = 0randint (100 - i)
i card = 0drawer[sampler[r]]
swap sampler[r] sampler[100 - i - 1]
while i < 50 and found = 0
r = random (100if -card = i)prisoner
card found = drawer[sampler[r]]1
swap sampler[r] sampler[100 - i - break 1]
if card = prisoner.
found = 1
.
iif found += 10
. break 1
prisoner += 1.
.
.
subr play_optimal
call shuffle_drawer
found for prisoner = 1 to 100
prisoner reveal = 0prisoner
while prisoner < 100 and found = 10
reveal for i = prisoner1 to 50
found card = 0drawer[reveal]
i if card = 0prisoner
while i < 50 and found = 01
card = drawer[reveal] break 1
if card = prisoner.
found reveal = 1card
.
revealif found = card0
i += break 1
.
.
prisoner += 1
.
.
n = 10000
pardonedwin = 0
for round_ range= 1 to n
call play_random
pardoned win += found
.
print "random: " & 100.0 * pardonedwin / n & "%"
#
pardonedwin = 0
for round_ range= 1 to n
call play_optimal
pardoned win += found
.
print "optimal: " & 100.0 * pardonedwin / n & "%"</syntaxhighlight>
</syntaxhighlight>
{{out}}
<pre>
random: 0.000%
optimal: 30.800%
</pre>
 
=={{header|Ecstasy}}==
<syntaxhighlight lang="ecstasy">
module OneHundredPrisoners {
@Inject Console console;
 
void run() {
console.print($"# of executions: {attempts}");
console.print($"Optimal play success rate: {simulate(tryOpt)}%");
console.print($" Random play success rate: {simulate(tryRnd)}%");
}
 
Int attempts = 10000;
 
Dec simulate(function Boolean(Int[]) allFoundNumber) {
Int[] drawers = new Int[100](i->i);
Int pardoned = 0;
for (Int i : 1..attempts) {
if (allFoundNumber(drawers.shuffled())) {
++pardoned;
}
}
return (pardoned * 1000000 / attempts).toDec() / 10000;
}
 
Boolean tryRnd(Int[] drawers) {
Inmates: for (Int inmate : 0..<100) {
Int[] choices = drawers.shuffled();
for (Int attempt : 0..<50) {
if (drawers[choices[attempt]] == inmate) {
continue Inmates;
}
}
return False;
}
return True;
}
 
Boolean tryOpt(Int[] drawers) {
Inmates: for (Int inmate : 0..<100) {
Int choice = inmate;
for (Int attempt : 0..<50) {
if (drawers[choice] == inmate) {
continue Inmates;
}
choice = drawers[choice];
}
return False;
}
return True;
}
}
</syntaxhighlight>
 
{{out}}
<pre>
# of executions: 10000
Optimal play success rate: 30.1%
Random play success rate: 0%
</pre>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<syntaxhighlight lang="elixir">defmodule HundredPrisoners do
def optimal_room(_, _, _, []), do: []
def optimal_room(prisoner, current_room, rooms, [_ | tail]) do
Line 2,117 ⟶ 2,389:
 
=={{header|F sharp|F#}}==
<syntaxhighlight lang="fsharp">let rnd = System.Random()
let shuffled min max =
[|min..max|] |> Array.sortBy (fun _ -> rnd.Next(min,max+1))
Line 2,161 ⟶ 2,433:
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: arrays formatting fry io kernel math random sequences ;
 
: setup ( -- seq seq ) 100 <iota> dup >array randomize ;
Line 2,190 ⟶ 2,462:
=={{header|FOCAL}}==
 
<syntaxhighlight lang=FOCAL"focal">01.10 T %5.02," RANDOM";S CU=0
01.20 F Z=1,2000;D 5;S CU=CU+SU
01.30 T CU/20,!,"OPTIMAL";S CU=0
Line 2,246 ⟶ 2,518:
Run the two strategies (random and follow the card number) 10,000 times each, and show number or successes.
 
<syntaxhighlight lang="forth">INCLUDE ran4.seq
 
100 CONSTANT #drawers
Line 2,343 ⟶ 2,615:
 
=={{header|Fortran}}==
<syntaxhighlight lang=FORTRAN"fortran">SUBROUTINE SHUFFLE_ARRAY(INT_ARRAY)
! Takes an input array and shuffles the elements by swapping them
! in pairs in turn 10 times
Line 2,507 ⟶ 2,779:
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">#include once "knuthshuf.bas" 'use the routines in https://rosettacode.org/wiki/Knuth_shuffle#FreeBASIC
 
function gus( i as long, strat as boolean ) as long
Line 2,549 ⟶ 2,821:
 
print using "For prisoners using the strategy we had ####### successes and ####### failures.";c_success;c_fail</syntaxhighlight>
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
include "Tlbx GameplayKit.incl"
 
_prisoners = 100
_instances = 10000
 
local fn DrawersArray as CFArrayRef
long index
CFMutableArrayRef temp = fn MutableArrayWithCapacity(100)
for index = 0 to 99
MutableArrayAddObject( temp, @(index) )
next
end fn = fn ArrayShuffledArray( temp )
 
 
local fn RandomResult( drawers as CFArrayRef ) as BOOL
long prisoner, i, drawer, total = 0
MutableIndexSetRef set
for prisoner = 0 to _prisoners - 1
set = fn MutableIndexSetInit
for i = 1 to _prisoners/2
drawer = rnd(_prisoners)-1
while ( fn IndexSetContainsIndex( set, intVal( drawers[drawer] ) ) )
drawer = rnd(_prisoners)-1
wend
MutableIndexSetAddIndex( set, intVal( drawers[drawer] ) )
if ( fn IndexSetContainsIndex( set, prisoner ) )
total++
break
end if
next
next
end fn = ( total == _prisoners )
 
 
local fn OptimalResult( drawers as CFArrayRef ) as BOOL
long prisoner, drawer, i, card, total = 0
for prisoner = 0 to _prisoners - 1
drawer = prisoner
for i = 1 to _prisoners/2
card = intVal( drawers[drawer] )
if ( card == prisoner )
total++
break
end if
drawer = card
next
next
end fn = ( total == _prisoners )
 
 
void local fn DoIt
static double sTime = 0.0
block TimerRef timer = timerbegin , 0.001, YES
sTime += 0.001
cls
printf @"Compute time: %.3f\n",sTime
timerend
dispatchglobal
long instance, randomTotal = 0, optimalTotal = 0
CFArrayRef drawers
for instance = 1 to _instances
drawers = fn DrawersArray
if ( fn RandomResult( drawers ) ) then randomTotal++
if ( fn OptimalResult( drawers ) ) then optimalTotal++
next
dispatchmain
TimerInvalidate( timer )
cls
print @"Prisoners: "_prisoners
print @"Instances: "_instances
printf @"Random - fail: %ld, success: %ld (%.2f%%)",_instances-randomTotal,randomTotal,(double)randomTotal/(double)_instances*100.0
printf @"Optimal - fail: %ld, success: %ld (%.2f%%)\n",_instances-optimalTotal,optimalTotal,(double)optimalTotal/(double)_instances*100.0
printf @"Compute time: %.3f\n",sTime
dispatchend
dispatchend
end fn
 
random
 
window 1, @"100 Prisoners"
 
fn DoIt
 
HandleEvents
</syntaxhighlight>
 
{{out}}
<pre>
Prisoners: 100
Instances: 10000
Random - fail: 10000, success: 0 (0.00%)
Optimal - fail: 6896, success: 3104 (31.04%)
 
Compute time: 7.856
</pre>
 
=={{header|Gambas}}==
Implementation of the '100 Prisoners' program written in VBA. Tested in Gambas 3.15.2
<syntaxhighlight lang="gambas">' Gambas module file
 
Public DrawerArray As Long[]
Line 2,732 ⟶ 3,112:
Trials/sec: 114.9</pre>
 
 
=={{header|GDScript}}==
{{works with|Godot|4.0}}
 
<syntaxhighlight lang="gdscript">
extends MainLoop
 
 
enum Strategy {Random, Optimal}
 
const prisoner_count := 100
 
 
func get_random_drawers() -> Array[int]:
var drawers: Array[int] = []
drawers.resize(prisoner_count)
for i in range(0, prisoner_count):
drawers[i] = i + 1
drawers.shuffle()
return drawers
 
 
var random_strategy = func(drawers: Array[int], prisoner: int) -> bool:
# Randomly selecting 50 drawers is equivalent to shuffling and picking the first 50
var drawerCopy: Array[int] = drawers.duplicate()
drawerCopy.shuffle()
for i in range(50):
if drawers[drawerCopy[i]-1] == prisoner:
return true
return false
 
 
var optimal_strategy = func(drawers: Array[int], prisoner: int) -> bool:
var choice: int = prisoner
for _i in range(50):
var drawer_value: int = drawers[choice-1]
if drawer_value == prisoner:
return true
choice = drawer_value
return false
 
 
func play_all(drawers: Array[int], strategy: Callable) -> bool:
for prisoner in range(1, prisoner_count+1):
if not strategy.call(drawers, prisoner):
return false
return true
 
 
func _process(_delta: float) -> bool:
# Constant seed for reproducibility, call randomize() in real use
seed(1234)
 
const SAMPLE_SIZE: int = 10_000
 
var random_successes: int = 0
for i in range(SAMPLE_SIZE):
if play_all(get_random_drawers(), random_strategy):
random_successes += 1
 
var optimal_successes: int = 0
for i in range(SAMPLE_SIZE):
if play_all(get_random_drawers(), optimal_strategy):
optimal_successes += 1
 
print("Random play: %%%f" % (100.0 * random_successes/SAMPLE_SIZE))
print("Optimal play: %%%f" % (100.0 * optimal_successes/SAMPLE_SIZE))
 
return true # Exit
 
</syntaxhighlight>
 
{{out}}
<pre>
Random play: %0.000000
Optimal play: %31.700000
</pre>
 
=={{header|Go}}==
<syntaxhighlight lang="go">package main
 
import (
Line 2,819 ⟶ 3,276:
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang="groovy">import java.util.function.Function
import java.util.stream.Collectors
import java.util.stream.IntStream
Line 2,886 ⟶ 3,343:
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">import System.Random
import Control.Monad.State
 
Line 2,967 ⟶ 3,424:
 
=={{header|J}}==
<syntaxhighlight lang=J"j">
NB. game is solvable by optimal strategy when the length (#) of the
NB. longest (>./) cycle (C.) is at most 50.
Line 2,996 ⟶ 3,453:
 
=={{header|Janet}}==
<syntaxhighlight lang="janet">
(math/seedrandom (os/cryptorand 8))
 
Line 3,062 ⟶ 3,519:
=={{header|Java}}==
{{trans|Kotlin}}
<syntaxhighlight lang="java">import java.util.Collections;
import java.util.List;
import java.util.Objects;
Line 3,135 ⟶ 3,592:
{{trans|C#}}
{{Works with|Node.js}}
<syntaxhighlight lang="javascript">
const _ = require('lodash');
 
Line 3,250 ⟶ 3,707:
{{works with|JavaScript|Node.js 16.13.0 (LTS)}}
 
<syntaxhighlight lang=JavaScript"javascript">"use strict";
 
// Simulate several thousand instances of the game:
Line 3,366 ⟶ 3,823:
 
jq does not have a built-in PRNG and so the jq program used here presupposes an external source of entropy such as /dev/urandom. The output shown below was obtained by invoking jq as follows:
<syntaxhighlight lang="sh">export LC_ALL=C
< /dev/urandom tr -cd '0-9' | fold -w 1 | jq -MRcnr -f 100-prisoners.jq</syntaxhighlight>
 
Line 3,374 ⟶ 3,831:
 
'''Preliminaries'''
<syntaxhighlight lang="jq">def count(s): reduce s as $x (0; .+1);
 
# Output: a PRN in range(0;$n) where $n is .
Line 3,399 ⟶ 3,856:
 
'''np Prisoners'''
<syntaxhighlight lang="jq"># Output: if all the prisoners succeed, emit true, otherwise false
def optimalStrategy($drawers; np):
# Does prisoner $p succeed?
Line 3,467 ⟶ 3,924:
=={{header|Julia}}==
{{trans|Python}}
<syntaxhighlight lang="julia">using Random, Formatting
 
function randomplay(n, numprisoners=100)
Line 3,513 ⟶ 3,970:
Random play wins: 0.00000000% of simulations.
Optimal play wins: 31.18100000% of simulations.
</pre>
 
=={{header|Koka}}==
Imperative equivalent (using mutable vectors, but also with exceptional control flow)
 
<syntaxhighlight lang="koka">
import std/num/random
 
value struct drawer
num: int
open: bool = False
 
inline extern unsafe-assign : forall<a> ( v : vector<a>, i : ssize_t, x : a ) -> total ()
c "kk_vector_unsafe_assign"
 
fun createDrawers()
val drawers = vector(100, Drawer(0,open=True))
for(0, 99) fn(i)
var found := False
while {!found}
val r = random-int() % 100
if drawers[r].open then
drawers.unsafe-assign(r.ssize_t, Drawer(i))
found := True
else
()
drawers
 
fun closeAll(d:vector<drawer>)
for(0,99) fn(i)
d.unsafe-assign(i.ssize_t, d[i](open=False))
 
effect fail
final ctl failed(): a
 
fun open-random(drawers: vector<drawer>)
val r = random-int() % 100
val opened = drawers[r]
if opened.open then
open-random(drawers)
else
drawers.unsafe-assign(r.ssize_t, opened(open=True))
opened.num
 
fun random-approach(drawers: vector<drawer>)
for(0, 99) fn(i)
var found := False
for(0, 49) fn(j)
val opened = open-random(drawers)
if opened == i then
found := True
else
()
if !found then
failed()
else
drawers.closeAll()
 
fun optimal-approach(drawers: vector<drawer>)
for(0, 99) fn(i)
var found := False
var drawer := i;
for(0, 49) fn(j)
val opened = drawers[drawer]
if opened.open then
failed()
if opened.num == i then
found := True
else
drawers.unsafe-assign(drawer.ssize_t, opened(open=True))
drawer := opened.num
if !found then
failed()
else
drawers.closeAll()
()
 
fun run-trials(f, num-trials)
var num_success := 0
for(0,num-trials - 1) fn(i)
val drawers = createDrawers()
with handler
return(x) ->
num_success := num_success + 1
final ctl failed() ->
()
f(drawers)
num_success
 
fun main()
val num_trials = 1000
val num_success_random = run-trials(random-approach, num_trials)
val num_success_optimal = run-trials(optimal-approach, num_trials)
println("Number of trials: " ++ num_trials.show)
println("Random approach: wins " ++ num_success_random.show ++ " (" ++ (num_success_random.float64 * 100.0 / num_trials.float64).show(2) ++ "%)")
println("Optimal approach: wins " ++ num_success_optimal.show ++ " (" ++ (num_success_optimal.float64 * 100.0 / num_trials.float64).show(2) ++ "%)")
</syntaxhighlight>
 
{{out}}
<pre>
Number of trials: 1000
Random approach: wins 0 (0.00%)
Optimal approach: wins 319 (31.90%)
</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">val playOptimal: () -> Boolean = {
val secrets = (0..99).toMutableList()
var ret = true
Line 3,580 ⟶ 4,140:
=={{header|Lua}}==
{{trans|lang}}
<syntaxhighlight lang="lua">function shuffle(tbl)
for i = #tbl, 2, -1 do
local j = math.random(i)
Line 3,671 ⟶ 4,231:
 
Don"t bother to simulate the random method: each prisoner has a probability p to win with:
<syntaxhighlight lang="maple">p:=simplify(1-product(1-1/(2*n-k),k=0..n-1));
# p=1/2</syntaxhighlight>
 
Since all prisoners' attempts are independent, the probability that they all win is:
 
<syntaxhighlight lang="maple">p^100;
evalf(%);
 
Line 3,688 ⟶ 4,248:
Here is a simulation based on this, assuming that the permutation of numbers in boxes is random:
 
<syntaxhighlight lang="maple">a:=[seq(max(GroupTheory[PermCycleType](Perm(Statistics[Shuffle]([$1..100])))),i=1..100000)]:
nops(select(n->n<=50,a))/nops(a);
evalf(%);
Line 3,698 ⟶ 4,258:
It can be [https://en.wikipedia.org/wiki/Random_permutation_statistics#One_hundred_prisoners proved] that the probability with the second strategy is in fact:
 
<syntaxhighlight lang="maple">1-(harmonic(100)-harmonic(50));
evalf(%);
 
Line 3,705 ⟶ 4,265:
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang=Mathematica"mathematica">ClearAll[PlayRandom, PlayOptimal]
PlayRandom[n_] :=
Module[{pardoned = 0, sampler, indrawer, found, reveal},
Line 3,762 ⟶ 4,322:
 
=={{header|MATLAB}}==
<syntaxhighlight lang=MATLAB"matlab">function [randSuccess,idealSuccess]=prisoners(numP,numG,numT)
%numP is the number of prisoners
%numG is the number of guesses
Line 3,828 ⟶ 4,388:
=={{header|MiniScript}}==
{{trans|Python}}
<syntaxhighlight lang=MiniScript"miniscript">playRandom = function(n)
// using 0-99 instead of 1-100
pardoned = 0
Line 3,883 ⟶ 4,443:
=={{header|Nim}}==
Imperative style.
<syntaxhighlight lang=Nim"nim">import random, sequtils, strutils
 
type
Line 3,939 ⟶ 4,499:
{{works with|Free Pascal}}
searching the longest cycle length as stated on talk page and increment an counter for that cycle length.
<syntaxhighlight lang="pascal">program Prisoners100;
 
const
Line 4,150 ⟶ 4,710:
Randomly 0.00% get pardoned out of 100000 checking max 0</pre>
=== Alternative for optimized ===
<syntaxhighlight lang="pascal">program Prisoners100;
{$IFDEF FPC}
{$MODE DELPHI}{$OPTIMIZATION ON,ALL}
Line 4,332 ⟶ 4,892:
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 4,395 ⟶ 4,955:
Built so you could easily build and test your own strategies.
 
<syntaxhighlight lang="picolisp">(de shuffle (Lst)
(by '(NIL (rand)) sort Lst) )
 
Line 4,441 ⟶ 5,001:
 
Then run
<syntaxhighlight lang="picolisp">(test-strategy-n-times '+Random 10000)
(test-strategy-n-times '+Optimal 10000)</syntaxhighlight>
 
Line 4,451 ⟶ 5,011:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<syntaxhighlight lang="phix">
<span style="color: #008080;">function</span> <span style="color: #000000;">play<span style="color: #0000FF;">(<span style="color: #004080;">integer</span> <span style="color: #000000;">prisoners<span style="color: #0000FF;">,</span> <span style="color: #000000;">iterations<span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">optimal<span style="color: #0000FF;">)</span>
function play(integer prisoners, iterations, bool optimal)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">drawers</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle<span style="color: #0000FF;">(<span style="color: #7060A8;">tagset<span style="color: #0000FF;">(<span style="color: #000000;">prisoners<span style="color: #0000FF;">)<span style="color: #0000FF;">)</span>
sequence drawers = shuffle(tagset(prisoners))
<span style="color: #004080;">integer</span> <span style="color: #000000;">pardoned</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
integer pardoned = 0
<span style="color: #004080;">bool</span> <span style="color: #000000;">found</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
bool found = false
<span style="color: #008080;">for</span> <span style="color: #000000;">i<span style="color: #0000FF;">=<span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">iterations</span> <span style="color: #008080;">do</span>
for i=1 to iterations do
<span style="color: #000000;">drawers</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle<span style="color: #0000FF;">(<span style="color: #000000;">drawers<span style="color: #0000FF;">)</span>
drawers = shuffle(drawers)
<span style="color: #008080;">for</span> <span style="color: #000000;">prisoner<span style="color: #0000FF;">=<span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">prisoners</span> <span style="color: #008080;">do</span>
for prisoner=1 to prisoners do
<span style="color: #000000;">found</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
found = false
<span style="color: #004080;">integer</span> <span style="color: #000000;">drawer</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff<span style="color: #0000FF;">(<span style="color: #000000;">optimal<span style="color: #0000FF;">?<span style="color: #000000;">prisoner<span style="color: #0000FF;">:<span style="color: #7060A8;">rand<span style="color: #0000FF;">(<span style="color: #000000;">prisoners<span style="color: #0000FF;">)<span style="color: #0000FF;">)</span>
integer drawer = iff(optimal?prisoner:rand(prisoners))
<span style="color: #008080;">for</span> <span style="color: #000000;">j<span style="color: #0000FF;">=<span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">prisoners<span style="color: #0000FF;">/<span style="color: #000000;">2</span> <span style="color: #008080;">do</span>
for j=1 to prisoners/2 do
<span style="color: #000000;">drawer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">drawers<span style="color: #0000FF;">[<span style="color: #000000;">drawer<span style="color: #0000FF;">]</span>
drawer = drawers[drawer]
<span style="color: #008080;">if</span> <span style="color: #000000;">drawer<span style="color: #0000FF;">==<span style="color: #000000;">prisoner</span> <span style="color: #008080;">then</span> <span style="color: #000000;">found</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if drawer==prisoner then found = true exit end if
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">optimal</span> <span style="color: #008080;">then</span> <span style="color: #000000;">drawer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rand<span style="color: #0000FF;">(<span style="color: #000000;">prisoners<span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if not optimal then drawer = rand(prisoners) end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">found</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if not found then exit end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #000000;">pardoned</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">found</span>
pardoned += found
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">return</span> <span style="color: #000000;">100<span style="color: #0000FF;">*<span style="color: #000000;">pardoned<span style="color: #0000FF;">/<span style="color: #000000;">iterations</span>
return 100*pardoned/iterations
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
end function
<span style="color: #008080;">constant</span> <span style="color: #000000;">iterations</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">100<span style="color: #000000;">_000</span>
constant iterations = 100_000
<span style="color: #7060A8;">printf<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"Simulation count: %d\n"<span style="color: #0000FF;">,<span style="color: #000000;">iterations<span style="color: #0000FF;">)</span>
printf(1,"Simulation count: %d\n",iterations)
<span style="color: #008080;">for</span> <span style="color: #000000;">prisoners<span style="color: #0000FF;">=<span style="color: #000000;">10</span> <span style="color: #008080;">to</span> <span style="color: #000000;">100</span> <span style="color: #008080;">by</span> <span style="color: #000000;">90</span> <span style="color: #008080;">do</span>
for prisoners in {10,100} do
<span style="color: #004080;">atom</span> <span style="color: #000000;">random</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">play<span style="color: #0000FF;">(<span style="color: #000000;">prisoners<span style="color: #0000FF;">,<span style="color: #000000;">iterations<span style="color: #0000FF;">,<span style="color: #004600;">false<span style="color: #0000FF;">)<span style="color: #0000FF;">,</span>
atom random = play(prisoners,iterations,false),
<span style="color: #000000;">optimal</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">play<span style="color: #0000FF;">(<span style="color: #000000;">prisoners<span style="color: #0000FF;">,<span style="color: #000000;">iterations<span style="color: #0000FF;">,<span style="color: #004600;">true<span style="color: #0000FF;">)</span>
optimal = play(prisoners,iterations,true)
<span style="color: #7060A8;">printf<span style="color: #0000FF;">(<span style="color: #000000;">1<span style="color: #0000FF;">,<span style="color: #008000;">"Prisoners:%d, random:%g, optimal:%g\n"<span style="color: #0000FF;">,<span style="color: #0000FF;">{<span style="color: #000000;">prisoners<span style="color: #0000FF;">,<span style="color: #000000;">random<span style="color: #0000FF;">,<span style="color: #000000;">optimal<span style="color: #0000FF;">}<span style="color: #0000FF;">)</span>
printf(1,"Prisoners:%d, random:%g, optimal:%g\n",{prisoners,random,optimal})
<span style="color: #008080;">end</span> <span style="color: #008080;">for
end for
<!--</syntaxhighlight>-->
</syntaxhighlight>
{{out}}
<pre>
Line 4,490 ⟶ 5,051:
=={{header|Phixmonti}}==
{{trans|Yabasic}}
<syntaxhighlight lang=Phixmonti"phixmonti">/# Rosetta Code problem: http://rosettacode.org/wiki/100_prisoners
by Galileo, 05/2022 #/
 
Line 4,543 ⟶ 5,104:
 
=={{header|PL/M}}==
<syntaxhighlight lang="plm">100H:
/* PARAMETERS */
DECLARE N$DRAWERS LITERALLY '100'; /* AMOUNT OF DRAWERS */
Line 4,703 ⟶ 5,264:
 
=={{header|Pointless}}==
<syntaxhighlight lang="pointless">optimalSeq(drawers, n) =
iterate(ind => drawers[ind - 1], n)
|> takeUntil(ind => drawers[ind - 1] == n)
Line 4,755 ⟶ 5,316:
=={{header|PowerShell}}==
{{trans|Chris}}
<syntaxhighlight lang=PowerShell"powershell">
### Clear Screen from old Output
Clear-Host
Line 4,886 ⟶ 5,447:
 
=={{header|Processing}}==
<syntaxhighlight lang=Processing"processing">IntList drawers = new IntList();
int trials = 100000;
int succes_count;
Line 4,955 ⟶ 5,516:
 
=={{header|PureBasic}}==
<syntaxhighlight lang=PureBasic"purebasic">#PRISONERS=100
#DRAWERS =100
#LOOPS = 50
Line 5,001 ⟶ 5,562:
=={{header|Python}}==
===Procedural===
<syntaxhighlight lang="python">import random
 
def play_random(n):
Line 5,058 ⟶ 5,619:
 
Or, an alternative procedural approach:
<syntaxhighlight lang="python"># http://rosettacode.org/wiki/100_prisoners
 
import random
Line 5,160 ⟶ 5,721:
 
{{Works with|Python|3.7}}
<syntaxhighlight lang="python">'''100 Prisoners'''
 
from random import randint, sample
Line 5,354 ⟶ 5,915:
 
=={{header|R}}==
<syntaxhighlight lang=R"r">t = 100000 #number of trials
success.r = rep(0,t) #this will keep track of how many prisoners find their ticket on each trial for the random method
success.o = rep(0,t) #this will keep track of how many prisoners find their ticket on each trial for the optimal method
Line 5,391 ⟶ 5,952:
 
=={{header|QB64}}==
<syntaxhighlight lang=QB64"qb64">
Const Found = -1, Searching = 0, Status = 1, Tries = 2
Const Attempt = 1, Victories = 2, RandomW = 1, ChainW = 2
Line 5,475 ⟶ 6,036:
 
=={{header|Quackery}}==
<syntaxhighlight lang=Quackery"quackery"> [ this ] is 100prisoners.qky
 
[ dup size 2 / split ] is halve ( [ --> [ [ )
Line 5,523 ⟶ 6,084:
 
'''Output:'''
<syntaxhighlight lang=Quackery"quackery">/O> [ $ '100prisoners.qky' loadfile ] now!
... simulate
...
Line 5,532 ⟶ 6,093:
 
=={{header|Racket}}==
<syntaxhighlight lang="racket">#lang racket
(require srfi/1)
 
Line 5,576 ⟶ 6,137:
Also test with 10 prisoners to verify that the logic is correct for random selection. Random selection should succeed with 10 prisoners at a probability of (1/2)**10, so in 100_000 simulations, should get pardons about .0977 percent of the time.
 
<syntaxhighlight lang=perl6"raku" line>unit sub MAIN (:$prisoners = 100, :$simulations = 10000);
my @prisoners = ^$prisoners;
my $half = floor +@prisoners / 2;
Line 5,633 ⟶ 6,194:
</pre>
=={{header|Red}}==
<syntaxhighlight lang=Rebol"rebol">
Red []
 
Line 5,684 ⟶ 6,245:
 
=={{header|REXX}}==
<syntaxhighlight lang="rexx">/*REXX program to simulate the problem of 100 prisoners: random, and optimal strategy.*/
parse arg men trials seed . /*obtain optional arguments from the CL*/
if men=='' | men=="," then men= 100 /*number of prisoners for this run.*/
Line 5,744 ⟶ 6,305:
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">prisoners = [*1..100]
N = 10_000
generate_rooms = ->{ [nil]+[*1..100].shuffle }
Line 5,777 ⟶ 6,338:
 
Cargo.toml
<syntaxhighlight lang="toml">[dependencies]
rand = '0.7.2'</syntaxhighlight>
 
src/main.rs
<syntaxhighlight lang="rust">extern crate rand;
 
use rand::prelude::*;
Line 5,829 ⟶ 6,390:
 
=={{header|Sather}}==
<syntaxhighlight lang="sather">class MAIN is
shuffle (a: ARRAY{INT}) is
ARR_PERMUTE_ALG{INT, ARRAY{INT}}::shuffle(a);
Line 5,899 ⟶ 6,460:
=={{header|Scala}}==
{{trans|Java}}
<syntaxhighlight lang="scala">import scala.util.Random
import scala.util.control.Breaks._
 
Line 5,963 ⟶ 6,524:
Optimal play success rate: 31.201000%
Random play success rate: 0.000000%</pre>
 
=={{header|SETL}}==
<syntaxhighlight lang="setl">program prisoners;
setrandom(0);
strategies := {
["Optimal", routine optimal_strategy],
["Random", routine random_strategy]
};
runs := 10000;
 
loop for strategy = strategies(name) do
successes := run_simulations(strategy, runs);
print(rpad(name + ":", 10), successes * 100 / runs, "%");
end loop;
proc run_simulations(strategy, amount);
loop for i in [1..amount] do
successes +:= if simulate(strategy) then 1 else 0 end;
end loop;
return successes;
end proc;
proc simulate(strategy);
drawers := [1..100];
shuffle(drawers);
loop for prisoner in [1..100] do
if not call(strategy, drawers, prisoner) then
return false;
end if;
end loop;
return true;
end proc;
proc optimal_strategy(drawers, prisoner);
d := prisoner;
loop for s in [1..50] do
if (d := drawers(d)) = prisoner then
return true;
end if;
end loop;
return false;
end proc;
proc random_strategy(drawers, prisoner);
loop for s in [1..50] do
if drawers(1+random(#drawers-1)) = prisoner then
return true;
end if;
end loop;
return false;
end proc;
proc shuffle(rw drawers);
loop for i in [1..#drawers] do
j := i+random(#drawers-i);
[drawers(i), drawers(j)] := [drawers(j), drawers(i)];
end loop;
end proc;
end program;</syntaxhighlight>
{{out}}
<pre>Optimal: 31.26 %
Random: 0 %</pre>
 
=={{header|Swift}}==
 
<syntaxhighlight lang="swift">import Foundation
 
struct PrisonersGame {
Line 6,056 ⟶ 6,681:
=={{header|Tcl}}==
{{trans|Common Lisp}}
<syntaxhighlight lang="tcl">set Samples 10000
set Prisoners 100
set MaxGuesses 50
Line 6,174 ⟶ 6,799:
{{works with|Transact-SQL|SQL Server 2017}}
 
<syntaxhighlight lang=Transact"transact-SQLsql">USE rosettacode;
GO
 
Line 6,357 ⟶ 6,982:
Probability of success with "random" strategy: 0.00
Probability of success with "optimal" strategy: 31.00</pre>
 
=={{header|Transd}}==
For checking the correctness of simulation of random selection, we can decrease the number of prisoners and increase the number of runs. Then, for 10 prisoners and 100,000 runs we should get 0.5^10 * 100,000 = about 0.1% of wins.
 
<syntaxhighlight lang="Scheme">#lang transd
 
MainModule: {
simRandom: (λ numPris Int() nRuns Int()
locals: nSucc 0.0
(for n in Range(nRuns) do
(with draws (for i in Range(numPris) project i) succ 1
(for prisN in Range(numPris) do
(shuffle draws)
(if (not (is-el Range(in: draws 0 (/ numPris 2)) prisN))
(= succ 0) break))
(+= nSucc succ)
) )
(ret (* (/ nSucc nRuns) 100))
),
 
simOptimal: (λ numPris Int() nRuns Int()
locals: nSucc 0.0
(for n in Range(nRuns) do
(with draws (for i in Range(numPris) project i) succ 0 nextDraw 0
(shuffle draws)
(for prisN in Range(numPris) do (= nextDraw prisN) (= succ 0)
(for i in Range( (/ numPris 2)) do
(= nextDraw (get draws nextDraw))
(if (== nextDraw prisN) (= succ 1) break))
(if (not succ) break))
(+= nSucc succ)
) )
(ret (* (/ nSucc nRuns) 100))
),
 
_start: (λ
(lout prec: 4 :fixed "Random play: " (simRandom 100 10000) "% of wins")
(lout "Strategic play: " (simOptimal 100 10000) "% of wins")
(lout "Check random play: " (simRandom 10 100000) "% of wins")
)
}</syntaxhighlight>
{{out}}
<pre>
Random play: 0.0000% of wins
Strategic play: 31.4500% of wins
Check random play: 0.1040% of wins
</pre>
 
=={{header|VBA}}/{{header|Visual Basic}}==
 
<syntaxhighlight lang="vb">Sub HundredPrisoners()
 
NumberOfPrisoners = Int(InputBox("Number of Prisoners", "Prisoners", 100))
Line 6,514 ⟶ 7,186:
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Module Module1
 
Function PlayOptimal() As Boolean
Line 6,585 ⟶ 7,257:
 
=={{header|VBScript}}==
<syntaxhighlight lang=VB"vb">
option explicit
const npris=100
Line 6,654 ⟶ 7,326:
</pre>
 
=={{header|V (Vlang)}}==
{{trans|Wren}}
<syntaxhighlight lang="v (vlang)">import rand
import rand.seed
// Uses 0-based numbering rather than 1-based numbering throughout.
Line 6,739 ⟶ 7,411:
{{trans|Go}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang=ecmascript"wren">import "random" for Random
import "./fmt" for Fmt
 
var rand = Random.new()
Line 6,781 ⟶ 7,453:
}
if (!nextPrisoner) {
nextTrial = true
break
}
}
Line 6,814 ⟶ 7,486:
 
=={{header|XPL0}}==
<syntaxhighlight lang=XPL0"xpl0">int Drawer(100);
 
proc KShuffle; \Randomly rearrange the cards in the drawers
Line 6,881 ⟶ 7,553:
=={{header|Yabasic}}==
{{trans|Phix}}
<syntaxhighlight lang=Yabasic"yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/100_prisoners
// by Galileo, 05/2022
 
Line 6,919 ⟶ 7,591:
Prisoners: 100, random: 0, optimal: 31.2
---Program done, press RETURN---</pre>
 
=={{header|Zig}}==
 
{{Works with|Zig|0.11.x}}
{{Works with|Zig|0.12.0-dev.1604+caae40c21}}
 
<syntaxhighlight lang="zig">const std = @import("std");
 
pub const Cupboard = struct {
comptime {
std.debug.assert(u7 == std.math.IntFittingRange(0, 100));
}
 
pub const Drawer = packed struct(u8) {
already_visited: bool,
card: u7,
};
 
drawers: [100]Drawer,
randomizer: std.rand.Random,
 
/// Cupboard is not shuffled after initialization,
/// it is shuffled during `play` execution.
pub fn init(random: std.rand.Random) Cupboard {
var drawers: [100]Drawer = undefined;
for (&drawers, 0..) |*drawer, i| {
drawer.* = .{
.already_visited = false,
.card = @intCast(i),
};
}
 
return .{
.drawers = drawers,
.randomizer = random,
};
}
 
pub const Decision = enum {
pardoned,
sentenced,
};
 
pub const Strategy = enum {
follow_card,
random,
 
pub fn decisionOfPrisoner(strategy: Strategy, cupboard: *Cupboard, prisoner_id: u7) Decision {
switch (strategy) {
.random => {
return for (0..50) |_| {
// If randomly chosen drawer was already opened,
// throw dice again.
const drawer = try_throw_random: while (true) {
const random_i = cupboard.randomizer.uintLessThan(u7, 100);
const drawer = &cupboard.drawers[random_i];
 
if (!drawer.already_visited)
break :try_throw_random drawer;
};
std.debug.assert(!drawer.already_visited);
defer drawer.already_visited = true;
 
if (drawer.card == prisoner_id)
break .pardoned;
} else .sentenced;
},
.follow_card => {
var drawer_i = prisoner_id;
return for (0..50) |_| {
const drawer = &cupboard.drawers[drawer_i];
std.debug.assert(!drawer.already_visited);
defer drawer.already_visited = true;
 
if (drawer.card == prisoner_id)
break .pardoned
else
drawer_i = drawer.card;
} else .sentenced;
},
}
}
};
 
pub fn play(cupboard: *Cupboard, strategy: Strategy) Decision {
cupboard.randomizer.shuffleWithIndex(Drawer, &cupboard.drawers, u7);
 
// Decisions for all 100 prisoners.
var all_decisions: [100]Decision = undefined;
for (&all_decisions, 0..) |*current_decision, prisoner_id| {
// Make decision for current prisoner
current_decision.* = strategy.decisionOfPrisoner(cupboard, @intCast(prisoner_id));
 
// Close all drawers after one step.
for (&cupboard.drawers) |*drawer|
drawer.already_visited = false;
}
 
// If there is at least one sentenced person, everyone are sentenced.
return for (all_decisions) |decision| {
if (decision == .sentenced)
break .sentenced;
} else .pardoned;
}
 
pub fn runSimulation(cupboard: *Cupboard, strategy: Cupboard.Strategy, total: u32) void {
var success: u32 = 0;
for (0..total) |_| {
const result = cupboard.play(strategy);
if (result == .pardoned) success += 1;
}
 
const ratio = @as(f32, @floatFromInt(success)) / @as(f32, @floatFromInt(total));
 
const stdout = std.io.getStdOut();
const stdout_w = stdout.writer();
 
stdout_w.print(
\\
\\Strategy: {s}
\\Total runs: {d}
\\Successful runs: {d}
\\Failed runs: {d}
\\Success rate: {d:.4}%.
\\
, .{
@tagName(strategy),
total,
success,
total - success,
ratio * 100.0,
}) catch {}; // Do nothing on error
}
};</syntaxhighlight>
 
<syntaxhighlight lang="zig">const std = @import("std");
 
pub fn main() std.os.GetRandomError!void {
var prnd = std.rand.DefaultPrng.init(seed: {
var init_seed: u64 = undefined;
try std.os.getrandom(std.mem.asBytes(&init_seed));
break :seed init_seed;
});
const random = prnd.random();
 
var cupboard = Cupboard.init(random);
 
cupboard.runSimulation(.follow_card, 10_000);
cupboard.runSimulation(.random, 10_000);
}</syntaxhighlight>
 
{{out}}
<pre>
 
Strategy: follow_card
Total runs: 10000
Successful runs: 3049
Failed runs: 6951
Success rate: 30.4900%.
 
Strategy: random
Total runs: 10000
Successful runs: 0
Failed runs: 10000
Success rate: 0.0000%.
 
</pre>
 
=={{header|zkl}}==
<syntaxhighlight lang="zkl">const SLOTS=100, PRISONERS=100, TRIES=50, N=10_000;
fcn oneHundredJDI{ // just do it strategy
cupboard,picks := [0..SLOTS-1].walk().shuffle(), cupboard.copy();
Line 6,937 ⟶ 7,776:
True // all found their number
}</syntaxhighlight>
<syntaxhighlight lang="zkl">s:=N.pump(Ref(0).incN,oneHundredJDI).value.toFloat()/N*100;
println("Just do it strategy (%,d simulatations): %.2f%%".fmt(N,s));
 
Line 6,948 ⟶ 7,787:
</pre>
And a sanity check (from the Raku entry):
<syntaxhighlight lang="zkl">const SLOTS=100, PRISONERS=10, TRIES=50, N=100_000;</syntaxhighlight>
{{out}}
<pre>
162

edits