Penney's game: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|UNIX Shell}}: add implementation)
(+ D entry)
Line 267: Line 267:
[Y] to play again
[Y] to play again
</pre>
</pre>

=={{header|D}}==
{{trans|Python}}
<lang d>void main() {
import std.stdio, std.random, std.algorithm, std.string,
std.conv, std.range, core.thread;

immutable first = uniform(0, 2) == 0;

string you, me;
if (first) {
me = 3.iota.map!(_ => "HT"[uniform(0, $)]).text;
writefln("I choose first and will win on first seeing %s in the list of tosses", me);
while (you.length != 3 || you.any!(c => !c.among('H', 'T')) || you == me) {
"What sequence of three Heads/Tails will you win with: ".write;
you = readln.strip;
}
} else {
while (you.length != 3 || you.any!(c => !c.among('H', 'T'))) {
"After you: What sequence of three Heads/Tails will you win with: ".write;
you = readln.strip;
}
me = (you[1] == 'T' ? 'H' : 'T') ~ you[0 .. 2];
writefln("I win on first seeing %s in the list of tosses", me);
}

"Rolling:\n ".write;
string rolled;
while (true) {
rolled ~= "HT"[uniform(0, $)];
rolled.back.write;
if (rolled.endsWith(you))
return "\n You win!".writeln;
if (rolled.endsWith(me))
return "\n I win!".writeln;
Thread.sleep(1.seconds);
}
}</lang>
The output is the same as the Python entry.


=={{header|Haskell}}==
=={{header|Haskell}}==

Revision as of 19:35, 8 February 2015

Task
Penney's game
You are encouraged to solve this task according to the task description, using any language you may know.

Penneys game is a game where two players bet on being the first to see a particular sequence of Heads and Tails in consecutive tosses of a fair coin.

It is common to agree on a sequence length of three then one player will openly choose a sequence, for example Heads, Tails, Heads, or HTH for short; then the other player on seeing the first players choice will choose his sequence. The coin is tossed and the first player to see his sequence in the sequence of coin tosses wins.

For example: One player might choose the sequence HHT and the other THT. Successive coin tosses of HTTHT gives the win to the second player as the last three coin tosses are his sequence.

The Task

Create a program that tosses the coin, keeps score and plays Penney's game against a human opponent.

  • Who chooses and shows their sequence of three should be chosen randomly.
  • If going first, the computer should choose its sequence of three randomly.
  • If going second, the computer should automatically play the optimum sequence.
  • Successive coin tosses should be shown.

Show output of a game where the computer choses first and a game where the user goes first here on this page.

Refs

C

This solution stores the sequences in bit-packed integers. With minor adjustments, this can be extended to allow larger sequence lengths beyond the required 3. However, the ai's algorithm for the perfect choice would need to be altered. More robust methods of input could be chosen, as scanf is generally fairly unsafe. A safer alternative would be to use something like fgets, and parse the input string ourselves. <lang C>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <time.h>
  1. define SEQLEN 3

int getseq(char *s) {

   int r = 0;
   int i = 1 << (SEQLEN - 1);
   while (*s && i) {
       switch (*s++) {
           case 'H':
           case 'h':
               r |= i;
               break;
           case 'T':
           case 't':
               /* 0 indicates tails, this is 0, so do nothing */
               break;
           default:
               return -1;
       }
       i >>= 1;
   }
   return r;

}

void printseq(int seq) {

   int i;
   for (i = SEQLEN - 1; i >= 0; --i)
       printf("%c", seq & (1 << i) ? 'h' : 't');

}

int getuser(void) {

   int user;
   char s[SEQLEN + 1];
   printf("Enter your sequence of %d (h/t): ", SEQLEN);
   while (1) {
       /* This needs to be manually changed if SEQLEN is changed */
       if (scanf("%3s", s) != 1) exit(1);
       if ((user = getseq(s)) != -1) return user;
       printf("Please enter only h/t characters: ");
   }

}

int getai(int user) {

   int ai;
   printf("Computers sequence of %d is: ", SEQLEN);
   /* The ai's perfect choice will only be perfect for SEQLEN == 3 */
   if (user == -1)
       ai = rand() & (1 << SEQLEN) - 1;
   else
       ai = (user >> 1) | ((~user << 1) & (1 << SEQLEN - 1));
   printseq(ai);
   printf("\n");
   return ai;

}

int rungame(int user, int ai) {

   /* Generate first SEQLEN flips. We only need to store the last SEQLEN
    * tosses at any one time. */
   int last3 = rand() & (1 << SEQLEN) - 1;
   printf("Tossed sequence: ");
   printseq(last3);
   while (1) {
       if (user == last3) {
           printf("\nUser wins!\n");
           return 1;
       }
       if (ai == last3) {
           printf("\nAi wins!\n");
           return 0;
       }
       last3 = ((last3 << 1) & (1 << SEQLEN) - 2) | (rand() & 1);
       printf("%c", last3 & 1 ? 'h' : 't');
   }

}

