Help me Shut the Box

12

The inspiration for this challenge should be ridiculously obvious at the time of posting.

The Task

You must create a Shut the Box style program (not function, program). The basics of shut the box are:

Players attempt to shut the box by turning a set of levers labelled 1-9. They must do so by flipping levers. The sequence of events of each turn are as follows:

  1. The current position of the levers are shown.
    • On a new game, the position of the levers should be displayed as 123456789.
    • On a game with shut levers, all shut levers are displayed as -. For example, on a game that has 1, 5, and 9 shut, the output would be -234-678-.
  2. The di(c)e (is|are) rolled.
    • If levers 7, 8, and 9 are all off, only one six-faced die is thrown. Otherwise, 2 six-faced dice are thrown.
  3. The player is prompted to choose how many levers they wish to flip.
    • If the player chooses a number >9 or <0, the game ends.
    • If the player chooses an already shut lever, the game ends.
  4. The player selects that many levers.
    • If the sum of the levers does not equal the value of the di(c)e thrown, the game ends.
  5. If all the levers are shut, congratulations, you win. Otherwise, go back to step 1.

Rules for the Program

  • On each turn, you should output the current positions of levers.
  • You must output the value of the roll with the phrase You rolled: (note the space).
  • You must prompt (and wait) for the number of levers to switch with the phrase How many levers to flip: (note the space).
  • You must prompt (and wait) for as many levers as the player specified with the phrase Which lever to flip: (note the space).
  • You must flip the specified levers.
  • If at any point the game ends, you must output Game Over.
  • If the player finishes a turn with no levers open, you must output You win!

Example Games

123456789
You rolled: 5
How many levers to flip: 5
Which lever to flip: 1
Which lever to flip: 2
Which lever to flip: 3
Which lever to flip: 4
Which lever to flip: 5
Game Over
123456789
You rolled: 5
How many levers to flip: 3
Which lever to flip: 2
Which lever to flip: 2
Which lever to flip: 1
Game Over
123456789
You rolled: 12
How many levers to flip: 2
Which lever to flip: 3
Which lever to flip: 9
12-45678-
You rolled: 6
How many levers to flip: 2
Which lever to flip: 2
Which lever to flip: 4
1---5678-
You rolled: 11
How many levers to flip: 2
Which lever to flip: 5
Which lever to flip: 6
1-----78-
You rolled: 8
How many levers to flip: 1
Which lever to flip: 8
1-----7--
You rolled: 8
How many levers to flip: 2
Which lever to flip: 1
Which lever to flip: 7
---------
You win!

Addison Crump

Posted 2016-01-31T21:22:03.493

Reputation: 10 763

Oh. I had it on my list to create a challenge involving Shut the Box. Nice! – mbomb007 – 2016-03-07T22:58:48.390

Answers

3

Python 3, 348

Saved 5 bytes thanks to Mathias Ettinger.
Saved 7 bytes thanks to DSM.

Ooof, this is a long one. I also hate that there's not a good way to do test cases.

from random import*
*l,='123456789'
q=['-']*9
r=randint
p=print
f=' to flip: '
while l!=q:
 p(*l,sep='');t=r(1,6)+r(1,6)*(l[6:]!=q[6:]);p('You rolled: %s'%t);d={int(input('Which lever'+f))for _ in' '*int(input('How many levers'+f))}
 if len(set(d))-len(d)+1-all(str(x)in l for x in d)+t-sum(d):exit('Game Over')
 for x in d:l[x-1]='-'
p('You win!')

Morgan Thrapp

Posted 2016-01-31T21:22:03.493

Reputation: 3 574

2

C, 405 403 398 392 390 387 bytes

#define R 1+rand()/(2147483647/6+1)
#define G return puts("Game Over");
#define I(s,w)printf(s);scanf("%d",&w);
w,s;main(r,l){char b[]="123456789";for(srand(time(0));w^9;w=strspn(b,"-")){puts(b);printf("You rolled: %d\n",r=R+(strspn(b+6,"-")<3?R:0));I("How many levers to flip: ",l)for(;l--;s+=w,b[w-1]=45){I("Which lever to flip: ",w);if(w>9|w<0|b[w-1]<48)G}if(s^=r)G}puts("You win!");}

Ungolfed

/* Macro to get random integer in range [1,6] */
#define R 1+rand()/(2147483647/6+1)

