Math-GMPz
view release on metacpan or search on metacpan
demos/solitaire.p view on Meta::CPAN
#################################################################################
# This script requires Math::GMPq and Math::GMPz. #
# It calculates the chance of winning at a simplistic form of solitaire. #
# The game is as follows: #
# #
# Take (say) 4 cards, numbered 1 to 4, shuffle them, and deal them out one #
# at a time. You lose the game if the first card dealt out is the "1", or #
# the second card dealt out is the "2", or the third card dealt out is the #
# "3" or the fourth card dealt out is the "4". Otherwise you win. #
# #
# What are the chances of winning ? #
# How do those chances change if you have 10 cards numbered 1 to 10, and #
# you deal them all out one at a time, applying the same rules ? ... what if #
# you were to play that game with a thousand cards numbered 1 to 1000 ? #
# #
# The below script calculates those chances for you. You just run: #
# perl solitaire.pl X - where X is the number of cards you're playing with. #
# If you want to see the probabilities for all numbers of cards up to and #
# including X, just run: perl solitaire.pl X all #
# NOTE: X must be greater than 1. #
# #
# Turns out that the probability of winning doesn't change much as the number #
# of cards is increased beyond about 5. As the number of cards increases, the #
# probability of "winning" gets closer and closer to 1 in e, where e is the #
# euler number (2.71828...) #
# With each iteration of the for{} loop (below) we get closer and closer to #
# the actual value of e. Furthermore, with successive iterations of the for{} #
# loop, the values alternate between "less than e" and "greater than e". #
# Hence, to maximize your chances of "winning", always play with an even #
# number of cards. With an even number of cards, your chances of winning are #
# always better than 1 in e, whereas with an odd number of cards your chances #
# are always less than 1 in e. (Of course, the difference is quite miniscule.) #
# #
# The same for{} loop can be also used to calculate the euler number to a #
# specified precision. See demos/euler.p in the Math::MPFR source distro. #
# #
# When played with a full deck of 52 standard playing cards, the game is known #
# as "frustration solitaire". #
# But that's a bit different to the exercise described above, because the #
# standard deck of playing cards contains 4 cards for each of the 13 values. #
#################################################################################
use strict;
use warnings;
use Math::GMPz qw(:mpz);
use Math::GMPq qw(:mpq);
die "Usage: perl solitaire.pl cards [all]" unless @ARGV;
die "\$ARGV[0] must be greater than 1" unless $ARGV[0] > 1;
my $its = shift;
$its--;
my $display_value;
$display_value = $ARGV[0] ? shift : 0;
$display_value = 0 unless lc($display_value) eq 'all';
#################################################################
# Create some variables, and assign some initial values #
#################################################################
my $first = Math::GMPz->new(1); #
my $second = Math::GMPz->new(0); #
my $current_items = 2; #
my $factorial = Math::GMPz->new(1); #
my $chance; # becomes a MATH::GMPz object on assignment #
my $e_q = Math::GMPq->new(); #
my $count = 1; #
my $t = Math::GMPq->new(); #
#################################################################
#########################
# Do the calculations #
#########################
for(1 .. $its) {
$count++;
Rmpz_mul_ui($factorial, $factorial, $current_items); #$factorial *= $current_items;
$chance = ($current_items - 1) * ($first + $second);
Rmpq_set_num($e_q, $factorial);
Rmpq_set_den($e_q, $chance);
Rmpq_canonicalize($e_q); # gcd(num, den) == 1
if($display_value && $_ < $its) {
Rmpq_inv($t, $e_q);
( run in 1.797 second using v1.01-cache-2.11-cpan-71847e10f99 )