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
- The Penney Ante Part 1 (Video).
- The Penney Ante Part 2 (Video).
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!
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!