twofish has asked for the wisdom of the Perl Monks concerning the following question:


Hi Monks,
I've written a small program to flip a coin, the format of the output (if the user cared to see it) is below.
I've got two other things i want to do, though 1 is somewhat of a segway into the other.
 
A) Keep track of the length of the current runs of heads and tails, resetting them to 0 when appropriate. Display them as you go along.

B) Find the length of the longest run of heads and the longest run of tails.
I guess my question is how do I go about tracking/counting the runs in the string? I think if I can do that I can get the counter figured out
Thanks much,
 
 
".........T T H H H H T H H H H H H T H T..........."
#!/usr/local/bin/perl while () { my $random = int( rand(2)); my $flip; if ($random == 0) { $flip = "H"; } if ($random == 1) { $flip = "T"; } print "$flip\ "; }

Replies are listed 'Best First'.
Re: Runs and Sequences
by Corion (Patriarch) on Sep 09, 2005 at 11:32 UTC

    Now, what code have you already written, and why should we do your homework for you?

Re: Runs and Sequences
by GrandFather (Saint) on Sep 09, 2005 at 12:33 UTC

    Here's a kinda fun solution. Can you see how it works?

    use warnings; use strict; my $flips = 'TTHHHHTHHHHHHTHT'; my $flops = substr $flips, 1; my ($maxT, $maxH, $side) = (0, 0, substr $flops, 0, 1); my $toggles = ($flips ^ $flops); $toggles =~ tr/\0\x1c/01/; my @runs = $toggles =~ /(0*1)/g; for my $run (@runs) { $maxT = length $run if $side eq 'T' && length $run > $maxT; $maxH = length $run if $side eq 'H' && length $run > $maxH; $side = $side eq 'T' ? 'H' : 'T'; } print "Longest heads run is $maxH\n"; print "Longest tails run is $maxT\n";

    Prints:

    Longest heads run is 6 Longest tails run is 2

    Perl is Huffman encoded by design.
      Neat, that works to. Though of course it doesn't actually generate the data, you'd have to save the output of the code i posted to a file.txt and then read that in. I'm not sure if you could cache a spetillion chars... ?

        Hey, we don't have to give you the whole answer in one hit here :)

        Exercise for the student:

        1. Add the data generation code for some given finite number of tosses
        2. Adapt the resulting code to deal with very long series

        You should reply to this with your solution. For bonus marks you should compare the execution time for this technique with other techniques that have, or may be, posted. Have fun.


        Perl is Huffman encoded by design.
Re: Runs and Sequences
by Roy Johnson (Monsignor) on Sep 09, 2005 at 11:58 UTC
    my ($h_run, $t_run, $longest_run) = (0,0,0); while () { if (int rand 2) { # had silly use of flip-flop -- thanks, tlm ++$h_run; $longest_run = $h_run if $h_run > $longest_run; $t_run = 0; } else { #similarly } }

    Caution: Contents may have been coded under pressure.
Re: Runs and Sequences
by uksza (Canon) on Sep 09, 2005 at 12:04 UTC
    Update: longest value.
    #!/usr/local/bin/perl use strict; use warnings; my ($h, $t, $last, $lt, $lh) = (0,0,"T",0,0); while () { my $random = int( rand(2)); if ($random == 0) { print "T $t times. Longest $lt\n" if $t; $lt<$t?$lt=$t:(); $t=0; $h++; } if ($random == 1) { print "H $h times. Longest $lh\n" if $h; $lh<$h?$lh=$h:(); $h=0; $t++; } }
      uksza ..wow, for the most part exactly what I was looking for, you're fast. Thanks to Roy Johnson also. I think this gives me a couple different ways I can generate and parse through the data. I'll work on customizing it to find and grab some other stats that might be kind of cool (like how many tries somone would have to go through on average to get a run of 16 ..should be around 1/(2^16).
      Thanks a lot!
        I'm no mathematician, but shouldn't it be 2/(2^16) = 1/2^15? I mean you can have a string of either all heads or all tails, right?

        thor

        Feel the white light, the light within
        Be your own disciple, fan the sparks of will
        For all of us waiting, your kingdom will come

Re: Runs and Sequences
by Angharad (Pilgrim) on Sep 09, 2005 at 11:35 UTC
    This looks like homework to me. You say you have written a program .. lets see the code first and perhaps we might be able to help.
      I know it looks like homework ..as I came across some similar java assignments while searching online. It isn't, it's something i just felt like doing. I read a stat that said there was some kind of record for an individual sitting there and fliiping a coin over and over, apparently the longest recorded run was 16 heads. I was curious how long (and how many tries) it took this individual. Thanks,
        I read a stat that said there was some kind of record for an individual sitting there and fliiping a coin over and over, apparently the longest recorded run was 16 heads. I was curious how long (and how many tries) it took this individual.
        Then, if you're also generating the sequence with Perl, which is not clear from your first post, and if you used rand to obtain random values, which is probable in case your did, then be warned that they won't be truly random. Which is the reason why modules like Math::TrulyRandom exist.

        It's not entirely clear to me what it is that you want to get, but as a general rule I suspect you may need a pattern matching like this:

        /((.)\2*)/; # slightly more general than your requirements, but shoul +dn't do harm.
        Or some variation of it that best fits your needs.

        HTH

        Well ... I could be wrong (I'm no perl guru) but .. why not first cut up the string into H's and T's, place them into an array. Now create a flag $H=0 as an example and then create a simple for loop, where you go though the array and create the appropriate if else statements to get the info you need.
        Make sense?
Re: Runs and Sequences
by tlm (Prior) on Sep 09, 2005 at 17:54 UTC

    If you know the expectation value of the number of flips sn required to first obtain a run of length n, then sn+1 is given by

    sn+1 = 2 sn + 1
    That's because once you hit a run of length n the next flip has a 50% probability of extending the run by one. So on average you'll need twice as many flips for a run of length n+1 than for a run of length n, plus an extra one (the n+1st flip in the run).

    Clearly, s1 = 1. Therefore, s2 = 3, s3 = 7. In fact it is easy to show by induction that

    sn = 2n − 1
    because it's true for n = 1, and, by the recurrence above
    2 (2n − 1) + 1 = 2n+1 − 1

    Therefore, on average, to get a run of length 16 you'll need 216 − 1 = 65535 flips.

    The question of what is the expectation value of the longest run in a fixed number s of flips is a harder one. I don't know of an exact expression for it, but the naive idea of solving for n gets one pretty close: log 2 (n + 1). (Usually the added 1 is omitted, since n is assumed to be large.)

    the lowliest monk