i; /* Index variable */
main(r,l,w,s)
{
    /* Running game board */
    char b[]="123456789";

    /* Run while still levers not pulled */
    for(srand(time(0));i^9;i=strspn(b,"-"))
    {
        puts(b); /* Print game board */
        r=R+(b[6]^45||b[7]^45||b[8]^45?R:0); /* Get dice roll */
        printf("You rolled: %d\n",r); /* Print dice roll */
        printf("How many levers to flip: ");
        scanf("%d",&l); /* Get # of levers */
        for(i=s=0;i++<l;s+=w)
        {
            printf("Which lever to flip: ");
            scanf("%d",&w); /* Get lever # */
            if(w>9||w<0||b[w-1]==45) /* If invalid lever or lever already pulled, game over man */
                return puts("Game Over");
            b[w-1]=45; /* flip the lever */
        }
        if(s^r) /* If sum does not equal roll, game over */
            return puts("Game Over");
    }
    puts("You win!");
}

Edit: D'oh! Left an unused variable in my golfed answer. I had removed it but pasted the wrong version.

Cole Cameron

Posted 2016-01-31T21:22:03.493

Reputation: 1 013

2

PowerShell v2+, 330 322 bytes

$a=1..9;$r={1+(Random 6)};for($g="Game Over"){($o=-join$a-replace0,'-');if($o-eq'-'*9){"You win!";exit}"You rolled: "+($b=(&$r)+(&$r)*(($a|sort)[8]-ge7));$l=Read-Host "How many levers to flip";if(9-lt$l-or1-gt$l){$g;exit}while($l){$b-=($i=Read-Host "Which lever to flip");$a[$i-1]-=$I;$l-=1}if($b-or($a|sort)[0]){$g;exit}}

Newlines for clarity:

$a=1..9
$r={1+(Random 6)}
for($g="Game Over"){
  ($o=-join$a-replace0,'-')
  if($o-eq'-'*9){"You win!";exit}
  "You rolled: "+($b=(&$r)+(&$r)*(($a|sort)[8]-ge7))
  $l=Read-Host "How many levers to flip"
  if(9-lt$l-or1-gt$l){$g;exit}
  while($l){
    $b-=($i=Read-Host "Which lever to flip")
    $a[$i-1]-=$i
    $l-=1
  }
  if($b-or($a|sort)[0]){$g;exit}
}

(Rrequires version 2 or later since Get-Random didn't exist in PowerShell v1...)

Explanation:

Start with setting the $array of levers by taking the range 1..9, and also set $r equal to a script block that we execute later (described below with $b). The Game Over wording gets set to $g at the start of an infinite loop for(){...}. Each iteration, we set our output $o and immediately output it (thanks to the (...) encapsulation) by -joining together the array and replace each 0 with a -. (The 0 is explained below). If the output is equal to 9 hyphens, output You win! and exit.

Next, we set our dice rolls to $b by calling the stored $r (via &) with some additional parameters. The Get-Random command with a -Maximum of 6 (the -Maximum is implied) will produce an integer from 0 to 5, inclusive. We add 1 on to that to get a six-sided die, and add that to another random die roll multiplied by (($a|sort)[8]-ge7) which checks whether the highest value left on the levers is one of 7,8,9 by first sorting $a and then taking the last element and checking whether it's greater-than-or-equal-to 7. We use implicit typecasting to turn the Boolean value into either 0 (False) or 1 (True) for the multiplication, so the additional "die" is either die*0 or die*1. We then output the result of the die roll.

Next is the Read-Host into $l for how many levers. Note that PowerShell automatically adds the colon-space : after a Read-Host prompt, so we get that for free at least. We then check that the number of levers the user wishes to flip is between 1 to 9, else exit.

Now we enter a while loop. Each iteration of this loop, we Read-Host which lever, store that into $i, and subtract that value from $b. We then also subtract the corresponding lever in the array, and subtract how many additional times to query the user.

The last line (excepting the closing brace) tests two Boolean constructions. The first, just $b, will only be $True if the user didn't properly subtract all numbers from the die roll (in PowerShell, any non-zero number is Truthy). The other condition sorts $a and takes the minimal value. If we subtracted the same lever twice, then the minimal value will be negative (or Truthy), otherwise the minimal value will be 0 (or Falsey).

Example Run:

PS C:\Tools\Scripts\golfing> .\shut-the-box.ps1
123456789
You rolled: 6
How many levers to flip: 1
Which lever to flip: 6
12345-789
You rolled: 6
How many levers to flip: 2
Which lever to flip: 2
Which lever to flip: 4
1-3-5-789
You rolled: 6
How many levers to flip: 2
Which lever to flip: 1
Which lever to flip: 5
--3---789
You rolled: 10
How many levers to flip: 2
Which lever to flip: 3
Which lever to flip: 7
-------89
You rolled: 9
How many levers to flip: 1
Which lever to flip: 9
-------8-
You rolled: 8
How many levers to flip: 1
Which lever to flip: 8
---------
You win!

AdmBorkBork

Posted 2016-01-31T21:22:03.493

Reputation: 41 581

Excellent explanation! +1 – Addison Crump – 2016-02-02T18:18:59.953