Programming puzzle #2


Posted in: puzzles | Save to del.icio.us | Twit This! 8 Nov 2009

The last programming problem, though not difficult, was interesting for the variety of ways readers tried to solve it. Here goes the second one:

Using a standard deck of playing cards we can display the first n digits of the constant PI. For example using a single deck of cards, you can display the following digits of PI:

3.14159265358979323846264

In the above example we cannot display the next digit, which happens to be a ‘3′, because we have already used 4 cards of the number ‘3′ from a single deck.

Write a function that takes d - the number of card decks; and returns the number of digits of PI you can display using the cards. So for d(deck) = 1, the function should return 24 (the number of starting digits of PI).

Take ‘Ace’ as the digit ‘1′ and ‘10′ as the digit ‘0′. A list of the million digits of PI can be found here.

Preferably the solution should be in PHP, but other languages are welcome.

UPDATE: 18th Dec. 2009
The following are 2 solutions provided by readers.

By Daniel Egeberg:
Need to first copy the primes from here to a text file.

<?php
 
function getDeck($n)
{
    if (!is_int($n) || $n < 1) {
        throw new DomainException('Number of decks must be positive integer.');
    }
 
    return array_combine(
        range(0, 10),
        array_fill(0, 11, 4 * $n)
    );
}
 
function numDigits($decks, $piFile, $bufferSize = 20)
{
    $deck = getDeck($decks);
    if (!file_exists($piFile)) {
        throw new InvalidArgumentException('Pi file does not exist.');
    }
    if (!is_int($bufferSize) || $bufferSize < 1) {
        throw new DomainException('Buffer size must be positive integer.');
    }
 
    $fp = fopen('pi.txt', 'r');
    $count = 0;
    while (!feof($fp)) {
        $buffer = fread($fp, $bufferSize);
        for ($i = 0, $s = strlen($buffer); $i < $s; ++$i) {
            $d = $buffer[$i];
            if (!preg_match('#[0-9]#s', $d)) {
                continue;
            }
 
            if ($deck[$d] === 0) {
                break 2;
            }
 
            ++$count;
            --$deck[$d];
        }
    }
    fclose($fp);
 
    $foundZero = false;
    foreach ($deck as $n) {
        if ($n === 0) {
            $foundZero = true;
        }
    }
 
    if (!$foundZero) {
        throw new RuntimeException('Ran out of digits.');
    }
 
    return $count;
}
 
try {
    if ($argc !== 3) {
        throw new InvalidArgumentException(sprintf('Usage: %s numDecks piFile', $argv[0]));
    }
 
    $decks = (int) $argv[1];
    $piFile = $argv[2];
 
    printf('Using %d deck(s) you can get %d digits of pi' . PHP_EOL, $decks, numDigits($decks, $piFile));
}
catch (Exception $e) {
    fprintf(STDERR, $e->getMessage() . PHP_EOL);
    exit(1);
}
?>

by Marcin

/**
 * @author marcin@php4u.co.uk
 */
 
puzzle2solver::solve(1);
 
class puzzle2solver {
 
    /**
     * Gets first $precision numbers of pi
     * @param int $precision
     */	
    public static function getPiNumbers($precision) {
        echo "Getting PI...";
        $pi_numbers = substr(preg_replace('/[^0-9]/','', strip_tags(file_get_contents('http://www.exploratorium.edu/pi/Pi10-6.html', FILE_TEXT))),0,$precision);
        echo "Ok\n";
        return $pi_numbers;
    }
 
    /**
     * Solver
     *
     * @param int $decks
     */
    public static function solve($decks) {
        if (is_int($decks) && $decks > 0) {
            $length = $decks * 40; // this is maximum what we can get 
            $pi_numbers = self::getPiNumbers($length); // take our pi numbers
 
            $starttime = microtime(true);
            $deck = new deck($decks); // initiate deck object
            $n=0;
            while ($n<$length) {
                if (!$deck->takeCard($pi_numbers[$n])) { // take our number from the stock
                    break; // if failed we don't have more cards
                }
                $result .= $pi_numbers[$n];
                $n++; // take next number
            }
            $time = microtime(true)-$starttime;
            echo "Solution: {$result} [{$n} numbers]\n";
            echo "Time: ".sprintf("%2.10f",$time)." secs\n";
        } else {
            echo "usage: php ".__file__." number_of_decks\n";	
        }
    }
}
 
