RosettaCodeData/Task/100-prisoners/Prolog/100-prisoners.pro
2025-08-11 18:05:26 -07:00

43 lines
1.5 KiB
Prolog

:- use_module(library(aggregate)).
:- use_module(library(lists)).
:- use_module(library(random)).
random_subset(Length, List, Subset) :-
random_permutation(List, Shuffled),
length(Subset, Length),
prefix(Subset, Shuffled).
random_play :-
numlist(1, 100, Prisoners),
random_permutation(Prisoners, Drawers),
forall(member(Prisoner, Prisoners), (
random_subset(50, Drawers, CheckedDrawers),
memberchk(Prisoner, CheckedDrawers)
)).
optimal_play :-
numlist(1, 100, Prisoners),
random_permutation(Prisoners, Drawers),
forall(member(Prisoner, Prisoners), optimal_play(50, Prisoner, Prisoner, Drawers)).
optimal_play(ChecksRemaining, Prisoner, NumberToCheck, Drawers) :-
ChecksRemaining > 0,
nth1(NumberToCheck, Drawers, NumberInDrawer),
( NumberInDrawer = Prisoner
-> true
; ChecksRemaining0 is ChecksRemaining - 1,
optimal_play(ChecksRemaining0, Prisoner, NumberInDrawer, Drawers)
).
:- meta_predicate play_n_times(+, 0, -).
play_n_times(PlayCount, Play, Percentage) :-
aggregate_all(count, ( between(1, PlayCount, _), call(Play) ), Victories),
Percentage is Victories / PlayCount * 100.
main(SimulationCount) :-
play_n_times(SimulationCount, random_play, RandomPlayPercent),
play_n_times(SimulationCount, optimal_play, OptimalPlayPercent),
format("Simulation count: ~d\nRandom play wins: ~f% of the simulations.\nOptimal play wins ~f% of the simulations.",
[SimulationCount, RandomPlayPercent, OptimalPlayPercent]).
:- main(100_000).