# Can you Golf Golf?

You are required to generate a random 18-hole golf course.

Example output:

``````[3 4 3 5 5 4 4 4 5 3 3 4 4 3 4 5 5 4]
``````

Rules:

• Your program must output a list of hole lengths for exactly 18 holes
• Each hole must have a length of 3, 4 or 5
• The hole lengths must add up to 72 for the entire course
• Your program must be able to produce every possible hole configuration with some non-zero-probability (the probabilities of each configuration need not be equal, but feel free to claim extra kudos if this is the case)
-
Please confirm, 44152809 solutions? – baby-rabbit Sep 26 '12 at 0:38
I too am curious on the exact number of solutions, however I think it should be more than 44 million... (I am no mathmetician, however: | 1(5)/1(3) = 306 possibilities (17*18) | 2(5)/2(3) = 69360 poss (17*17*16*15) | 3(5)/3(3) = 11182080 poss (16*16*16*15*14*13) | does that look right? – NRGdallas Sep 26 '12 at 15:51
@baby-rabbit: I can confirm 44,152,809 solutions by brute force enumeration. Also, it can be directly calculated this way: since the average is exactly `4`, and the only possibilities are `3`, `4`, or `5`, the possible solution classes are { `no 3's or 5's`, `one 3 and one 5`, `two 3's and two 5's`, ..., `nine 3's and nine 5's` }. This can be calculated by `nCr(18,0)*nCr(18,0) + nCr(18,1)*nCr(17,1) + nCr(18,2)*nCr(16,2) + ... + nCr(18,9)*nCr(9,9) = 44,152,809`. This means approximately `11.4%` of all possible combinations are valid solutions `(44,152,809 / 3^18)`. – mellamokb Sep 26 '12 at 22:02

# k (18 17 16 chars)

Back to the original approach, credit to CS for the improvement.

``````(+/4-){3+18?3}/0
``````

Other approach (17 chars), same method as the J solution, H/T to CS

``````4+a,-a:9?2 -18?18
``````

Old version:

``````(72-+/){18?3+!3}/0
``````

Not susceptible to stack-overflow and runs in fixed amount of space.

-
 What's H/T to CS? – Gareth Sep 26 '12 at 14:11 – slackwear Sep 26 '12 at 14:35

# K, 28

``````{\$[72=+/s:18?3 4 5;s;.z.s`]}
``````
-
+1 Awesome solution! – Helper Method Sep 25 '12 at 11:33

## J, 2018 17 characters

``````(?~18){4+(,-)?9#2
``````

This works in the same way as the previous answer except that the 9 random digits are either 0 or 1 and are negated before being appended. This means there are as many `-1`s as there are `1`s. Adding 4 gives me a list of `3`s, `4`s and `5`s that add up to 72 every time.

Previous answer:

``````({~?~@#)3+(,2-])?9#3
``````

Generates the first 9 holes randomly `?9#3`, then copies and inverts them `(,2-])` (turns a 3 into a 5 and a 5 into a 3) to generate the final 9. This guarantees that the total will be 72 (since every 3 will have a matching 5 the average total per hole will be 4 and 4x18=72). It then randomly shuffles the result `({~?~@#)` to ensure that every combination is possible.

-
 actually you won't generate {3,5,4,4,4...} you are better off shuffling the entire result – ratchet freak Sep 25 '12 at 11:23 @rachetfreak Good point. I'll edit now. – Gareth Sep 25 '12 at 11:31

# Mathematica 71 68

Code

``````RandomSample@IntegerPartitions[72, {18}, {3, 4, 5}][[RandomInteger@9 + 1]]
``````

Design 5 courses

``````Table[RandomSample@IntegerPartitions[72, {18}, {3, 4, 5}][[RandomInteger@{1, 10}]], {5}]
``````

Analysis

``````IntegerPartitions[72, {18}, {3, 4, 5}]
``````

produces all 10 possible partitions of 72 into 18 elements consisting of 3's, 4's and 5's.

`%[[RandomInteger[{1, 10}]]]` randomly selects one of those 10 partitions. `%` represents the most recent input of code.

`RandomSample` gives a pseudorandom permutation of the selected partition. In other words, it jumbles the digits.

Because the number of permutations for the 10 partitions vary (enormously), the distribution of golf courses is not random. In fact, the course consisting of 18 holes of par 4 will be appear approximately one time out of ten.

-

## GolfScript, 27 chars

``````{;18{3.rand+}*].{+}*72-}do`
``````

Uses the same rejection sampling method as sgrieve's Python solution. Thus, every valid output actually is equally likely.

-

## GolfScript (26 chars)

``````{;0{3rand.3+@@+(}18*])}do`
``````

There are some obvious similarities with Ilmari's solution, but also some obvious differences. In particular, I'm exploiting the fact that the average par is 4.

-
 Damn, but that sure is a clever trick with the loop condition there. I came up with `{;0{3.rand+.@+}18*])72-}do` myself, but couldn't figure out how to get it any shorter from there. +1. – Ilmari Karonen Sep 25 '12 at 23:54

## Q (25 characters)

Original (27)

``````while[72<>sum a:18?3 4 5];a
``````

Sample output

``````4 4 3 3 4 5 4 3 4 5 5 3 5 5 5 4 3 3
``````

Slightly shorter (25)

``````{72<>sum x}{x:18?3 4 5}/0
``````
-

# Python 70

``````from random import*
print sample(([3,5]*randint(0,9)+[4]*99)[:18],18)
``````
edit:

Here's another one, similar to the solution of sgrieve:

# Python 73 + equal probability

``````from random import*
a=[]
while sum(a)-72:a=sample([3,4,5]*18,18)
print a
``````
-

## 16-bit x86 machine code under MS-DOS - 45 bytes

Hexdump:

``````0E5F576A12595188ECE44088C3E44130D8240374F400C4AAE2EF595E80FC2475DFAC0432CD29B020CD29E2F5C3
``````

Base64 coded binary:

``````Dl9XahJZUYjs5ECIw+RBMNgkA3T0AMSq4u9ZXoD8JHXfrAQyzSmwIM0p4vXD
``````

Actual source code with some comments:

`````` bits 16
org 0x100

again:
push cs               ; Save whatever CS we get.
pop di                ; Use CS:DI as our course buffer..
push di               ; Save for later use in the print loop
push 18               ; We need 18 holes for our golf course.
pop cx                ; ch = 0, cl = 18.
push cx               ; Save for later use.
mov ah, ch            ; Zero out ah.
generate_course:
in al, 0x40           ; Port 0x40 is the 8253 PIT Counter 0.
mov bl, al            ; Save the first "random" value in bl.
in al, 0x41           ; Port 0x41 is the 8253 PIT Counter 1.
xor al, bl            ; Add some more pseudo randomness.
and al, 3             ; We only need the two lower bits.
jz generate_course    ; If zero, re-generate a value, since we need only 3, 4, 5 holes.
add ah, al            ; Sum in ah register.
stosb                 ; Store in the course buffer.
loop generate_course  ; Loop for 18 holes.
pop cx                ; cx = 18.
pop si                ; si = course buffer.
cmp ah, 36            ; 72 holes?
jne again             ; No, re-generate the whole course.

print:                 ; Yup, we have a nice course.
lodsb                 ; Load the next hole.
add al, '2'           ; Add ASCII '2' to get '3', '4' or '5'
int 0x29              ; Undocumented MS-DOS print function.
mov al, ' '           ; Print a space too for better readability.
int 0x29              ; Print the character.
loop print            ; Print the whole course.
ret                   ; Return to the beginning of the PSP where a INT 0x20 happen to be.
``````

Compile with `nasm 18h.asm -o 18h.com` and run under MS-DOS (or Dosbox), or NTVDM from a 32-bit Windows version.

Sample output:

``````4 5 4 5 4 5 3 4 3 4 3 4 4 5 4 3 5 3
``````
-
love assembler... – woliveirajr Sep 27 '12 at 12:18

# Python 77

Code

``````from numpy.random import*;l=[]
while sum(l)!=72:l=randint(3,6,18)
print l
``````

Output

``````[3 4 4 5 3 3 3 5 4 4 5 4 5 3 4 4 5 4]
``````

The import really kills this solution. It uses numpy to generate a 18 numbers between 3 and 5 and keeps generating lists until the sum of the list equals 72.

-
What prevents the program from reaching 72 well before generating 18 holes? What prevents it from skipping 72? – David Carraher Sep 25 '12 at 9:35
The code will always generate 18 holes, then check if the sum equals 72. For example, if the sum after 16 holes was 72, it would still generate another 2 holes, therby pushing the sum above 72 and failing the test. – sgrieve Sep 25 '12 at 9:40

## R - 41

``````x=0;while(sum(x)!=72)x=sample(3:5,18,T);x

# [1] 5 3 5 3 3 3 3 3 5 4 5 4 5 4 4 5 5 3
``````

The algorithm is similar to @sgrieve's.

-
Same problem as @sgrieve above -- nothing prevents it from going over in 18 holes. – gt6989b Sep 25 '12 at 12:27
That's not a problem, the sample command in this case always generates 18 values. – sgrieve Sep 25 '12 at 12:35

# JavaScript 11699 65

for(i=0,h=[];i<18;)h[i++]=5;while(h.reduce(function(a,b){return a+b})!=72){i=Math.random()*18|0;h[i]=[3,4,4][i%3]}h;

h=[0];while(h.reduce(function(a,b){return a+b})-72)for(i=0;i<18;h[i++]=[3,4,5][Math.random()*3|0])h

``````while(i%18||(a=[i=s=0]),s+=a[i++]=Math.random()*3+3|0,s-72|i-18)a
``````
-
`function(a,b)a+b` in JS 1.8 – grawity Sep 25 '12 at 19:31
When I run this in Chrome 21, I get `i is not defined`. – mellamokb Sep 26 '12 at 23:24

# JavaScript, 6664 61 chars

Heavily inspired by TwoScoopsofPig (PHP) and Joe Tuskan (JS).

``````for(a=[s=0];s!=72;)for(s=i=0;i<18;s+=a[i++]=Math.random()*3+3|0);a
``````

``````for(a=[s=0];s-72;)for(s=i=0;i<18;s+=a[i++]=Math.random()*3+3|0)a
``````

``````for(a=s=[];s;)for(i=18,s=72;i;s-=a[--i]=Math.random()*3+3|0)a
``````
-
`s!=72` can be `s-72` to save one char. And the last semi-colon `;a` isn't needed either for another char. – Joe Tuskan Sep 25 '12 at 20:21

Python, 128 120 116 characters

``````import random,itertools
random.choice([g for g in itertools.product(*(range(3,6)for l in range(18))) if sum(g)==72])
``````

`import` statements are still length killers (23 characters only to import 2 function in the namespace)

i hope you do not need the result in a near future, as this code first evaluates all possible solutions before chosing one at random. maybe the slowest solution to this problem.

i do claim extra kudos for equal probability of each configuration...

-
`import random,itertools` – grawity Sep 25 '12 at 20:59
you are right, that shorten things a bit. – Adrien Plisson Sep 26 '12 at 9:02
Other tips: `import random as r,itertools as i` then use `r` and `i` instead of `random` and `itertools`. Use `18*[0]` instead of `range(18)`, and `[3,4,5,6]` instead of `range(3,6)` :) – Alex L Sep 26 '12 at 9:20
i am using python 3: a list comprehension is a generator and has no length, which forbids its use with the `choice()` function. that's also what makes this code so slow... – Adrien Plisson Sep 26 '12 at 9:23
ooops, sorry, i messed up list comprehension and generator expression (i generally avoid list comprehension in favor of generator expression because of the better performance of iterator). so indeed, even in python3 i can still remove some characters... @Alex did it right. – Adrien Plisson Sep 26 '12 at 15:39
show 2 more comments

# PHP - 77 Chars

``````<?while(array_sum(\$a)!=72){for(\$i=0;18>\$i;){\$a[++\$i]=rand(3,5);}}print_r(\$a);
``````

Much like sgrieve's solution, this builds a list of 18 holes, checks total par, and either prints it or rejects it and tries again. Oddly enough, our two solutions are the same length.

Rather annoyingly, PHP doesn't offer array functions with any brevity of name. Array_sum and print_r are killing me. Suggestions welcome.

-
Curly braces are not needed here, and sum can be `+=`. `<?while(\$s!=72)for(\$s=\$i=0;18>\$i;\$s+=\$a[++\$i]=rand(3,5));print_r(\$a);` – grawity Sep 25 '12 at 19:13
That's useful - I never thought to put the logic in the for loop call (and I feel kinda dumb for not incrementing a counter for the sum). – TwoScoopsofPig Sep 26 '12 at 19:45
Thanks â€“ but that isn't actually what I meant by "curly braces not needed"; you could have removed them in the original code too: `while(array_sum(\$a)!=72)for(\$i=0;18>\$i;)\$a[++\$i]=rand(3,5);` – grawity Sep 27 '12 at 16:40
Well except I run against a stricter php.ini than that because I'm golfing at work; it complains no end about braces being missing/mismatched. Normally I would have. – TwoScoopsofPig Oct 17 '12 at 17:53
That's odd; 5.4.7 with E_ALL|E_STRICT never complains about missing `{}`'s (since PHP's syntax explicitly allows that). – grawity Oct 17 '12 at 18:21
show 1 more comment

# Ruby 1.9 (62 chars)

``````a=Array.new(18){[3,4,5].sample}until(a||[]).inject(:+)==72
p a
``````

# Rails (55 chars)

In the `\$ rails c` REPL (in any Rails folder):

``````a=Array.new(18){[3,4,5].sample}until(a||[]).sum==72
p a
``````

Note: It works with Ruby 1.8 if you use `shuffle[0]` instead of `sample`.

-
Do you need whitespace around until? – Kaz Sep 25 '12 at 19:41
@Kaz You're right, it's not needed. :) 62 chars now. – js-coder Sep 26 '12 at 12:18

# Java (61 chars)

``````while(s!=72)for(i=0,s=0;i<18;i++)s+=3+(int)(Math.random()*3);
``````

Sample output:

``````5 4 3 4 5 3 4 4 3 5 4 4 4 4 3 4 4 5
``````
-

# Lisp (78 69 chars)

(do((c()(mapcar(lambda(x)(+ 3(random 3)))(make-list 18))))((=(apply'+ c)72)c))

``````(do((c()(loop repeat 18 collect(+ 3(random 3)))))((=(apply'+ c)72)c))
``````

It's rather similar to sgrieve's Python solution.

Start with c as NIL, check for a sum of 72, the `do` "increment function" for c generates a list of 18 numbers between 3 and 5, check for 72 again, lather, rinse, repeat.

It's refreshing to see `do` and `loop` nicely play golf together.

-

# Clojure - 55

``````(shuffle(mapcat #([[4 4][3 5]%](rand-int 2))(range 9)))
``````

Quite a fun trick.... exploits the mathematical structure of the problem that there must be exactly as many 3 par holes as 5 par holes.

-

# Python 83

``````import random as r;x=[]
while sum(x)!=72:x=[r.randint(3,5) for i in 18*[0]]
print x
``````

Like sgrieve's solution, but without numpy

Golfing Adrien Plisson's solution: 120->108 characters

``````import random as r,itertools as i
r.choice([g for g in i.product(*([3,4,5,6]for l in 18*[0]))if sum(g)==72])
``````

# MATLAB 53

``````x=[];
while sum(x)~=72
x=3+floor(rand(1,18)*3);
end
x
``````

Output:

x = 4 3 4 4 4 4 5 4 4 3 4 4 3 5 3 5 4 5

-

# C (94 chars)

``````int h[18],s=0,i;
while(s!=72)for(i=s=0;i<18;s+=h[i++]=rand()%3+3);
while(i)printf("%d ",h[--i]);
``````

The `s=0` on line 1 may not be required, because what are the chances an uninitialized int will equal 72? I just don't like reading uninitialized values in straight C. Also, this probably requires seeding the `rand()` function.

## output

``````3 3 3 4 5 5 3 3 4 5 5 4 3 4 5 5 5 3
``````
-
So basically you're gonna loop through random strings of 18 numbers ranged 3 to 5 until one happens to equal 72? Good thing efficiency isn't a requisite. – KeithS Sep 25 '12 at 23:10
@KeithS To be fair, that's what the majority of the answers to this question are doing. – Gareth Sep 25 '12 at 23:19

# TXR (100 chars)

``````@(bind g@(for((x(gen t(+ 3(rand 3))))y)(t)((pop x))(set y[x 0..18])(if(= [apply + y]72)(return y))))
``````

This expression generates an infinite lazy list of random numbers from 3 to 5:

``````(gen t (+ 3(rand 3)))  ;; t means true: while t is true, generate.
``````

The rest of the logic is a simple loop which checks whether the first 18 elements of this list add up to 72. If not, it pops an element off and tries again. The `for` loop contains an implicit block called `nil` and so `(return ...)` can be used to terminate the loop and return value.

-
 I put in a commit that allows the (t) to be replaced by (). :) – Kaz Sep 25 '12 at 20:03

## C (123 chars) - effort on efficiency

Pipe through wc and it will generate all 44152809 solutions within 10 seconds...

``````char s[19];g(d,t){int i;if(d--){for(i=51,t-=3;i<54;i++,t--)if(t>=3*d&&t<=5*d)s[d]=i,g(d,t);}else puts(s);}main(){g(18,72);}
``````

Oh, well - didn't read the question properly - but given we're generating all solutions then picking a random one with equal probability is a scripting exercise :P

-

## Bash shell script (65 chars)

``````shuf -e `for x in {0..8}
do echo \$((r=RANDOM%3+3)) \$((8-r))
done`
``````

(shuf comes from the GNU coreutils package. Also, thanks Gareth.)

-

# C# (143 non-whitespace):

``````()=>{
var n=new Math.Random().Next(10);
Enumerable.Range(1,18)
.Select((x,i)=>i<n?3:i>=18-n?5:4)
.OrderBy(x=>Guid.NewGuid())
.ForEach(Console.Write);
}
``````
-
 `new Guid()` creates an empty GUID. To actually generate a unique GUID you need to call a static method `Guid.NewGuid`. – Rotsor Sep 26 '12 at 5:18 And you have two off-by-one errors (so to speak): the comparisons should be i=18-n, not the other way around. And you could reduce the size by using a constant 3 instead of x-1 and 5 instead of x+1. And then you could replace Enumerable.Repeat by Enumerable.Range. – Mormegil Sep 26 '12 at 14:20 Edited; still 143 chars – KeithS Sep 26 '12 at 16:16

# Haskell, 104102 98 chars.

``````import System.Random
q l|sum l==72=print l|1>0=main
main=mapM(\_->randomRIO(3::Int,5))[1..18]>>=q
``````
-
 `[1..n]>>[r]` is slightly shorter than `replicate n\$r`. – leftaroundabout Sep 27 '12 at 19:17 Good idea! Thanks. – Rotsor Sep 27 '12 at 23:09 Also changed `sequence` to `mapM`. – Rotsor Sep 27 '12 at 23:14

# Python, 97

Using a different method than the rejection sampling, this picks a random list of indices of random even length and alternates adding and subtracting to the elements at these indices.

``````from random import*;a=[4]*18;d=1
for i in sample(range(18),2*randint(0,9)):a[i]+=d;d=-d
print a
``````
-

# Clojure - 72 chars

`(some #(if(=(apply +%)72)%)(partition 18(repeatedly #(+(rand-int 3)3))))`

Would be much shorter if Clojure didn't have such flowery descriptive function names :-)

-

# Groovy

126 chars

``````def a=[];while(1){(new Random().nextInt(3)!=1&&a.size()<17?a<<3<<5:a<<4);if(a.size()==18)break};Collections.shuffle(a);print a
``````

... ooooh, what a waste of chars :)

110 chars

``````def a=[];while(a.size()<18){(new Random().next(2)>1&&a.size()<17?a<<3<<5:a<<4)};Collections.shuffle(a);print a
``````
-

## Perl, 74

``````{@c=map{3+int rand 3}(0)x18;\$s=0;\$s+=\$_ for@c;redo unless\$s==72}print"@c"
``````

Alternative solution:

``````@q=((3,5)x(\$a=int rand 9),(4,4)x(9-\$a));%t=map{(rand,\$_)}(0..17);print"@q[@t{sort keys%t}]"
``````
-