10
\$\begingroup\$

Write an interactive program or function which allows the user to play The Coinflip Game! The object of the game is to repeatedly flip a coin until you get the same result \$n\$ times in a row.

Specific behavior of the program/function is as follows:

  • At the start of the game, the user inputs a positive integer \$n>1\$
  • The program should then "flip a coin" (i.e. choose between two values randomly), and show the result to the user. Possible outcomes can be any two distinct outputs (e.g. 1 or 0) and must be chosen non deterministically such that each result always has a nonzero chance of appearing.
  • Next, the following loop occurs
    1. Prompt the user to input whether they wish to continue trying or quit. This prompt must include the two input options the player has, one corresponding to continuing, and one corresponding to quitting, clearly delimited. If they choose to quit, take no further input and exit the program.
    2. If they choose to continue, perform another "coinflip", and show the user the outcome (same rules as before).
    3. If the "coinflip" has had the same outcome \$n\$ times in a row (meaning this outcome and the previous \$n-1\$ outcomes are all equal), print a congratulatory message (any message that is not one of the coinflip values or continue/quit prompts) and exit, taking no more input.
    4. If the "coinflip" has not had the same outcome \$n\$ times in a row yet, return to step 1 of the loop.

This is , so shortest implementation in bytes wins.

More rule clarifications:

  • Steps must occur in the order shown, so you can't prompt the user to continue before showing them their first coinflip result for example.
  • All six values listed below must be distinct from one another:
    • Coinflip outcome 1
    • Coinflip outcome 2
    • Continue/Quit prompt
    • Continue playing input
    • Quit game input
    • Congratulatory message
  • The coinflip only needs to be nondeterministic; You don't need the randomness to be uniform per flip.
  • There can only be two possible outcomes for each coinflip. A random float between 0 and 1 is not a coinflip.
  • Player input can be taken in any reasonable fashion.
  • You can assume the player will never give invalid input.
\$\endgroup\$
8
  • \$\begingroup\$ Prompt the user to input whether they wish to continue trying or quit, print a congratulatory message, for code golf? \$\endgroup\$
    – Noodle9
    Aug 25, 2022 at 19:12
  • \$\begingroup\$ @Noodle9 Not sure exactly what you're asking, but yes, I am making you put in extra work as part of the challenge. Do note that these messages are not required anywhere to be verbose english messages, only distinct from one another. \$\endgroup\$ Aug 25, 2022 at 19:18
  • \$\begingroup\$ Can you use generators as a form of user input? \$\endgroup\$
    – mousetail
    Aug 25, 2022 at 19:53
  • 1
    \$\begingroup\$ Can n be a command-line argument? \$\endgroup\$
    – Neil
    Aug 25, 2022 at 23:17
  • \$\begingroup\$ Does coin flip need to be independent? If my coin always flip another side different from the previous flip (for example, the coin shows HTHTHTHT or THTHTHTH. as the first flip is random, every flip may have either H or T nondeterministic before program execute), is this still a valid coin? And by using a coin like that, I don't need to handle the condition about game win (as that will never happen). \$\endgroup\$
    – tsh
    Aug 26, 2022 at 4:22

10 Answers 10

7
\$\begingroup\$

Python 3.8 (pre-release), 101 bytes

from random import*
p=m=n=int(input())
while'0'<input((m:=[n,m,print(r:=random()>.5)][r==p]-1)/m):p=r

Try it online!

  • Coin flip outcome 1: True
  • Coin flip outcome 2: False
  • Continue/Quit prompt: 1.0
  • Continue playing input: 1
  • Quit game input: 0
  • Congratulatory message: ZeroDivisionError: division by zero
\$\endgroup\$
5
  • \$\begingroup\$ Using a floating point value is very clever \$\endgroup\$ Aug 26, 2022 at 15:28
  • \$\begingroup\$ Using the possibly-allowed id trick, 84 bytes. \$\endgroup\$ Aug 26, 2022 at 17:05
  • \$\begingroup\$ @Adam this seems to be periodic, so it doesn't match the rules (which require non-determinism) \$\endgroup\$ Aug 29, 2022 at 14:11
  • \$\begingroup\$ Can't you use >0 instead of >.5? The rules don't require a 50% chance, just some non-zero chance \$\endgroup\$ Aug 29, 2022 at 14:15
  • \$\begingroup\$ +1 I love the congratulatory message 🤣. \$\endgroup\$
    – code
    Aug 31, 2022 at 4:50