int main(void) {

   srand(time(NULL));
   int playerwins = 0;
   int totalgames = 0;
   /* Just use ctrl-c for exit */
   while (1) {
       int user = -1;
       int ai   = -1;
       printf("\n");
       if (rand() & 1) {
           ai   = getai(user);
           user = getuser();
       }
       else {
           user = getuser();
           ai   = getai(user);
       }
       
       playerwins += rungame(user, ai);
       totalgames++;
       printf("You have won %d out of %d games\n", playerwins, totalgames);
       printf("=================================\n");
   }
   return 0;

} </lang>

Output:

Enter your sequence of 3 (h/t): tth
Computers sequence of 3 is: htt
Tossed sequence: ttth
User wins!
You have won 1 out of 1 games
=================================

Enter your sequence of 3 (h/t): tth
Computers sequence of 3 is: htt
Tossed sequence: thhhthhhthhhtt
Ai wins!
You have won 1 out of 2 games
=================================

C++

<lang cpp>

  1. include <time.h>
  2. include <iostream>
  3. include <string>

using namespace std;

class penney { public:

   penney()
   { pW = cW = 0;  }
   void gameLoop()
   {

string a; while( true ) { playerChoice = computerChoice = ""; if( rand() % 2 ) { computer(); player(); } else { player(); computer(); }

play();

cout << "[Y] to play again "; cin >> a; if( a[0] != 'Y' && a[0] != 'y' ) { cout << "Computer won " << cW << " times." << endl << "Player won " << pW << " times."; break; } cout << endl << endl;

       }
   }

private:

   void computer()
   {
       if( playerChoice.length() == 0 )

{ for( int x = 0; x < 3; x++ ) computerChoice.append( ( rand() % 2 ) ? "H" : "T", 1 ); } else { computerChoice.append( playerChoice[1] == 'T' ? "H" : "T", 1 ); computerChoice += playerChoice.substr( 0, 2 ); } cout << "Computer's sequence of three is: " << computerChoice << endl;

   }
   void player()
   {

cout << "Enter your sequence of three (H/T) "; cin >> playerChoice;

   }
   void play()
   {

sequence = ""; while( true ) { sequence.append( ( rand() % 2 ) ? "H" : "T", 1 ); if( sequence.find( playerChoice ) != sequence.npos ) { showWinner( 1 ); break; } else if( sequence.find( computerChoice ) != sequence.npos ) { showWinner( 0 ); break; } }

   }
   void showWinner( int i )
   {

string s; if( i ) { s = "Player wins!"; pW++; } else { s = "Computer wins!"; cW++; } cout << "Tossed sequence: " << sequence << endl << s << endl << endl;

   }
   string playerChoice, computerChoice, sequence;
   int pW, cW;

}; int main( int argc, char* argv[] ) {

   srand( static_cast<unsigned>( time( NULL ) ) );
   penney game; game.gameLoop();
   return 0;

} </lang>

Output:
Computer's sequence of three is: HHH
Enter your sequence of three (H/T) THH
Tossed sequence: TTHTTTTTTTTTTTHTHTTTHTTHTTHH
Player wins!

[Y] to play again y

Enter your sequence of three (H/T) HTH
Computer's sequence of three is: HHT
Tossed sequence: THHT
Computer wins!

[Y] to play again 

D

Translation of: Python

<lang d>void main() {

   import std.stdio, std.random, std.algorithm, std.string,
          std.conv, std.range, core.thread;
   immutable first = uniform(0, 2) == 0;
   string you, me;
   if (first) {
       me = 3.iota.map!(_ => "HT"[uniform(0, $)]).text;
       writefln("I choose first and will win on first seeing %s in the list of tosses", me);
       while (you.length != 3 || you.any!(c => !c.among('H', 'T')) || you == me) {
           "What sequence of three Heads/Tails will you win with: ".write;
           you = readln.strip;
       }
   } else {
       while (you.length != 3 || you.any!(c => !c.among('H', 'T'))) {
           "After you: What sequence of three Heads/Tails will you win with: ".write;
           you = readln.strip;
       }
       me = (you[1] == 'T' ? 'H' : 'T') ~ you[0 .. 2];
       writefln("I win on first seeing %s in the list of tosses", me);
   }
   "Rolling:\n  ".write;
   string rolled;
   while (true) {
       rolled ~= "HT"[uniform(0, $)];
       rolled.back.write;
       if (rolled.endsWith(you))
           return "\n  You win!".writeln;
       if (rolled.endsWith(me))
           return "\n  I win!".writeln;
       Thread.sleep(1.seconds);
   }

}</lang> The output is the same as the Python entry.

