# Mölkky

Mölkky is a Finnish throwing game. The players use a wooden pin (also called "mölkky") to try to knock over wooden pins of almost similar dimensions with the throwing pin, marked with numbers from 1 to 12. The initial position of the pins is as follows:

   (07)(09)(08)
(05)(11)(12)(06)
(03)(10)(04)
(01)(02)


This description and the rules below are based on Wikipedia.

# Simplified Mölkky rules

1. Knocking over one pin scores the number of points marked on the pin.

2. Knocking 2 or more pins scores the number of pins knocked over (e.g., knocking over 3 pins scores 3 points).

3. The aim of the game is to reach exactly 50 points. Scoring more than 50 is penalized by setting the score back to 25 points.

4. For the purpose of this challenge, we will make the assumption that the pins are always in the exact order described above. (In a real game, the pins are stood up again after each throw in the location where they landed.)

All other Mölkky rules are ignored and only a single player is considered.

# Input

A non-empty list of lists of 12 booleans. Each list of booleans describes the outcome of a throw: 1 if the pin was knocked over and 0 otherwise. The booleans are given in the exact order of the pins, from top left to bottom right: 7, 9, 8, 5, 11, 12, 6, 3, 10, 4, 1, 2.

# Output

The score after all throws described in the input, calculated by applying rules 1, 2 and 3.

# Detailed example

Let's consider the following input:

// 07 09 08 05 11 12 06 03 10 04 01 02
[ [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],  // scores 5 (rule #1)
[ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],  // scores 2 (rule #2), total: 7
[ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 ],  // scores 7, total: 14
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],  // scores 12, total: 26
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],  // scores 12, total: 38
[ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ],  // scores 11, total: 49
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],  // scores 7, total: 56 -> 25 (rule #3)
[ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ] // scores 2, total: 27


The expected output is 27.

# Challenge rules

• You may take input in any reasonable format. Instead of lists of booleans, you can use integers where the most significant bit is the pin #7 and the least significant bit is the pin #2. In this format, the above example would be passed as [ 256, 2304, 127, 64, 64, 128, 2048, 3072 ].
• The input list may contain throws where no pin at all is knocked over, in which case the score is let unchanged.
• You don't have anything special to do when the score reaches exactly 50 points. But you can assume that no other throw will follow when it happens.
• This is , so the shortest answer in bytes wins.

# Test cases

Using lists of integers as input:

[ 0 ] --> 0
[ 528 ] --> 2
[ 4095 ] --> 12
[ 64, 0, 3208 ] --> 16
[ 16, 1907, 2048 ] --> 18
[ 2023, 2010, 1, 8 ] --> 29
[ 1726, 128, 35, 3136, 1024 ] --> 34
[ 32, 32, 2924, 2, 256, 16 ] --> 28
[ 64, 64, 2434, 1904, 3251, 32, 256 ] --> 25
[ 3659, 2777, 2211, 3957, 64, 2208, 492, 2815 ] --> 25
[ 2047, 1402, 2, 2599, 4, 1024, 2048, 3266 ] --> 50
[ 256, 2304, 127, 64, 64, 128, 2048, 3072 ] --> 27
[ 16, 8, 128, 1, 2048, 1, 2048, 513, 8, 3206 ] --> 30


You can follow this link to get these test cases in Boolean format.

• Cool challenge, and also a great game to play in the summer for those of you who haven't tried it out — works great along with a grill. – Nit May 6 '18 at 22:31
• @Nit Thank you. :) I have to confess that I didn't know this game until today. I saw people playing it while walking in a park this afternoon. Now, I'd like to give it a try. – Arnauld May 6 '18 at 22:35

# Python 2, 126 111 108 104 bytes

-3 bytes thanks to Jonathan Allan

-4 bytes thanks to Kaya!

f=lambda A,t=0:t>50and f(A,25)or A and f(A[1:],t-~(sum(A[0])-1or 762447093078/12**A[0].index(1)%12))or t


Try it online!

Defines a recursive function that takes a 2D array of 1s and 0s and returns an integer value. Nothing too special in the construction, and I'm sure there's a simpler solution.

### Explanation:

f=lambda A,t=0:    #Define the function, initialising t to 0 on the first iteration
t>50and f(A,25)      #If t>50 then iterate again with t=25
or    #Else
A and                #If A exists
f(A[1:],       #Iterate again without the first list of A
t-~         #And add to t, either
(sum(A[0])-1   #The sum of all elements if that's not 1
or
762447093078/12**A[0].index(1)%12   #Else the appropriate pin value (black magic!)
or t       #Finally, if A is finished, just return t

• (0x103925BA4786>>4*A[0].index(1))%16 saves 1 character versus ord('GIHEKLFCJDAB'[A[0].index(1)])-65 – Kaya May 7 '18 at 4:58
• A little more optimal: 762447093078/12**A[0].index(1)%12 – Kaya May 7 '18 at 5:06
• That stuff looks like black magic to me! Thanks @Kaya! – Jo King May 7 '18 at 7:14
• That's just encoding with base 12 – enedil May 7 '18 at 13:01

# Jelly, 25 bytes

“ñ€bḷ’œ?TLḢṖ?µ€+25¹>?50ɗ/


A monadic link accepting a list of lists of ones and zeros (each of length 12) which returns an integer.

Try it online! Or see the test-suite (using the integer values given in the OP)

### How?

This solution makes use of, œ?, which given a number, n, and a list finds the nth lexicographical permutation of the list where the list defines the sort order. First we need to work out this n:

 index:  1  2  3  4  5  6  7  8  9 10 11 12
value:  7  9  8  5 11 12  6  3 10  4  1  2   (as defined by the question)
P: 11 12  8 10  4  7  1  3  2  9  5  6   (our permutation lookup array)


...that is, P at index i is set to the original index of the value i.
This P has a lexicographical index of 438,337,469 (that is, if you took all 12! permutations of the numbers 1 to 12 and sorted them lexicographically, the 438,337,469th would be P).
This may be found using Jelly's Œ¿ atom.
Both steps may be performed in one go using the Jelly program ĠŒ¿

“ñ€bḷ’œ?TLḢṖ?µ€+25¹>?50ɗ/ - Link: list of lists of zeros and ones
µ€           - perform the monadic chain to the left for €ach list:
“ñ€bḷ’                    -   base 250 number = 438337469
œ?                  -   nth permutation (reorder the 1s and 0s to their pin values)
T                 -   truthy indices (get the pin values of the 1s)
?             -   if...
Ṗ              -   ...condition: pop (length greater than 1 ?)
L                -   ...then: length (the number of pins)
Ḣ               -   ...else: head (the first (& only) pin value)
/ - reduce the resulting list of integers with:
ɗ  -   last three links as a dyad:
+          -     addition (add the two values together)
50   -     literal fifty
?     -     if...
>      -     ...condition: greater than (sum greater than 50 ?)
25        -     ...then: literal twenty-five
¹       -     ...else: identity (do nothing - just yield the sum)

• I think your explanation about finding the appropriate lexicographical index among all permutations would be worth adding as a Jelly tip. (Last time I had to do that, I did a manual dichotomic search, which is not that long for short sequences but ... kinda tedious. ^^) – Arnauld May 7 '18 at 10:32
• LOL; I had exactly the same solution, except for two different bytes: Ṗ -> Ḋ, µ -> Ʋ. Jelly would really benefit from acceppting a niladic link as ¡'s <link> (first argument), except that, if on the very start of the program, keep the special-casing behavior. – Erik the Outgolfer May 7 '18 at 15:05
• ...and I almost used both! – Jonathan Allan May 7 '18 at 15:07

# Python 2, 90 bytes

Heavily inspired by Jo King's Python 2 answer and utilising Kaya's base-12 representation comment

t=0
for v in input():t+=sum(v)-1or 762447093078/12**v.index(1)%12;t=[t+1,25][t>49]
print t


Try it online! Or see the test-suite

# Pyth, 5148 38 bytes

VQI>=+Z?qJsN1@.PC"îO&"S12xN1J50=Z25;Z


Saved 10 bytes thanks to Jonathan Allan Takes input as a list of lists of booleans.
Try it here

### Explanation

VQI>=+Z?qJsN1@.PC"îO&"S12xN1J50=Z25;Z
VQ                                  ;     For each input...
=+Z                                   ... add to the total...
?q sN1                             ... if one pin is down...
@.PC"îO&"S12xN1              ... the score of that pin.
J                    J           ... otherwise, the count.
I>                           50         If we pass 50...
=Z25     ... reset to 25.
Z    Output the total.

• Not sure how to get it into the program exactly, but it should save 6 or 7 bytes if you can... 7tT8h4hT12h5h2T4h02 -> .PC"îO&"S12 - uses lexicographical permutation indexing like my Jelly answer. (The code has an unprintable byte of 0x0F at the start of the string.) – Jonathan Allan May 7 '18 at 2:46
• )) can be ; – Jonathan Allan May 7 '18 at 2:58

# 05AB1E, 29 28 bytes

v•CÞŸαLć•13вyOΘmyÏOO25‚¬50›è


Try it online!

Explanation