3
\$\begingroup\$

Pyth, 31 bytes

KUJ"C/Q"We,aK
O2t{>QKJIqweJB.?N

Try it online!

Coinflip outcomes are "0" or "1"
Continue/Quit prompt is "C/Q"
Continue playing input is "C"
Quit playing input is "Q"
If you win, you receive a congratulatory "

\$\endgroup\$
3
\$\begingroup\$

Bash, 82 75 bytes

read n
while read;do
echo $[x=RANDOM%2,t*=x==l,l=x]
let n==++t&&exit 2
done

Try it online!

  • prompts for n
  • prompts to continue or quit: "enter" continues and "ctrl-D" quits with exit code 1
  • prints 0 or 1 randomly if you continued
  • quits with exit code 2 if you won. continues loop otherwise.
    • Works by resetting the total count t every time there is a switch in direction.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ How does this check that the last n coinflips were equal? \$\endgroup\$
    – Neil
    Aug 25, 2022 at 23:16
  • \$\begingroup\$ @Neil, Fixed now. \$\endgroup\$
    – Jonah
    Aug 26, 2022 at 1:18
3
\$\begingroup\$

Python, 129 131 127 106 bytes

i,p,a=input,print,1
p(v:=id(n:=int(i()))%3%2)
while"3">i(2.3):p(c:=id(dict())%3%2);a,v=c^v or-~a,c;1/(n>a)

Attempt This Online!

The coin flips are 0 and 1, continue with 2 and quit with 3, and the success message is an error message.


+2 bytes from @Steffan
-11 bytes from @Jonathan Allan*

\$\endgroup\$
10
  • \$\begingroup\$ It says that the two options should be clearly delimited, so you should probably do 2/3. \$\endgroup\$
    – naffetS
    Aug 25, 2022 at 21:51
  • \$\begingroup\$ or a+1 => or-~a. \$\endgroup\$
    – naffetS
    Aug 25, 2022 at 21:51
  • 1
    \$\begingroup\$ I think this might fit the bill of non-deterministic and avoids the import saving ten bytes. EDIT: save another with 1/(n>a). \$\endgroup\$ Aug 25, 2022 at 23:49
  • 1
    \$\begingroup\$ This doesn't work, id(t) is the same every time you run through the while loop. \$\endgroup\$
    – naffetS
    Aug 26, 2022 at 1:07
  • \$\begingroup\$ @Steffan I think this version works? \$\endgroup\$ Aug 26, 2022 at 1:14
3
\$\begingroup\$

05AB1E, 23 22 19 17 bytes

[₂Ω=ˆ1z¯γθg¹Q+=Ê#

-4 bytes thanks to @CommandMaster.

  • Coin flip outcomes: 2 and 6
  • Continue/Quit prompt: 1.0
  • Continue playing input: 1
  • Quit game input: 0
  • Congratulations message: 2.0

Try it online.

Explanation:

[            # Start an infinite loop:
 ₂           #  Push 26
  Ω          #  Pop and push a random digit from it
   =         #  Output it with trailing newline (without popping)
    ˆ        #  Pop and add it to the global_array
 1z          #  Push 1.0 (push 1; calculate 1/value)
 ¯           #  Push the global_array
  γ          #  Group it to equal adjacent values
   θ         #  Pop and leave just the last group
    g        #  Pop and get the length of this last group
     ¹Q      #  Check if it's equal to the first input `n` (1 if truthy; 0 if falsey)
       +     #  Add that to the 1.0
        =    #  Output it with trailing newline (without popping)
 Ê           #  If it's NOT equal to the next (implicit) input-integer:
  #          #   Stop the infinite loop

Regarding the Ê#:

  • If we haven't got \$n\$ the same values in a row yet, the value we output is still 1.0. The Ê will be falsey if the prompt input is to continue (1), and will be truthy if the prompt input is to quit (0).
  • If we have reached \$n\$ the same values in a row, the value we output is the congratulations message 2.0. The Ê will now be truthy, regardless of whether the prompt input is to continue (1) or quit (0).
\$\endgroup\$
4
  • \$\begingroup\$ I believe iq can be replaced with # for -1 bytes \$\endgroup\$ Aug 29, 2022 at 4:00
  • \$\begingroup\$ @CommandMaster Woops.. it indeed can, thanks. \$\endgroup\$ Aug 29, 2022 at 6:48
  • 1
    \$\begingroup\$ 19 bytes by using the global array: [₂Ω=ˆ1z¯γθg¹Q+=<I~# \$\endgroup\$ Aug 29, 2022 at 7:54
  • \$\begingroup\$ @CommandMaster Thanks! Also, the I isn't necessary in your 19-byter, since it can be taken implicitly, but I've found a way to save another byte by replacing <~ with Ê after swapping the continue/quit prompts. \$\endgroup\$ Aug 29, 2022 at 9:16
2
\$\begingroup\$

(Browser) JavaScript, 122 bytes

a=prompt,k=0,s=0;for(g=+a();;k++){c=!Math.random();a(c);if(c!=s){s^=1;k=0}else if(g-1==k){a`!`;break}if(a`q|g`=="q")break}

If you're wondering why if(Math.random()) works, yes: it can return 0 (but not often).

Hey, there is a nonzero chance of 0 popping up...

\$\endgroup\$
1
\$\begingroup\$

Python, 141 bytes

from random import*
n=int(input());a=[.5]
while 1:
 print(f:=random()>.5);a+=f,
 if 0==sum(a[-n:])%n:print(2);break
 if'C'<input('C/Q'):break

Attempt This Online!

Coinflip outcomes are False and True, prompt is C/Q, where C = continue and Q = quit.

-14 bytes thanks to CursorCoercer

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Save a byte by going from randint(0,1) to random()>.5 if you're okay with changing the outcomes to True and False. Additionally, save 13 bytes by changing a=[2]*n to a=[.5] and all(x==a[-1]for x in a[-n:]) to 0==sum(a[-n:])%n \$\endgroup\$ Aug 25, 2022 at 21:10
  • \$\begingroup\$ 138 bytes \$\endgroup\$ Aug 25, 2022 at 22:34
1
\$\begingroup\$

Batch, 107 bytes

@set/al=c=0
:c
@set/af=%random%%%2,c=1+c*!(l-f),l=f
@echo %f%
@if %c%==%1 goto w
@set/pi=cq
@goto %i%

Takes n as a command-line parameter. Outputs 0 or 1 for the coin. Prompt is cq, input is c to continue, q to quit. Stops with the message The system cannot find the batch label specified - w if you win. Explanation: c is the count of consecutive equal flips, l is the last flip, f is the current flip, i is the user input (note that outside set/a variables have to be enclosed in %s and even inside set/a in the case of %random%).

\$\endgroup\$
1
\$\begingroup\$

simply, 260 254 244 bytes

Yeah, the code is a big fat boy.
It is also far from the intended way to use the language.


Values

The program has the following values:

  • Coinflip outcome 1: 0
  • Coinflip outcome 2: 1
  • Continue/Quit prompt: window.confirm
  • Continue playing input: true
  • Quit game input: false
  • Congratulatory message: 'W'

The code

Thanks to Steffan for saving 3 bytes.

$F=run$argv->map->constructor("return self")$W=run$F()$T=&int(run$W->prompt)$L=&rand(0,1)$C=1for$i in0..9999{$R=run$W->confirm($L)unless$R;break$F=&rand(0,1)if run&compare($L$F){$L=$F$C=1}else{$C=&add(1$C)unless run&compare($C$T){out'W'break}}}

Unfortunately, my language doesn't have infinite loops, yet...
However, this loops 10000 times, which should be enough to get the user to stop or give you a win.

It is possible to emulate this with setTimeout, but the program flow will be extremely weird, and cost a ton of bytes.

Additionally, the result of the last coin flip is shown in the message requesting to continue or stop, to save bytes.

Ungolfed and readable

$func = call $argv["map"]["constructor"]("return self");
%window = call $func();

%times = &int(call %window->prompt("How many equals"));
%last_flip = &rand(0, 1);
%count = 1;

for $i in 0..9999 {
    $result = call %window->confirm(&str_concat("Rolled ", %last_flip, ' ', %count, " time(s). Continue?"));
    
    unless $result {
        break;
    }
    
    $flip = &rand(0, 1);
    if call &compare(%last_flip, $flip) {
        %last_flip = $flip;
        %count = 1;
    } else {
        %count = &add(1, %count);
        
        unless call &compare(%count, %times) {
            echo "You're Winner!";
            break;
        }
    }
}

Ungolfed to Plain English

Set $func to the result of calling $argv["map"]["constructor"]("return self").
Set %window to the result of calling $func().

Set %times to the result of calling &int(
    Call the function %window->prompt("How many equals")
).

Set %last_flip to the result of calling &rand(0, 1).
Set %count to 1.

Loop from 0 to 9999 as $i
Begin
    Set $result to the result of calling %window->confirm(
        Call the function &str_concat("Rolled ", %last_flip, ' ', %count, " time(s). Continue?")
    ).
    
    Unless $result then
        Break.
    
    Set $flip to the result of calling &rand(0, 1).
    
    If Call &compare(%last_flip, $flip)
    Begin
        Set %last_flip to $flip.
        Set %count to 1.
    End
    Else
    Begin
        Set %count to the result of calling &add(1, %count);
        
        Unless Call &compare(%count, %times)
        Begin
            Show the value "You're Winner!".
            Break.
        End
    End
End

All versions work exactly the same, but the output is kinda different, just to be more user friendly.

Explanation

The variable $argv is an array with arguments passed to the .execute() method of the compiler.
This can be used to run []["filter"]["constructor"]("return this")(), which returns the window object (Source in http://www.jsfuck.com/).
But since the compiler changes the this value, I had to use self, which is the same as window.self which is just the window object.
Since []["filter"]... is invalid syntax, I get around it by using $argv->filer ... ($argv["filter"]... is valid as well).

The keyword run (or call) is required to say "I am absolutely sure this variable is a function, now run it".
Due to bugs, the if and unless requires that the functions are executed with run, otherwise it assumes it is checking if the function exist.

The syntax $T=&int(run$W->prompt) is valid, because you don't need to have parenthesis when there's no arguments.

You will find a few cases where the syntax makes no sense, like $C=1for$i in0..9999 or $C=&add(1$C)unless.
As long as the tokens are distinguishable from each other, there's no problem.
$C=1for$i in0..9999 will be parsed as the following tokens: $c, =, 1, for, $i, in, 0, .., 9999.

Since, currently, there's no boolean operators, I use the unless block.
It is basically an if(!(condition)).
Since I need to check if values are false-y, for example: unless$R;break, I use this block.

The function &compare checks if the first argument is lower, higher or equal to the second argument.
If it is lower, returns -1.
If it is higher, returns 1.
Otherwise, returns 0 (a false-y value).

$W->prompt (window.prompt) shows a message requesting a value.
$W->confirm (window.confirm) shows a message and requests the user to click "OK" or "Cancel".

console.log(window.prompt("Write any value", "any value"));

console.log(window.confirm("Want to show 'true'?"));

\$\endgroup\$
2
  • \$\begingroup\$ Can you do []["map"] instead of filter? \$\endgroup\$
    – naffetS
    Aug 28, 2022 at 0:56
  • \$\begingroup\$ Yes, I can use map instead of filter. Thank you. Sadly, I can't use []["map"] and need to set the value to a variable. However, I forgot that the variable $argv is always an array, and is automatically created (it works mostly the same as the argv in C and PHP and others). I used it instead, to save 3 more bytes. Thank you. \$\endgroup\$ Aug 28, 2022 at 4:05
0
\$\begingroup\$

JavaScript (browser), 105 bytes

p=prompt,r=()=>Math.random()<.5,t=p();c=b=1;for(u=r();b;b=c==t?p(3):+p`1.0`){n=r();p(n);n==u?c++:c=1,u=n}

  • Coin flip outcome 1: true
  • Coin flip outcome 2: false
  • Continue/Quit prompt: 1.0
  • Continue playing input: 1
  • Quit game input: 0
  • Congratulatory message: 3
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.