# Snooker scoring

I was watching the world snooker championship and it got me wondering..

Snooker scoring

In the game of snooker there are certain rules that you must adhere too:

• When there are red balls on the table, during your turn you must first pot a red ball
• After potting each red ball, you must pot a colored (not red) ball (the potted colored ball is then replaced onto the table)
• After all the red balls are up (there are 15) you can first choose a colored ball and then you start with the lowest scoring ball and work your way up to the highest scoring ball (these are not replaced)
• Not potting at any point ends your turn.
• Points per ball
• Red ball: 1 point
• Yellow ball: 2 points
• Green ball: 3 points
• Brown ball: 4 points
• Blue ball: 5 points
• Pink ball: 6 points
• Black ball: 7 points

The question

You start with a table with all the balls still on it - 15 red and one of each of the other coloured balls - and are given the score of a player in snooker after their first turn, what are the ways that they could have achieved this score?

Input will be a score going from 1 to 147. You can choose if it is an integer or a string. Output should be the different combinations of number of times you potted each ball.

Test cases:

Input: 4
Output:
1r 1g
2r 1y
Input: 25
Output:
4r 3b
5r 2b 1br 1y
5r 2b 2g
...
9r 8y


Rules:

• You can choose whether you output the possibilities divided by a new line or a separator of some sort (/,;|\ or even others I'm missing)

This is codegolf, so the shortest code wins.

• Can I output as list of arrays? Commented Apr 25, 2017 at 5:29
• I'd recommend making the input score range between 1 and 147 (oh for the 155). Commented Apr 25, 2017 at 6:05
• Regarding an array output: number of balls ordered by score is unambiguous, so maybe "5r 3b 2g" could be output as [5,0,2,0,3,0,0] (as long as this is consistent)? Commented Apr 25, 2017 at 6:10
• You use b for brown and bl for blue; so bk for black? Could we use n, e and k (last letters) for these three? How about dleruna to identify all eight colours (3rd letter of each)? Commented Apr 25, 2017 at 7:20
• @Shaggy, If you use an indication of color like dleruna or another one, no. If you just use an array like [5 0 0 4 1 0 0], then they should be sorted from low to high. Commented Apr 25, 2017 at 8:15

# Jelly,  65  25 bytes

7Ḋṗ15Ė€F;ɗ€ƊÄċƇ⁸f€RŻ€IṢ€Q


A monadic Link that accepts an integer, "score", from $$\[1,147]\$$ and yields a list of lists - each being a potential selection of ball scores used in reaching the given score disregarding the order in which they were actually potted.

Try it with only six reds (15 replaced with 6; again, fifteen reds would take an age).

### How?

7Ḋṗ15Ė€F;ɗ€ƊÄċƇ⁸f€RŻ€IṢ€Q - Link integer, S
7                         - seven
Ḋ                        - dequeue -> coloured ball scores, [2..7]
Ɗ              - last three links as a monad - f([2..7]):
15                     -   fifteen
ṗ                       -   ([2..7]) Cartesian power (15) -> all length 15 words
using the coloured ball scores as letters
€               -   for each (such Word):
ɗ                -     last three links as a dyad - f(Word, [2..7])
e.g. Word = [7,...,7]
Ė€                   -       enumerate each          [[1,7],...,[1,7]]
F                  -       flatten                 [1,7,...,1,7]
;                 -       concatenate ([2..7])    [1,7,...,1,7,2,3,4,5,6,7]
Ä             - cumulative sums, i.e. convert each such legal way to
clear the table to a list of the running score
Ƈ           - filter keep those for which this is truthy (non-zero):
⁸          -   chain's left argument (S)
ċ            -   count - i.e. count of S in the running score
R       - range (input Score) -> [1..S]
f€        - for each (running score list) filter keep ([1..S])
Ż€     - prefix each with a zero
I    - forward differences of each (back to ball scores)
Ṣ€  - sort each
Q - deduplicate


Original $$\66\$$ byte entry ($$\65\$$ really, since the trailing G is post-formatting):

L⁼30µÐfµ7Ḋ;\¤;€Ṣ€µ€;/
ċ1<⁴µÐfµ;Ç
7Ḋœċ⁴Ḷ¤;/L€;$€;@þ2B¤;/ḟ€0ÇS⁼¥Ðf⁸G  Well, it's too slow for TIO now! ...so here is a paste of the 2636 ways to make exactly 100 produced offline. ...and here is a version that will run there with just SIX reds (maximum break = 75) Prints a grid of numbers each line being a space separated list of ball values (e.g. three red and two green would be on a line reading 1 1 1 3 3). For a value-grouped version that prints lines of counts along with the full names of the balls, at 102 bytes: ŒrÑ€ Ṫ;ị“¡^³ṗ⁼¬wḌ⁼ø÷OẏK¦ẆP»Ḳ¤$K
L⁼30µÐfµ7Ḋ;\¤;€Ṣ€µ€;/
ċ1<⁴µÐfµ;Ç
7Ḋœċ⁴Ḷ¤;/L€;$€;@þ2B¤;/ḟ€0ÇS⁼¥Ðf⁸Ñ€K€Y  ### How? L⁼30µÐfµ7Ḋ;\¤;€Ṣ€µ€;/ - Link 1, create post-red-ball games: list of all pre-yellow-ball-games µÐf - filter keep if: L⁼30 - length equals 30 (games that get on to the yellow) µ µ€ - for €ach sequence leading to the yellow: ¤ - nilad followed by link(s) as a nilad: 7Ḋ - 7 dequeued = [2,3,4,5,6,7] ;\ - ;\ cumulative reduce with concatenation = [[2],[2,3],[2,3,4],...] ;€ - concatenate the sequence with €ach of those Ṣ€ - sort each one ;/ - reduce with concatenation (flatten by one) ċ1<⁴µÐfµ;Ç - Link 2, filter bogus entries created and append post-yellow-ball games: list of pre-yellow-ball games (along with the bogus ones with 16 reds potted) µÐf - filter keep if: ċ1 - count ones ⁴ - literal 16 < - less than? µ - monadic chain separation Ç - call the last link (1) as a monad ; - concatenate 7Ḋœċ⁴Ḷ¤;/L€;$€;@þ2B¤;/ḟ€0ÇS⁼¥Ðf⁸G - Main link: score
7Ḋ                                - 7 dequeued = [2,3,4,5,6,7]
⁴                            -   literal 16
Ḷ                             -   lowered range = [0,1,2,...,15]
œċ                              - combinations with replacement (every possible colour-ball selection that goes with the red pots)
;/                         - reduce with concatenation (flatten by one)
\$€                    - last two links as a monad for €ach:
L€                       -   length of €ach (number of coloured balls potted)
;                      -   concatenate
2B               -   2 in binary = [1,0]
þ                 - outer product with:
;@                  -   concatenation with reversed @rguments
;/            - reduce with concatenation (flatten by one)
ḟ€0         - filter discard zeros from €ach
Ç        - call the last link (2) as a monad
Ðf   - filter keep:
¥  ⁸  -   last two links as a dyad, with score on the right
S⁼      -     sum(ball values) is equal to score?
G - format as a grid
- implicit print

• It works well for all the cases I have tried. Only in some cases the last code gives leading zeros. Commented Apr 25, 2017 at 9:25
• Ah yes they should have been filtered out... Fixed. Commented Apr 25, 2017 at 9:25
• Your output for the 53 one is unambiguous as I said before, but I'm still doubting if it is readable for everyone.. Commented Apr 25, 2017 at 10:47
• It is much better in the grid way. If there aren't any shorter answers in the next few days, I am going to accept your answer! Commented Apr 25, 2017 at 11:48
• Hmm. I get 2636 century break combinations. So either you or I are wrong... Commented Apr 25, 2017 at 14:01

## JavaScript (ES7), 188180 178 bytes

Returns an array of arrays (sorted from red to black).

n=>[...Array(17**6)].map((_,x)=>[2,3,4,5,6,p=7].map(v=>(k=a[++j]=x%17|0,x/=17,t+=k,p+=!!(y=y&&k),s-=k*v),y=s=n,a=[j=t=0])&&(s==15|s>=t)&s<16&s<t+2&t<9+p&&(a[0]=s,a)).filter(a=>a)


### Commented

Note: This version doesn't include the last optimization on p (now initialized to 7) which makes the logic harder to understand.

n =>                              // given a target score n:
[...Array(17**6)].map((_, x) => // for each x in [0 .. 17^6 - 1]:
[2, 3, 4, 5, 6, 7].map(v =>   //   for each v in [2 .. 7] (yellow to black):
( k = a[++j] = x % 17 | 0,  //     k = a[j] = number of colored balls of value v
x /= 17,                  //     update x to extract the next value
t += k,                   //     update t = total number of colored balls
p += !!(                  //     update p = number of consecutive colors that were
y = y && k              //     potted at least once, using y = flag that is zeroed
),                        //     as soon as a color is not potted at all
s -= k * v ),             //     subtract k * v from the current score s
y = s = n,                  //     initialize y and s
a = [j = t = p = 0]         //     initialize a, j (pointer in a), t and p
)                             //   at this point, s is the alleged number of red balls
&&                            //   this combination is valid if we have:
(s == 15 | s >= t) &        //     - 15 red balls or more red balls than colored ones
s < 16 &                    //     - no more than 15 red balls
s < t + 2 &                 //     - at most one more red ball than colored ones
t < 16 + p                  //     - no more than 15 + p colored balls
&&                            //   if valid:
(a[0] = s, a)               //     update the combination with red balls and return it
).filter(a => a)                // end of outer map(): filter out invalid entries


### Example output

Below is the output for n = 140:

//  R   Y  G  Br Bl P  Bk
[ [ 15, 1, 1, 1, 1, 8, 9  ],
[ 15, 1, 1, 1, 2, 6, 10 ],
[ 15, 1, 1, 1, 3, 4, 11 ],
[ 15, 1, 1, 2, 1, 5, 11 ],
[ 15, 1, 1, 1, 4, 2, 12 ],
[ 15, 1, 1, 2, 2, 3, 12 ],
[ 15, 1, 2, 1, 1, 4, 12 ],
[ 15, 1, 1, 2, 3, 1, 13 ],
[ 15, 1, 1, 3, 1, 2, 13 ],
[ 15, 1, 2, 1, 2, 2, 13 ],
[ 15, 2, 1, 1, 1, 3, 13 ],
[ 15, 1, 2, 2, 1, 1, 14 ],
[ 15, 2, 1, 1, 2, 1, 14 ],
[ 15, 1, 1, 1, 1, 1, 15 ] ]


### Demo

This is too slow for a snippet. You can try it here instead. (You may get one or two unresponsive script alerts, but it should eventually complete.)