v                              # for each boolean list in input
•CÞŸαLć•                      # push 13875514324986
13в                   # convert to a list of base-13 numbers
yO                 # push the sum of y
Θm               # truthify and raise the pin-list to this number (0 or 1)
yÏ             # keep those which are true in the current list
OO           # sum the list and the stack
25‚        # pair with 25
¬50›    # check if the first number is larger than 50
è   # index into the pair with this result


$\+=y/1//-1||/1/g&&(0,6,8,7,4,10,11,5,2,9,3,0,1)[pos];$\=25if++$\>50}{  Try it online! Takes input as a series of newline separated bitstrings. # Haskell, 96 bytes foldl(\s a->([s..50]++e)!!sum(last$zipWith(*)[7,9,8,5,11,12,6,3,10,4,1,2]a:[a|sum a>1]))0
e=25:e


Try it online!

The wrapping is clever: I essentially index at position s+sum(…) into the list ([0..50]++cycle[25]). However, a shorter way to write that is indexing at position sum(…) and beginning the list at s.

# Java 10, 131130 129 bytes

m->{int r=0,i,s,t;for(var a:m){for(i=s=t=0;i<12;s+=a[i++])t=a[i]>0?"    \n".charAt(i):t;r+=s<2?t:s;r=r>50?25:r;}return r;}


Contains 10 unprintables.
Input as integer-matrix of zeros and ones.