Haskell

<lang Haskell>import qualified Data.List as L import System.IO import System.Random

data CoinToss = H | T deriving (Read, Show, Eq)

parseToss :: String -> [CoinToss] parseToss [] = [] parseToss (s:sx)

 | s == 'h' || s == 'H' = H : parseToss sx
 | s == 't' || s == 'T' = T : parseToss sx
 | otherwise = parseToss sx

notToss :: CoinToss -> CoinToss notToss H = T notToss T = H

instance Random CoinToss where

 random g = let (b, gb) = random g in (if b then H else T, gb)
 randomR = undefined

prompt :: (Read a) => String -> String -> (String -> Maybe a) -> IO a prompt msg err parse = do

 putStrLn msg
 line <- getLine
 let ans = parse line
 case ans of
   Nothing   -> do
     putStrLn err
     prompt msg err parse
   Just ansB -> return ansB

showCat :: (Show a) => [a] -> String showCat = concatMap show

data Winner = Player | CPU

-- This may never terminate. runToss :: (RandomGen g) => [CoinToss] -> [CoinToss] -> g -> ([CoinToss], Winner) runToss player cpu gen =

 let stream = randoms gen
     run ss@(s:sx)
       | L.isPrefixOf player ss = player
       | L.isPrefixOf cpu ss    = cpu
       | otherwise              = s : run sx
     winner = run stream
 in if L.isSuffixOf player winner
    then (winner, Player)
    else (winner, CPU)

game :: (RandomGen g, Num a, Show a) => Bool -> a -> a -> g -> IO () game cpuTurn playerScore cpuScore gen = do

 putStrLn $ "\nThe current score is CPU: " ++ show cpuScore
   ++ ", You: " ++ show playerScore
 let (genA, genB) = split gen
     promptPlayer check =
       prompt "Pick 3 coin sides: " "Invalid input." $ \s ->
         let tosses = parseToss s in
         if check tosses then Just tosses else Nothing
     promptCpu x  = putStrLn $ "I have chosen: " ++ showCat x
 (tosses, winner) <-
   if cpuTurn
   then do
     let cpuChoice = take 3 $ randoms gen
     promptCpu cpuChoice
     playerChoice <- promptPlayer $ \n -> n /= cpuChoice && 3 == length n
     return $ runToss playerChoice cpuChoice genA
   else do
     playerChoice <- promptPlayer $ \n -> 3 == length n
     let cpuChoice = case playerChoice of [a,b,_] -> [notToss b, a, b]
     promptCpu cpuChoice
     return $ runToss playerChoice cpuChoice genA
 putStrLn $ "The sequence tossed was: " ++ showCat tosses
 case winner of
   Player -> do
     putStrLn "You win!"
     game (not cpuTurn) (playerScore + 1) cpuScore genB
   CPU -> do
     putStrLn "I win!"
     game (not cpuTurn) playerScore (cpuScore + 1) genB

main :: IO () main = do

 hSetBuffering stdin LineBuffering
 stdgen <- getStdGen
 let (cpuFirst, genA) = random stdgen
 game cpuFirst 0 0 genA</lang>
Output:
The current score is CPU: 0, You: 0
Pick 3 coin sides:
HTH
I have chosen: HHT
The sequence tossed was: TTTTTTHHT
I win!

The current score is CPU: 1, You: 0
I have chosen: TTT
Pick 3 coin sides:
HTT
The sequence tossed was: HTT
You win!

The current score is CPU: 1, You: 1
Pick 3 coin sides:

J

Solution: <lang J>require 'format/printf numeric'

randomize NB. randomize seed for new session

Vals=: 'HT' NB. valid values input=: 1!:1@<&1: NB. get input from user prompt=: input@echo NB. prompt user for input checkInput=: 'Choose 3 H/Ts' assert (Vals e.~ ]) , 3 = # getUserSeq=: (] [ checkInput)@toupper@prompt choose1st=: Vals {~ 3 ?@$ 2: NB. computer chooses 1st choose2nd=: (-.@(1&{) , 0 1&{)&.(Vals&i.) NB. computer chooses 2nd

