Rebol3 Code Examplex


100 prisoners

Model the probabilistic strategy puzzle where prisoners must find their numbers under strict constraints.

Rebol [
    title: "Rosetta code: 100 prisoners"
    file: %100_prisoners.r3
    url: https://rosettacode.org/wiki/100_prisoners
    needs: 3.0.0
    note: "Based on Red language implementation!"
]

random/seed 1
prisoners: 100                     ;; Total number of prisoners in the puzzle
K_runs: 10000                      ;; Number of simulation runs to perform

rand_arr: make block! prisoners         ;; Will hold the numbers 1..100
repeat n prisoners [append rand_arr n]  ;; Fill rand_arr with [1 2 3 ... 100]

;; --------------------------------------------------
;; strat_optimal: "optimal" strategy from the puzzle
;; Each prisoner starts at the locker with their own number,
;; then follows the chain inside the lockers until they find their number
;; or until they have opened 50 lockers.
;; Returns TRUE if the prisoner finds their own number, FALSE otherwise.
;; --------------------------------------------------
strat_optimal: func [pris /local locker][
    locker: pris                                    ;; Start at 'own-numbered' locker
    loop 50 [
        if Board/:locker = pris [ return true ]     ;; Found prisoner's number? -> success
        locker: Board/:locker                       ;; Move to the locker whose number was inside
    ]
    false                                           ;; Not found within 50 tries -> fail
]

;; --------------------------------------------------
;; strat_rand: "random" strategy
;; Each prisoner picks a random permutation of lockers,
;; then opens the first 50 in that random order, checking for their number.
;; Returns TRUE if found, FALSE if not.
;; --------------------------------------------------
strat_rand: func [pris][
    random rand_arr                                 ;; Randomize the locker opening order
    repeat n 50 [
        if Board/(rand_arr/:n) = pris [ return true ];; Check the nth randomly chosen locker
    ]                                                ;; If found -> success
    false                                            ;; Not found in 50 tries -> fail
]

;; --------------------------------------------------
;; check_board: Runs a strategy for the entire set of prisoners
;; Returns TRUE if *every prisoner* finds their number, FALSE if any fail.
;; Argument 'strat' is the symbol 'optimal or 'rand
;; --------------------------------------------------
check_board: func [strat][
    ;; Choose which strategy function to run
    strat: either strat = 'optimal [:strat_optimal] [:strat_rand]

    ;; Test each prisoner with the chosen strategy
    repeat pris prisoners [
        unless strat pris [return false]            ;; If any fail, run ends -> false
    ]
    true                                            ;; All prisoners succeeded -> true
]

saved: saved_rand: 0                                ;; Counters for the number of successful runs per strategy

;; --------------------------------------------------
;; Run the given number of simulations
;; --------------------------------------------------
loop K_runs [
    Board: random copy rand_arr                     ;; Create a random locker arrangement for this run
    if check_board 'optimal [saved: saved + 1]      ;; Attempt "optimal" strategy, count full successes
    if check_board 'rand    [saved_rand: saved_rand + 1]  ;; Attempt "random" strategy, count full successes
]

;; At this point:
;; - 'saved'       = number of runs where *all prisoners* survived using optimal strategy
;; - 'saved_rand'  = number of runs where *all prisoners* survived using random strategy
print ["runs" k_runs newline  "Percent saved opt.strategy:" saved * 100.0 / k_runs ]
print ["Percent saved random strategy:" saved_rand * 100.0 / k_runs ]