-1 byte thanks to @JonathanFrech, changing \t into an actual tab (works in TIO, doesn't work in my local IDE).

Try it online.

Explanation:

m->{                // Method with integer-matrix parameter and integer return-type
int r=0,          //  Result-integer, starting at 0
i,s,t;        //  Temp integers
for(var a:m){     //  Loop over the integer-arrays of the input
for(i=s=t=0;    //   Reset i, s and t to 0
i<12;       //   Loop i in the range [0,12)
s+=a[i++])  //    Increase s by the current value (0 or 1)
t=a[i]>0?     //    If the current value is 1:
"  \n".charAt(i)
//     Set t to the score at this position
:t;         //    Else: Leave t the same
r+=s<2?         //   If only a single pin was hit:
t           //    Add its score t to the result
:            //   Else:
s;          //    Add the amount of pins s to the result
r=r>50?         //   If the result is now above 50
25           //    Penalize it back to 25
:r;}          //   If not, it stays the same
return r;}        //  Return the result

• I think you can save one byte by using an actual tab character in "\t\n". – Jonathan Frech May 7 '18 at 10:14
• @JonathanFrech Hmm, indeed seems to work in TIO. Doesn't work locally in my IDE, but who cares about that I guess.. ;) – Kevin Cruijssen May 7 '18 at 10:27
• When there is a working implementation somewhere, it is allowed. :@ – Jonathan Frech May 7 '18 at 11:59

# Charcoal, 43 bytes

≔⁰ηＦθ«≧⁺⎇⊖ΣιΣι⌕α§”$｜#z⁸Ｕg⊗”⌕ι¹η¿›η⁵⁰≔²⁵η»Ｉη  Try it online! Link is to verbose version of code. Takes input as a boolean array. Explanation: ≔⁰η  Set the score to 0. Ｆθ«  Loop over the throws. ⎇⊖Σι  Is the number of pins 1? Σι  If not, then take the number of pins. ⌕α§”$｜#z⁸Ｕg⊗”⌕ι¹


Otherwise, translate the position of the pin to a value.

≧⁺...η


Add it to the score.

¿›η⁵⁰≔²⁵η


If the score exceeds 50 then set it back to 25.

»Ｉη


Print the final result after all the throws.

# Haskell, 110 bytes

m s|sum s==1=sum$zipWith(*)[7,9,8,5,11,12,6,3,10,4,1,2]s|1>0=sum s f l=foldl(\b->c.(b+).m)0l c a|a>50=25|1>0=a  Same length: f l=foldl(\b a->last$b+m a:[25|b+m a>50])0l instead of f and c

Try it online!

• Drop the l argument in f for 3 bytes. f=foldl(\b->c.(b+).m)0 – aoemica May 11 '18 at 1:14

# Husk, 47 35 bytes

-12 bytes thanks to H.PWiz (better way of generating the list encoding points)!

F₅0
S?25>50+?←Lεf+Nm+3d4652893071


Try it online!

### Explanation

F₅0  -- input is a list of boolean lists
F    -- left fold by
₅   -- | the function flipped (overflowing label) on line 1
0  -- | with initial value 0

S?25>50+?←Lεf+Nm+3d4652893071  -- example inputs: [0,0,0,1,0,0,0,0,0,0,0,0] 0
4652893071  -- integer literal: 4652893071
d            -- digits: [4,6,5,2,8,9,3,0,7,1]
m+3             -- map (+3): [7,9,8,5,11,12,6,3,10,4]
+N                -- append natural numbers: [7,9,8,5,11,12,6,3,10,4,1,2,3,...
f                   -- filter this list by argument: [5]
?  ε                     -- if it's of length 1
←                       -- | take first
L                      -- | else the length
-- : 5
+                         -- add to argument: 5
?  >50                          -- if the value is > 50
25                             -- | then 25
S                                -- | else the value
-- : 5

• How about m+3d4652893071? – H.PWiz May 7 '18 at 0:35

# Red, 189 172 bytes

func[b][s: 0 foreach c b[d: 0 foreach e c[if e = 1[d: d + 1]]i: find c 1
n: either i[pick[7 9 8 5 11 12 6 3 10 4 1 2]index? i][0]if 50 < s: s + either 1 < d[d][n][s: 25]]s]


Try it online!

## Explanation of the ungolfed code:

f: func[b][                                            ; a block of blocks of booleans
s: 0                                               ; sets sum to 0
foreach c b[                                       ; for each row of booleans
d: 0 foreach e c[if e = 1[d: d + 1]            ; count the number of 1s
i: find c 1                                    ; the index of the first 1
n: either i[pick [7 9 8 5 11 12 6 3 10 4 1 2]  ; if there is 1, pick the number
index? i][0]                       ; at the index of 1
; otherwise 0
if 50 < s: s + either 1 < d[d][n][s: 25]       ; if there is only one 1, add
; the number to the sum, otherwise
; the number of 1s
; if the sum > 50, reset it to 25
]
s                                                  ; return the sum
]


# JavaScript (ES6), 98 bytes

a=>a.map(b=>b.map((m,i)=>(c+=m,d+=m*('0x'+'7985bc63a412'[i])),c=d=0)|(t+=c>1?c:d)>50?t=25:0,t=0)|t


Test cases:

f=
a=>a.map(b=>b.map((m,i)=>(c+=m,d+=m*('0x'+'7985bc63a412'[i])),c=d=0)|(t+=c>1?c:d)>50?t=25:0,t=0)|t

console.log(f([ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ])) // 0

console.log(f([ [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 ] ])) // 2

console.log(f([ [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] ])) // 12

console.log(f(
[ [ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ] ]
)); // 16

console.log(f(
[ [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ],
[ 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
])); // 18

console.log(f(
[ [ 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1 ],
[ 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 ] ]
)); // 29

console.log(f(
[ [ 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0 ],
[ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 ],
[ 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ]
))  // 34

console.log(f(
[ [ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ],
[ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ] ]
))  // 28

console.log(f(
[ [ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 ],
[ 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0 ],
[ 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1 ],
[ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ] ]
))  // 25

console.log(f(
[ [ 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1 ],
[ 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1 ],
[ 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1 ],
[ 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1 ],
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0 ],
[ 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 ] ]
)) // 25

console.log(f(
[ [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
[ 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 ],
[ 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 ],
[ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 ] ]
)) // 50

console.log(f(
[ [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 ],
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ]
)) // 27

console.log(f(
[ [ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
[ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 ],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
[ 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0 ] ]
)) // 30

• Same size as (and very similar to) my reference implementation. :) – Arnauld May 8 '18 at 20:14
• Ah, cool. I'm happy whenever I can match your code size. It's only once in a blue moon that I can beat it :) – Rick Hitchcock May 8 '18 at 20:20

# Stax, 37 bytes

├T<↓"♥←~;▌6»≥øF←î5░U╚_π○Q▒<│∟└ù║pε♀▀æ


Run and debug it

Try It online!

Explanation

F:1"=EA5MQ9-I1%)"!s@c%1={h+}{%+}?c50>{d25}{}?    # Full program, unpacked

F                                                # Loop through every element
:1                                              # Get indices of truthy elements
"=EA5MQ9-I1%)"!                               # Push encoded [7,9,8,5,11,12,6,3,10,4,1,2]
s@                              # Swap the top 2 elements of stack and get elements at indexes
c%1=                          # Copy the top element, get length of array, compare to length of 1
{h+}{%+}?                 # If it has length of 1, add the element, otherwise add the length of the array to total
c50>            # Compare total to 50,
{d25}{}?    # If it is greater, pop it off and push 25 to reset counter, otherwise do nothing


Not my best work, but it works. I'm sure there is somehting I'm missing to make it a bit shorter.

# Python 2, 109105 103 bytes

c=0
for l in input():a=sum(l);c+=int('7985bc63a412'[l.index(1)],16)if a==1else a;c=(25,c)[c<51]
print c


Try it online!

Alternative without a recursive function.

-2 with thanks to @Jo King

• You can remove the brackets around the string literal – Jo King May 7 '18 at 22:15