/**
 * Class which represents our decks
 */
class deck {
 
    /**
     * How many decks we have
     *
     * @param int $decks_number
     */
    public function __construct($decks_number) {
        $this->decks_number = $decks_number * 4; // 4 cards from each deck
        $this->decks = array_fill(0, 10, 0);
    }
 
    /**
     * Takes card (we increase our card counter), returns false if we ran out of cards
     *
     * @param int $number [0-9]
     * @return boolean
     */
    public function takeCard($number) {
        if ($this->decks[$number]==$this->decks_number) {
            return false; 
        } else {
            $this->decks[$number]++;
            return true;
        }
    }
}



Share this post

Share on Facebook
Share on Twitter
Share on StumbleUpon
Share on Delicious
Share on Digg
Share on Technorati
Share on Reddit
Feeds RSS Subscribe to site Feed

Other related posts



5 Responses

1

Daniel Egeberg

November 8th, 2009 at 12:38 pm

When the digits of pi are pre-calculated, doing that is fairly trivial by just keep reading from a file containing them.

<?php
function getDeck($n)
{
if (!is_int($n) || $n < 1) {
throw new DomainException('Number of decks must be positive integer.');
}

return array_combine(
range(0, 10),
array_fill(0, 11, 4 * $n)
);
}

function numDigits($decks, $piFile, $bufferSize = 20)
{
$deck = getDeck($decks);
if (!file_exists($piFile)) {
throw new InvalidArgumentException('Pi file does not exist.');
}
if (!is_int($bufferSize) || $bufferSize < 1) {
throw new DomainException('Buffer size must be positive integer.');
}

$fp = fopen('pi.txt', 'r');
$count = 0;
while (!feof($fp)) {
$buffer = fread($fp, $bufferSize);
for ($i = 0, $s = strlen($buffer); $i getMessage() . PHP_EOL);
exit(1);
}

That works reasonably fast. If you were ensured a file that was always correctly filled you could skip the regex check. Increasing the buffer size would also make it faster and reading the entire file would be even faster because of minimized I/O. It would consume more memory, however.

2

Daniel Egeberg

November 8th, 2009 at 12:39 pm

Hmm… the commenting system seems to have screwed up my code. I’ve pasted it here:
http://pastie.org/689167

3

Marcin

November 9th, 2009 at 3:24 pm

My entry:
http://pastie.org/691008

Getting PI number from url is pretty slow, rest is quick.
Can’t wait for other “smart” more math solutions

4

Gabriel Duman

December 16th, 2009 at 7:37 am

here is a shorter solution. i’ve copied the regex of marcin #3. sorry for that.


<?
/**
* @param integer $d number of decks
* @param string $pi Pi
* @return integer
*/
function getLengthOfPi($d, $pi) {
$counter = array();
$i=0;
do {
$counter[$pi[$i]]++;
$i++;
} while ($counter[$pi[$i]]

5

Gabriel Duman

December 16th, 2009 at 7:38 am

code-tag did not work. here again:
http://pastie.org/745653

Comment Form

Use the html <code> tag to insert small source code snippets

For longer code examples use http://pastie.org/.

Get latest updates by E-mail

About this blog

This site is a digital habitat of Sameer, a freelance web developer working from Pune.More

Recent Comments

  • sameer: Check to see if the 'IDE > options > format' is set to HTML. [...]
  • sameer: Google strips any newline characters form the text. Although it does accept it with the online trans [...]
  • Arjan: Fiddler is a debugging tool for IE (not Microsoft's Fiddler) [...]
  • Susan Martin: while creating a test for site, command icons on IDE greyed out and do not respond when selected. I [...]
  • Saar: Thanks for this example. helped me a lot. I have 1 problem, I am translating chunks of code, but I [...]
  • sameer: You can add extra GET variables in the options array as below: $pager_options = array( 'mode [...]
  • Martin: How can you carry over your own variables into the URL? I am using a form to POST a couple of var [...]
  • nancy: thanks very much ! first tools [...]

  • Users Online

    • 8 Users Online
    • 7 Guests, 1 Bot