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 )