playPenney=: verb define

 if. ?2 do.                               NB. randomize first chooser
   Comp=. choose1st 
   'Computer chose %s' printf <Comp
   You=. getUserSeq 'Choose a sequence of three coin tosses (H/T):'
   'Choose a different sequence to computer' assert You -.@-: Comp
 else.
   You=. getUserSeq 'Choose a sequence of three coin tosses (H/T):'
   Comp=. choose2nd You
   'Computer chose %s ' printf <Comp
 end.
 Tosses=. Vals {~ 100 ?@$ 2
 Result=. (Comp,:You) {.@I.@E."1 Tosses
 'Toss sequence is %s' printf < (3 + <./ Result) {. Tosses
 echo ('No result';'You win!';'Computer won!') {::~ *-/ Result

)</lang> Usage: <lang J> playPenney Computer chose TTT Choose a sequence of three coin tosses (H/T): HTT Toss sequence is TTHHTT You win!

  playPenney

Choose a sequence of three coin tosses (H/T): HTT Computer chose HHT Toss sequence is HTHTT You win!</lang>

Java

<lang java>import java.util.*;

public class PenneysGame {

   public static void main(String[] args) {
       Random rand = new Random();
       String compChoice = "", playerChoice;
       if (rand.nextBoolean()) {
           for (int i = 0; i < 3; i++)
               compChoice += "HT".charAt(rand.nextInt(2));
           System.out.printf("Computer chooses %s%n", compChoice);
           playerChoice = prompt(compChoice);
       } else {
           playerChoice = prompt(compChoice);
           compChoice = "T";
           if (playerChoice.charAt(1) == 'T')
               compChoice = "H";
           compChoice += playerChoice.substring(0, 2);
           System.out.printf("Computer chooses %s%n", compChoice);
       }
       String tossed = "";
       while (true) {
           tossed += "HT".charAt(rand.nextInt(2));
           System.out.printf("Tossed %s%n" , tossed);
           if (tossed.endsWith(playerChoice)) {
               System.out.println("You win!");
               break;
           }
           if (tossed.endsWith(compChoice)) {
               System.out.println("Computer wins!");
               break;
           }
       }
   }
   private static String prompt(String otherChoice) {
       Scanner sc = new Scanner(System.in);
       String s;
       do {
           System.out.print("Choose a sequence: ");
           s = sc.nextLine().trim().toUpperCase();
       } while (!s.matches("[HT]{3}") || s.equals(otherChoice));
       return s;
   }

}</lang>

Computer chooses HTH
Choose a sequence: hhh
Tossed H
Tossed HH
Tossed HHH
You win!

Choose a sequence: tth
Computer chooses HTT
Tossed H
Tossed HT
Tossed HTH
Tossed HTHH
Tossed HTHHT
Tossed HTHHTT
Computer wins!

Perl 6

<lang perl6>enum Coin <Heads Tails>; enum Yay <Yay Good Super Hah Ooh Yipee Sweet Cool Yes Haha>; enum Boo <Drat Darn Crumb Oops Rats Bah Criminy Argh Shards>; enum Bozo «'Dude' 'Cha' 'Bzzt' 'Hey' 'Silly dilly' 'Say what!?' 'You numbskull'»;

sub flipping {

   for 1..4 {
       print "-\b";  sleep .1;
       print "\\\b"; sleep .1;
       print "|\b";  sleep .1;
       print "/\b";  sleep .1;
   }

}

sub your-choice($p is copy) {

   loop (my @seq; @seq != 3; $p = "{Bozo.pick}! Please pick exactly 3: ") {
       @seq = prompt($p).uc.comb(/ H | T /).map: {
           when 'H' { Heads }
           when 'T' { Tails }
       }
   }
   @seq;

}

repeat until prompt("Wanna play again? ").lc ~~ /^n/ {

   my $mefirst = Coin.roll;
   print tc "$mefirst I start, {Coin(+!$mefirst).lc} you start, flipping...\n\t";
   flipping;
   say my $flip = Coin.roll;
   my @yours;
   my @mine;
   if $flip == $mefirst {
       print "{Yay.pick}! I get to choose first, and I choose: "; sleep 2; say @mine = Coin.roll(3);
       @yours = your-choice("Now you gotta choose: ");
       while @yours eqv @mine {
           say "{Bozo.pick}! We'd both win at the same time if you pick that!";
           @yours = your-choice("Pick something different from me: ");
       }
       say "So, you'll win if we see: ", @yours;
   }
   else {
       @yours = your-choice("{Boo.pick}! First you choose: ");
       say "OK, you'll win if we see: ", @yours;
       print "In that case, I'll just randomly choose: "; sleep 2; say @mine = Coin(+!@yours[1]), @yours[0,1];
   }
    
   sub check($a,$b,$c) {
       given [$a,$b,$c] {
           when @mine  { say "\n{Yay.pick}, I win, and you lose!"; Nil }
           when @yours { say "\n{Boo.pick}, you win, but I'll beat you next time!"; Nil }
           default     { Coin.roll }
       }
   }
   sleep 1;
   say < OK! Ready? Right... So... Yo!>.pick;
   sleep .5;
   say ("Pay attention now!",
       "Watch closely!",
       "Let's do it...",
       "You feeling lucky?",
       "No way you gonna win this...",
       "Can I borrow that coin again?").pick;
   sleep 1;
   print "Here we go!\n\t";
   for Coin.roll(3), &check ...^ :!defined {
       flipping;
       print "$_ ";
   }

}</lang>

Output:

Note: the actual run displays a little coin-flipping animation, but that won't show up here:

Heads I start, tails you start, flipping...
	Heads
Yipee! I get to choose first, and I choose: Heads Heads Tails
Now you gotta choose: tth
So, you'll win if we see: Tails Tails Heads
Yo!
Can I borrow that coin again?
Here we go!
	Tails Tails Tails Tails Tails Heads 
Argh, you win, but I'll beat you next time!
Wanna play again? y
Tails I start, heads you start, flipping...
	Tails
Yes! I get to choose first, and I choose: Heads Tails Tails
Now you gotta choose: H T T
Dude! We'd both win at the same time if you pick that!
Pick something different from me: heads tails tails
Silly dilly! We'd both win at the same time if you pick that!
Pick something different from me: h,h,h
So, you'll win if we see: Heads Heads Heads
OK!
You feeling lucky?
Here we go!
	Tails Tails Tails Heads Heads Heads 
Drat, you win, but I'll beat you next time!
Wanna play again? y
Heads I start, tails you start, flipping...
	Tails
Shards! First you choose: tht
OK, you'll win if we see: Tails Heads Tails
In that case, I'll just randomly choose: Tails Tails Heads
Right...
Pay attention now!
Here we go!
	Heads Tails Tails Heads 
Hah, I win, and you lose!
Wanna play again? n

Python

<lang python>from __future__ import print_function import random from time import sleep

first = random.choice([True, False])

you = if first:

   me = .join(random.sample('HT'*3, 3))
   print('I choose first and will win on first seeing {} in the list of tosses'.format(me))
   while len(you) != 3 or any(ch not in 'HT' for ch in you) or you == me:
       you = input('What sequence of three Heads/Tails will you win with: ')

else:

   while len(you) != 3 or any(ch not in 'HT' for ch in you):
       you = input('After you: What sequence of three Heads/Tails will you win with: ')
   me = ('H' if you[1] == 'T' else 'T') + you[:2]
   print('I win on first seeing {} in the list of tosses'.format(me))
   

print('Rolling:\n ', end=) rolled = while True:

   rolled += random.choice('HT')
   print(rolled[-1], end=)
   if rolled.endswith(you):
       print('\n  You win!')
       break
   if rolled.endswith(me):
       print('\n  I win!')
       break
   sleep(1)    # For dramatic effect</lang>
Output:
>>> 
After you: What sequence of three Heads/Tails will you win with: TTH
I win on first seeing HTT in the list of tosses
Rolling:
  THHTHHTT
  I win!
>>> ================================ RESTART ================================
>>> 
I choose first and will win on first seeing HHT in the list of tosses
What sequence of three Heads/Tails will you win with: THH
Rolling:
  HTHTHTTTHTTTTTTHH
  You win!
>>> 

Racket

This does what's required of it from the task... just don't input anything outside the alphabet "htHT" for the human move.

<lang racket>#lang racket

Penney's Game. Tim Brown 2014-10-15

(define (flip . _) (match (random 2) (0 "H") (1 "T")))

(define (get-human-sequence) ; no sanity checking here!

 (display "choose your winning sequence of 3 H or T > ")
 (drop-right (drop (string-split (string-upcase (read-line)) "") 1) 1))

(define flips->string (curryr string-join "."))

(define (game-on p1 p2)

 (printf "~a chooses: ~a. ~a chooses: ~a~%"
         (car p1) (flips->string (cdr p1)) (car p2) (flips->string (cdr p2)))
 (match-define (list (list name.1 p1.1 p1.2 p1.3) (list name.2 p2.1 p2.2 p2.3)) (list p1 p2))
 (let turn ((seq null))
   (match seq
     [(list-rest (== p1.3) (== p1.2) (== p1.1) _) name.1]
     [(list-rest (== p2.3) (== p2.2) (== p2.1) _) name.2]
     [else
      (let* ((flp (flip)) (seq+ (cons flp else)))
        (printf "new-flip: ~a -> ~a~%" flp (flips->string (reverse seq+))) (turn seq+))])))

(define (play-game)

 (define-values
   (player-1 player-2)
   (match (flip)
     ["H" (printf "Human chooses first: ")
          (define p1 (cons 'Hom-Sap (get-human-sequence)))
          (values p1 (cons 'Computer
                           (match p1
                             [(list _ f1 (and f2 (app (match-lambda ("H" "T") ("T" "H")) ¬f2)) _)
                              (list ¬f2 f1 f2)])))]
     ["T" (printf "Computer chooses first. ")
          (define p1 (cons 'Computer (build-list 3 flip)))
          (printf "~a chooses: ~a~%" (car p1) (flips->string (cdr p1)))
          (values p1 (cons 'Hom-Sap (get-human-sequence)))]))
 (printf "~a wins!~%" (game-on player-1 player-2)))</lang>
Output:

Homo Sapiens Plays First (and wins!)

> (play-game)
Human chooses first: choose your winning sequence of 3 H or T > hth
Hom-Sap chooses: H.T.H. Computer chooses: H.H.T
new-flip: H -> H
new-flip: T -> H.T
new-flip: H -> H.T.H
Hom-Sap wins!

The Computer Plays First (and loses!)

> (play-game)
Computer chooses first. Computer chooses: T.T.T
choose your winning sequence of 3 H or T > htt
Computer chooses: T.T.T. Hom-Sap chooses: H.T.T
new-flip: H -> H
new-flip: H -> H.H
new-flip: H -> H.H.H
new-flip: T -> H.H.H.T
new-flip: H -> H.H.H.T.H
new-flip: T -> H.H.H.T.H.T
new-flip: H -> H.H.H.T.H.T.H
new-flip: T -> H.H.H.T.H.T.H.T
new-flip: H -> H.H.H.T.H.T.H.T.H
new-flip: T -> H.H.H.T.H.T.H.T.H.T
new-flip: T -> H.H.H.T.H.T.H.T.H.T.T
Hom-Sap wins!

(Nail-biting stuff!)

REXX

The REXX program keeps a running score (number of wins out of so many games played)
as well as allowing the human to pick the number (lenfth) of the coin toss sequence.
Extra code was added to ensure a valid response from the human player as well as give an informative error message.
The human player is allowed to spell out the H or T   (as heads or tails).
A feature also added was to allow a seed for the   random   BIF to allow repeatability for a game. <lang rexx>/*REXX program plays Penney's Game, a 2-player coin toss sequence game.*/ __=copies('─',9) /*literal for eyecatching fence. */ signal on halt /*a clean way out if CLBF quits. */ parse arg # ? . /*get optional args from the C.L.*/ if #== | #=="," then #=3 /*default coin sequence length. */ if ?\== & ?\==',' then call random ,,? /*use seed for RANDOM #s ?*/ wins=0; do games=1 /*play a number of Penney's games*/

          call game                   /*play a single inning of a game.*/
          end   /*games*/             /*keep at it 'til  QUIT  or halt.*/

exit /*stick a fork in it, we're done.*/ /*──────────────────────────────────one-line subroutines────────────────*/ halt: say; say __ "Penney's Game was halted."; say; exit 13 r: arg ,$; do arg(1); $=$||random(0,1); end; return $ s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*plural*/ /*──────────────────────────────────GAME subroutine─────────────────────*/ game: @.=; tosses=@. /*the coin toss sequence so far. */ toss1=r(1) /*result: 0=computer, 1=CBLF.*/ if \toss1 then call randComp /*maybe let the computer go first*/ if toss1 then say __ "You win the first toss, so you pick your sequence first."

          else say __ "The computer won first toss, the pick was: " @.comp
               call prompter          /*get the human's guess from C.L.*/
               call randComp          /*get computer's guess if needed.*/
                                      /*CBLF:  carbon-based life form. */

say __ " your pick:" @.CBLF /*echo human's pick to terminal. */ say __ "computer's pick:" @.comp /* " comp.'s " " " */ say /* [↓] flip the coin 'til a win.*/

     do  flips=1  until pos(@.CBLF,tosses)\==0  |  pos(@.comp,tosses)\==0
     tosses=tosses || translate(r(1),'HT',10)
     end   /*flips*/                  /* [↑]   this is a flipping coin,*/
                                                /* [↓] series of tosses*/

say __ "The tossed coin series was: " tosses /*show the coin tosses.*/ say @@@="won this toss with " flips ' coin tosses.' /*handy literal.*/ if pos(@.CBLF,tosses)\==0 then do; say __ "You" @@@; wins=wins+1; end

                          else      say __  "The computer"  @@@

_=wins; if _==0 then _='no' /*use gooder English.*/ say __ "You've won" _ "game"s(wins) 'out of ' games"." say; say copies('╩╦',79%2)'╩'; say /*show eyeball fence.*/ return /*──────────────────────────────────PROMPTER subroutine─────────────────*/ prompter: oops=__ 'Oops! '; a= /*define some handy REXX literals*/ @a_z='ABCDEFG-IJKLMNOPQRS+UVWXYZ' /*the extraneous alphabetic chars*/ p=__ 'Pick a sequence of' # "coin tosses of H or T (Heads or Tails) or Quit:"

         do  until  ok;   say;  say p;  pull a  /*uppercase the answer.*/
         if abbrev('QUIT',a,1)  then exit 1     /*human wants to quit. */
         a=space(translate(a,,@a_z',./\;:_'),0) /*elide extraneous chrs*/
         b=translate(a,10,'HT');    L=length(a) /*tran───►bin; get len.*/
         ok=0                                   /*response is OK so far*/
             select                             /*verify user response.*/
             when \datatype(b,'B') then say oops "Illegal response."
             when \datatype(a,'M') then say oops "Illegal characters in response."
             when L==0             then say oops "No choice was given."
             when L<#              then say oops "Not enough coin choices."
             when L>#              then say oops "Too many coin choices."
             when a==@.comp        then say oops "You can't choose the computer's choice: " @.comp
             otherwise         ok=1
             end   /*select*/
         end       /*until ok*/

@.CBLF=a; @.CBLF!=b /*we have the human's guess now. */ return /*──────────────────────────────────RANDCOMP subroutine─────────────────*/ randComp: if @.comp\== then return /*the computer already has a pick*/ _=@.CBLF! /* [↓] use best-choice algorithm.*/ if _\== then g=left((\substr(_,min(2,#),1))left(_,1)substr(_,3),#)

 do  until g\==@.CBLF!;  g=r(#);  end /*otherwise, generate a choice.  */

@.comp=translate(g,'HT',10) return</lang> output of a six-game session   (ended by user entering a quit):

───────── The computer won first toss, the pick was:  HHH

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
tail tail tails

─────────       your pick: TTT
───────── computer's pick: HHH

───────── The computer won this toss with  12  coin tosses.

───────── The tossed coin series was:  HHTTHHTHTHHH

───────── You've won no games out of  1.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── You win the first toss, so you pick your sequence first.

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
h, h, t

─────────       your pick: HHT
───────── computer's pick: THT

───────── The computer won this toss with  5  coin tosses.

───────── The tossed coin series was:  TTTHT

───────── You've won no games out of  2.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── The computer won first toss, the pick was:  HHT

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
heads heads heads

─────────       your pick: HHH
───────── computer's pick: HHT

───────── The computer won this toss with  3  coin tosses.

───────── The tossed coin series was:  HHT

───────── You've won no games out of  3.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── The computer won first toss, the pick was:  HTH

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
t t h

─────────       your pick: TTH
───────── computer's pick: HTH

───────── You won this toss with  3  coin tosses.

───────── The tossed coin series was:  TTH

───────── You've won 1 game out of  4.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── You win the first toss, so you pick your sequence first.

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
t,h,h

─────────       your pick: THH
───────── computer's pick: HTH

───────── You won this toss with  4  coin tosses.

───────── The tossed coin series was:  TTHH

───────── You've won 2 games out of  5.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── The computer won first toss, the pick was:  TTH

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
tth
───────── Oops!   You can't choose the computer's choice:  TTH

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
tht

─────────       your pick: THT
───────── computer's pick: TTH

───────── The computer won this toss with  3  coin tosses.

───────── The tossed coin series was:  TTH

───────── You've won 2 games out of  6.

╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩╦╩

───────── You win the first toss, so you pick your sequence first.

───────── Pick a sequence of 3 coin tosses of  H or T (Heads or Tails) or Quit:
quit

Ruby

<lang ruby># Penney's Game

Toss = [:Heads, :Tails]

def yourChoice

 puts "Enter your choice (H/T)"
 choice = []
 3.times do
   until (c = $stdin.getc.upcase) == "H" or c == "T"
   end
   choice << (c=="H" ? Toss[0] : Toss[1])
 end
 puts "You chose #{choice.join(' ')}"
 choice

end

puts "%s I start, %s you start ..... #{coin = Toss.sample}" % Toss if coin == Toss[0]

 myC = Array.new(3){Toss.sample}
 puts "I chose #{myC.join(' ')}"
 yC = yourChoice

else

 yC = yourChoice
 myC = Toss - [yC[1]] + yC.first(2)
 puts "I chose #{myC.join(' ')}"

end

seq = Array.new(3){Toss.sample} print seq.join(' ') loop do

 puts "\n I win!" or break   if seq == myC
 puts "\n You win!" or break if seq == yC
 seq.push(Toss.sample).shift
 print " #{seq[-1]}"

end</lang>

Output:
Heads I start, Tails you start ..... Tails
Enter your choice (H/T)
THT
You chose Tails Heads Tails
I chose Tails Tails Heads
Heads Tails Heads Heads Tails Tails Tails Heads
 I win!

Heads I start, Tails you start ..... Heads
I chose Heads Heads Heads
Enter your choice (H/T)
THH
You chose Tails Heads Heads
Heads Heads Tails Heads Tails Heads Tails Tails Tails Tails Tails Tails Tails Heads Heads
 You win!

Tcl

Works with: Tcl version 8.6

<lang tcl>package require Tcl 8.6

oo::class create Player {

   variable who seq seen idx
   constructor {name sequence} {

set who $name set seq $sequence set seen {} set idx end-[expr {[string length $seq] - 1}]

   }
   method pick {} {

return $seq

   }
   method name {} {

return $who

   }
   method match {digit} {

append seen $digit return [expr {[string range $seen $idx end] eq $seq}]

   }

}

oo::class create HumanPlayer {

   superclass Player
   constructor {length {otherPlayersSelection ""}} {

fconfigure stdout -buffering none while true { puts -nonewline "What do you pick? (length $length): " if {[gets stdin pick] < 0} exit set pick [regsub -all {[^HT]} [string map {0 H 1 T h H t T} $pick] ""] if {[string length $pick] eq $length} break puts "That's not a legal pick!" } set name "Human" if {[incr ::humans] > 1} {append name " #$::humans"} next $name $pick

   }

}

oo::class create RobotPlayer {

   superclass Player
   constructor {length {otherPlayersSelection ""}} {

if {$otherPlayersSelection eq ""} { set pick "" for {set i 0} {$i < $length} {incr i} { append pick [lindex {H T} [expr {int(rand()*2)}]] } } else { if {$length != 3} { error "lengths other than 3 not implemented" } lassign [split $otherPlayersSelection ""] a b c set pick [string cat [string map {H T T H} $b] $a $b] } set name "Robot" if {[incr ::robots] > 1} {append name " #$::robots"} puts "$name picks $pick" next $name $pick

   }

}

proc game {length args} {

   puts "Let's play Penney's Game!"
   # instantiate the players
   set picks {}
   set players {}
   while {[llength $args]} {

set idx [expr {int(rand()*[llength $args])}] set p [[lindex $args $idx] new $length {*}$picks] set args [lreplace $args $idx $idx] lappend players $p lappend picks [$p pick]

   }
   # sanity check
   if {[llength $picks] != [llength [lsort -unique $picks]]} {

puts "Two players picked the same thing; that's illegal"

   }
   # do the game loop
   while 1 {

set coin [lindex {H T} [expr {int(rand()*2)}]] puts "Coin flip [incr counter] is $coin" foreach p $players { if {[$p match $coin]} { puts "[$p name] has won!" return } }

   }

}

game 3 HumanPlayer RobotPlayer</lang>

Sample Game:
Let's play Penney's Game!
What do you pick? (length 3): HTH
Robot picks HHT
Coin flip 1 is T
Coin flip 2 is H
Coin flip 3 is T
Coin flip 4 is T
Coin flip 5 is T
Coin flip 6 is H
Coin flip 7 is T
Coin flip 8 is T
Coin flip 9 is H
Coin flip 10 is T
Coin flip 11 is T
Coin flip 12 is T
Coin flip 13 is H
Coin flip 14 is T
Coin flip 15 is T
Coin flip 16 is H
Coin flip 17 is T
Coin flip 18 is T
Coin flip 19 is H
Coin flip 20 is T
Coin flip 21 is H
Human has won!

UNIX Shell

Works with: Bash

<lang sh>#!/bin/bash main() {

 echo "Penney's Game"
 echo -n "Flipping to see who goes first ... "
 if $(flip) == H ; then
   echo "I do."
   p2=$(choose_sequence)
   echo "I choose: $p2"
 else
   echo "You do."
 fi
 while true; do
   echo "Enter your three-flip sequence:"
   read p1
   case "$p1" in
    "$p2") echo "Sequence must be different from mine";;
    [hHTt][hHtT][hHtT]) break;;
    *) echo "Sequence must be three H's or T's";;
   esac
 done
 p1=$(tr a-z A-Z <<<"$p1")
 if [ -z "$p2" ]; then 
   p2=$(choose_sequence "$p1")
   echo "I choose: $p2"
 fi
 echo
 echo "Here we go.  $p1, you win; $p2, I win."
 flips=
 while true; do
   flip=$(flip)
   echo -n $flip
   flips+=$flip
   while (( ${#flips} > 3 )); do
     flips="${flips#?}"
   done
   case "$flips" in
     *$p1) echo $'\nYou win!'; exit 0;;
     *$p2) echo $'\nI win!'; exit 1;;
   esac
 done

}

choose_sequence() {

 local result
 if (( $# )); then
   case "$1" in
     ?Hh?) result=T;;
     *) result=H;;
   esac
   result+="${1%?}"
 else
   result=$(flip)$(flip)$(flip)
 fi
 echo "$result"

}

flip() {

 if (( RANDOM % 2 )); then 
   echo H
 else
   echo T
 fi

}

main "$@"</lang>

Output:

PC first:

Penney's Game
Flipping to see who goes first ... I do.
I choose: HHT
Enter your three-flip sequence:
THH

Here we go.  THH, you win; HHT, I win.
THH
You win!

Human first:

penney
Penney's Game
Flipping to see who goes first ... You do.
Enter your three-flip sequence:
HTH
I choose: HHT

Here we go.  HTH, you win; HHT, I win.
HHHT
I win!