24
\$\begingroup\$

Your task is to sum up and output one player's score in a game of 10-pin bowling after up to 21 rolls.

The rolls are represented as a sequence of integers in your preferred method of input. Each integer corresponds to the number of pins that were knocked down in that roll.

Scoring

After each round the number of pins knocked down in that round is counted into the final score. If a player knocks down all ten pins in the first roll of a round, this is a strike, and the round is over. Otherwise, the round lasts for one more roll. If the second roll of a round knocks down all the remaining pins, this is a spare.

For each strike there is a bonus equal to the sum of pins knocked down in the two next rolls. For each spare there is a bonus equal to the number of pins knocked down in the next roll.

The 10th and final round, the player may be granted extra rolls: In case of a strike, the player gets two more rolls to make up his strike bonus. In case of a spare, the player gets one more roll.

Examples

Input: 4 3 8 2 7 1 10 7 3 0 10 2 2 10 10 5 4
Output: 131

Input: 10 10 9 1 7 3 2 7 10 1 9 10 7 1 10 10 10
Output: 183

Rules

  • You may assumed that the input is valid.
  • As per Mego's comment I have loosened the requirements for the input/output methods to meet our current standard.
  • Answers in languages that are newer than the challenge are allowed
  • Shortest code wins!
\$\endgroup\$
8
  • \$\begingroup\$ Do I remember correctly that bonuses don´t stack? \$\endgroup\$
    – Titus
    Apr 22, 2017 at 21:58
  • \$\begingroup\$ @Titus I'm not exactly sure what you mean, but no, bonuses don't "stack", i.e, for a strike you add the number of pins that are knocked down in the two next rolls, regardless of whether they are strikes or not. So maximum score for one strike is 30 points, and maximum for a whole game is 300. \$\endgroup\$
    – daniero
    Apr 23, 2017 at 0:39
  • \$\begingroup\$ Do distinct command line arguments qualify as space separated integers? \$\endgroup\$
    – Titus
    Apr 23, 2017 at 11:07
  • 1
    \$\begingroup\$ @Titus sure. This is an old post - Today's consensus on acceptable input methods was not established at this point. Actually, I don't see now why today's standard shouldn't apply to this (including function parameters etc), although I'm not a fan of changing the rules of the challenge retroactively. \$\endgroup\$
    – daniero
    Apr 23, 2017 at 14:16
  • 1
    \$\begingroup\$ @daniero The usual advice is that it's acceptable to loosen the rules to fit modern standards, so long as it doesn't drastically change the challenge. \$\endgroup\$
    – user45941
    Aug 24, 2017 at 8:41

10 Answers 10

6
\$\begingroup\$

GolfScript, 50 41 characters

~0]-1%~0{\.9>{+1$3$}{@+.9>3$*}if++}10*p];

Another attempt in GolfScript (run it online).

An explanation of the code follows. The solution utilises the stack nature of the problem (consume rolls one after another) but therefore the input has to be reversed.

~0          # Take the input and evaluate to single numbers on the stack. Add zero.
]-1%~       # Reverse the stack (make array, reverse array, dump array)

0           # Start with a sum of zero
{           # Perform this block 10 times (once for each round)
  \         #   Take the next roll
  .9>{      #   If it is a strike
    +       #     Add the value of the roll to the sum
    1$3$    #     and duplicate top two members of the stack (i.e. next two rolls).
  }{        #   ... else ...
    @+      #     Take the next roll and add with first roll in round.
    .9>     #     Does this sum show a spare?
    3$*     #     Get next roll (potential bonus) and multiply with yes/no.
            #     Since we pushed an additional 0 in the beginning 
            #     there is a spare roll even for the last round.
  }if       #   endif
  ++        #   Add top three stack entries together
            #   (i.e. sum+2 bonus rolls for strike, sum+rolls+bonus else)
}10*        # Loop ten times

p];         # Sum is top of stack. Print sum and discard any leftover rolls.

Previous version:

~].1>.1>]zip{((.10<{@(0=@+@1>1$9><}*@}10*;]{+}.@**
\$\endgroup\$
5
\$\begingroup\$

Python, 116 110 105 103 100 99 characters

z=map(int,raw_input().split())
s=0
exec('s+=sum(z[:2+(z[0]+z[1]>9)]);z=z[2-(z[0]>9):];'*10)

Spending 30 characters on input is irksome. Suggestions welcome.

Much thanks to Howard for improvements.

\$\endgroup\$
5
  • \$\begingroup\$ You may replace 1+(z[i]!=10) with 2-(z[i]>9) to save one char. \$\endgroup\$
    – Howard
    Oct 10, 2012 at 20:44
  • \$\begingroup\$ @Howard: Excellent suggestion. I have incorporated it into my answer. It saved two characters. \$\endgroup\$ Oct 10, 2012 at 20:51
  • \$\begingroup\$ And two more if you remove i completely (set to 0) and instead of i+=... use z=z[2-(z[0]>9)::]; \$\endgroup\$
    – Howard
    Oct 10, 2012 at 20:53
  • \$\begingroup\$ @Howard: Thanks again. Saved three characters. \$\endgroup\$ Oct 10, 2012 at 21:02
  • \$\begingroup\$ Standards for I/O are generally more flexible now so z=input() should be fine (effectively taking a string representation of a list of ints and evaling it). However full programs should output somewhere (I think this was also the case back then too). As such I believe this may be changed to this 78 byte program \$\endgroup\$ Sep 27, 2017 at 17:54
4
\$\begingroup\$

R, 101 bytes

I am not sure why this challenge was bumped, but I like it, so I'll late answer anyways.

f=function(x,s=0,c=10)`if`(c&length(x),f(x[-(0:(x[1]!=10)+1)],sum(x[1:(2+(sum(x[1:2])>9))])+s,c-1),s)

Try it online!

Ungolfed:

f <- function(throws, score = 0, count = 10){
  if(count != 0 & length(throws) != 0){
    IsStrike <- throws[1] == 10
    IsStrikeOrSpare <- sum(throws[1:2]) >= 10
    f(throws[-c(1, 2 * !IsStrike)],
      score + sum(throws[c(1:(2 + IsStrikeOrSpare))]),
      count - 1)
  } else {
    return(score)
  }
}

Recursive function. Takes x as input, which holds the scores. Initialises the scores and counts the amount of rounds thrown.

The if statement checks if 10 rounds are thrown, or if x is empty. If that is the case, the score is returned. Else the function will call itself as follows:

It removes the throws from x, by checking if it is a strike or not. If so, the first entry is removed, else the first two. (S=x[1]!=10) checks for strikes. We remove (-) index 0:S, where S is 1 if it is a strike, and 0 if not. And then we add one: -(0:(x[1]!=10)+1). We pass the shortened x to the next call.

As for the score, this is found by taking x[1:2] if it is a regular turn, and x[1:3] if it is a strike or a spare. We check if sum(x[1:2]) is bigger or equal than 10. If it is a strike, obviously this is the case. If it is a spare, then this works as well. So if this is TRUE, we add x[3] to the sum. This is then added to s.

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

CoffeeScript (234 215 170)

z=(a)->b=(Number i for i in a.split(' ').reverse());t=0;(r=b.pop();l=b.length;if(9<r)then(t+=r;t+=b[l-1]+b[l-2];)else(f=r+b.pop();t+=f;(t+=b[l-2])if 9<f))for i in[0..9];t

EDIT: A hefty re-write, shamelessly plagiarising Howard's great stack-based approach. I'm confident more can be stripped out for accessing the last element of an array without destroying it...

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

Ruby, 252 bytes

Accepts input into an array add all elements first, then searches for spare and strike bonus

s,p,t,r=0,0,1,1
o=ARGV
o.each_with_index do |m,n|
y=m.to_i
s+=y
if r<10
p+=y
if p==10&&t==1
r,p=(r+1),0
s+=o[n+1].to_i+o[n+2].to_i
elsif p<10&&t==1
t=2
elsif p<10&&t==2
t,p,r=1,0,(r+1)
elsif p==10&&t==2
t,p,r=1,0,(r+1)
s+=o[n+1].to_i
end end end
puts s
\$\endgroup\$
1
\$\begingroup\$

PHP, 82 bytes

for($a=$argv;$r++<10;$i+=$p<10)$s+=(9<$q=$a[++$i+1]+$p=$a[$i])*$a[$i+2]+$q;echo$s;

takes input from command line arguments; run with -nr or test it online.

breakdown

for($a=$argv;       # import arguments
    $r++<10;        # loop through rounds
    $i+=$p<10)          # 6. if no strike, increment throw count again
    $s+=(9<
        $q=$a[++$i+1]+  # 1. increment throw count  2. $q=second throw plus
        $p=$a[$i]       # 3. $p=first throw
        )*$a[$i+2]      # 4. if $q>9 (strike or spare), add third throw to sum
    +$q;                # 5. add first and second throw to sum
echo$s;             # print sum
\$\endgroup\$
1
\$\begingroup\$

Perl 5, 65 + 2 = 67 bytes

Requires -ap flags

$\+=(($"=shift@F)<10?$"+=shift@F:10+$F[1])+$F[0]*(9<$")for 0..9}{

Try it online!

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

Jelly,  36  35 bytes

+\µi©⁵+Ị$ḂḤị;®×Ị¤¡-
;0Ç3ƤFṣ-m€2Fḣ⁵S

A monadic link accepting a list of integers and returning an integer.

Try it online!

How?

Calculates the score of each overlapping run of three bowls as if it were one that started at the beginning of a frame and optionally appends a strike identifier (-1), flattens this resulting list, splits it at the strike identifiers, then discards every second result from each chunk (removing the scores of those runs that did not really start with the start of a frame).

To cater for the final frame a zero is first appended to the input (to allow the 3-wise slicing to allow a frame to start on what was the penultimate bowl) and the resulting scores are truncated to the first ten (to remove the now possible bogus 11th frame) prior to summing them up.

+\µi©⁵+Ị$ḂḤị;®×Ị¤¡- - Link 1, threeBowlEvaluate: list, bowlScores
                    -               e.g. [0,4,6]   [9,1,10]   [0,4,4]  [10,7,9]
 \                  - cumulative reduce with:
+                   -   addition         [0,4,10]  [9,10,20]  [0,4,8]  [10,17,26]
  µ                 - monadic chain separation, call that "left"
     ⁵              - literal ten        10        10         10       10
   i                - first index in left 3         2 (spare)  0        1 (strike)
    ©               - (copy to register for later reuse)
        $           - last two links as a monad (f(x)):
       Ị            -   abs(x) <= 1       0         0          1        1
      +             -   add x             3         2          1        2
         Ḃ          - modulo by 2         1         0          1        0
          Ḥ         - double              2         0          2        0
           ị        - index into left (both 1-indexed and modular)
                    -            ...      4        20          4       26
                  - - literal -1         -1        -1         -1       -1
                 ¡  - repeat:
            ;       - ...action: concatenate
                ¤   - ...number of times: nilad followed by link(s) as a nilad:
             ®      -   z from register   3         2          0        1
               Ị    -   abs(z) <= 1       0         0          1        1
              ×     -   multiply          0         0          0        1 (strike)
                    - ...yielding:        4         20         4        [26,-1]

;0Ç3ƤFṣ-m€2Fḣ⁵S - Main link: list bowlValues
                -                    e.g. [4,3,8,2,7,1,10,7,3,0,10,2,2,10,10,5,4]
 0              - literal zero            0
;               - concatenate             [4,3,8,2,7,1,10,7,3,0,10,2,2,10,10,5,4,0]
   3Ƥ           - for infixes of length 3:
  Ç             -   last link (1) as a monad
                -                         [7,11,17,9,8,11,[20,-1],10,3,12,[14,-1],4,12,[25,-1],[19,-1],9]
     F          - flatten                 [7,11,17,9,8,11,20,-1,10,3,12,14,-1,4,12,25,-1,19,-1,9]
       -        - literal -1              -1
      ṣ         - split at                [[7,11,17,9,8,11,20],[10,3,12,14],[4,12,25],[19],[9]]
          2     - literal two             2
        m€      - modulo slice for €ach   [[7,17,8,20],[10,12],[4,25],[19],[9]]
           F    - flatten                 [7,17,8,20,10,12,4,25,19,9]
             ⁵  - literal ten             10
            ḣ   - head to index           [7,17,8,20,10,12,4,25,19,9] (no effect this time)
              S - sum                     131
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6),  79 78 72 69  68 bytes

f=([x,y,...r],n=9)=>x+y+~~r[!n|x+y>9?0:f]+(n&&f(x>9?[y,...r]:r,n-1))

Try it online!

Commented

f = (               // f is a recursive function taking:
  [x,               //   x = result of the current roll
      y,            //   y = result of the next roll
         ...r],     //   r[] = remaining results
  n = 9             //   n = remaining number of rounds
) =>                //
  x + y +           // add x + y to the score
  ~~r[              //
    !n |            // if this is the last round
    x + y > 9 ?     // or this is either a spare or a strike:
      0             //   add the result of the next roll to the score
    :               // else:
      f             //   use a dummy index so that nothing is added
  ] + (             //
    n &&            // if n is not equal to 0:
      f(            //   add the result of a recursive call:
        x > 9 ?     //     if this is a strike:
          [y, ...r] //       re-insert y into r[]
        :           //     else:
          r,        //       pass r[] unchanged
        n - 1       //     decrement n
      )             //   end of recursive call
  )                 //
\$\endgroup\$
2
  • \$\begingroup\$ Is the double-bitwise-NOT needed or is it not a bitwise NOT? \$\endgroup\$
    – S.S. Anne
    Feb 9, 2020 at 20:21
  • 1
    \$\begingroup\$ @S.S.Anne It's just there to turn undefined into \$0\$ if there's nothing at the computed index. \$\endgroup\$
    – Arnauld
    Feb 9, 2020 at 20:45
0
\$\begingroup\$

Perl, 140?

First attempt:

#!/usr/bin/perl
# usage: ./bowling.pl [list of scores]

@A=@ARGV;{last if(9<$n++);$a=shift@A;$S+=$a;($S+=$A[0]+$A[1])&redo if($a==10);$b=shift@A;$S+=$b;($S+=$A[0])&redo if(10==$a+$b);redo}print$S

Sadly, there are certain cases where it fails. I will come and redo it later.

\$\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.