53
\$\begingroup\$

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)
\$\endgroup\$
  • 3
    \$\begingroup\$ Please confirm, 44152809 solutions? \$\endgroup\$ – baby-rabbit Sep 26 '12 at 0:38
  • 1
    \$\begingroup\$ 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? \$\endgroup\$ – NRGdallas Sep 26 '12 at 15:51
  • 11
    \$\begingroup\$ @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). \$\endgroup\$ – mellamokb Sep 26 '12 at 22:02
  • 2
    \$\begingroup\$ sum(factorial(18)/factorial(x)/factorial(y)/factorial(z) for x in range(25) for y in range(25) for z in range(25) if 3*x+4*y+5*z == 72 and x+y+z == 18) gives 44152809L \$\endgroup\$ – Sanjeev Murty Jan 5 '14 at 7:05

47 Answers 47

1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

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 :-)

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

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
\$\endgroup\$
1
\$\begingroup\$

VBA - 117

VBA never wins at golf. :-)

Sub a()
Do Until d=72
d=0
c=""
For b=1 To 18
e=Int(3*Rnd()+3)
c=c &" " &e
d=d+e
Next
Loop
MsgBox c
End Sub
\$\endgroup\$
1
\$\begingroup\$

PowerShell - 59

while(($x|measure -s).sum-ne72){$x=1..18|%{3..5|random}};$x
\$\endgroup\$
1
\$\begingroup\$

Perl, 59

@a=map{3+rand 3|0}1..18 while 72!=eval join'+',@a;print"@a"

Not a winner by any means and could probably be improved still...

Array sum method stolen from perlmonks.

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

Mathematica, 45 chars

NestWhile[{3, 5}~RandomInteger~18 &, {}, Tr@# != 72 &]
\$\endgroup\$
1
\$\begingroup\$

Perl 6 (42 bytes)

my@a=roll 18,3..5 while 72!= [+] @a;say @a

Probably too long to be acceptable, but at least the solution does exist. roll rolls the dice containing 3, 4, and 5. This generates numbers until the sum is equal to 72. I believe it can generate any course with equal probability (in theory), but considering pseudo-random number generators, it probably doesn't.

Sample output:

~ $ perl6 -e 'my@a=roll 18,3..5 while 72!= [+] @a;say @a'
3 4 3 3 4 5 4 3 4 4 3 4 5 4 5 5 4 5
\$\endgroup\$
1
\$\begingroup\$

TI-BASIC, 13 bytes

3+3fPart(randIntNoRep(0,17)/3

Outputs list of 18 integers. Meets all specs and has equal probability for each case.

\$\endgroup\$
  • \$\begingroup\$ And yes, total is always 72 thanks to our handy 2-byte randIntNoRep( \$\endgroup\$ – Timtech Dec 26 '14 at 1:19
  • \$\begingroup\$ This only produces lists with exactly 6 3's, 6 4's, and 6 5's. \$\endgroup\$ – lirtosiast May 16 '15 at 20:00
  • \$\begingroup\$ "Each hole must have a length of 3, 4 or 5" \$\endgroup\$ – Timtech May 19 '15 at 12:20
  • 1
    \$\begingroup\$ "Your program must be able to produce every possible hole configuration"-- so for example, 9 3s and 9 5s would be valid. \$\endgroup\$ – lirtosiast May 19 '15 at 14:03
1
\$\begingroup\$

Pyth, 18 bytes

#Jm+3O3U18IqsJ72JB

How it works:

#                    infinite loop
       U18           generate the list [0, 1, ..., 17]
  m    U18           map every value of this list to
   +3O3              a random number between 3 and 5
 Jm+3O3U18           and assign the resulting list to J
          I          if
           qsJ72     the sum of J == 72
                J    print J
                 B   and exit the loop
\$\endgroup\$
1
\$\begingroup\$

CJam, 31

[Language was created after the question was posted]

Shamelessly long for CJam. It's basically a brute-force solution that keeps trying random configurations until it finds one that adds to 72.

L{;L{3mr3+_U+:U;a+}I*U72=:U!}g`
\$\endgroup\$
1
\$\begingroup\$

Java: 389 bytes

Run by calling the b() function.

import java.util.*;public class a{Random b=new Random();int[]b(){int[]c=new int[18];int d=0;for(int i=0;i<c.length;i++){int e=g(c.length-i,d);int f=h(c.length-i,d);c[i]=i(e,f);d=d+c[i];}
return c;}
int i(int j,int k){return b.nextInt((k-j)+1)+j;}
int g(int l,int m){int n=(l-1)*5;int o=72-m;int p=o-n;return p<3?3:p;}
int h(int q,int r){int s=(q-1)*3;int t=72-r;int u=t-s;return u>5?5:u;}}
\$\endgroup\$
  • \$\begingroup\$ whoever downvoted can explain? \$\endgroup\$ – PoweredByRice Dec 28 '14 at 15:59
1
\$\begingroup\$

Javascript, 148 143 bytes

t=[];d=0;while(d<18){q=t.reduce(function(a,b){return a+b},z=0);while(!z||q+z+13-d*5<0||q+z-d*3>21)z=3+3*Math.random()|0;t.push(z);d++}alert(t)
\$\endgroup\$
1
\$\begingroup\$

PARI/GP, 85 bytes

vecextract(Vec(partitions(72,[3,5],[18,18])[random(10)+1]),numtoperm(18,random(18!)))

This generates a random partition of 72 with 18 components ranging from 3 to 5. The probabilities are not uniform, from 1/10 for the all-4 vector to 1/171531360 for [3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5] and its permutations.

\$\endgroup\$
0
\$\begingroup\$

Octave, 37 bytes

while sum(x=2+randi(3,1,18))-72;end;x

It seems straight forward, (and I guess it is), but there are a few nifty tricks in here. It's 16 bytes shorter than the MATLAB answer, and I think it's hard to golf any further.

In Octave, you can initialize a variable inside a function call, or inside the while statement as done here. So, by doing sum(x=2+randi(3,1,18)) I manage to continuously shuffle a vector of 18 elements with values [3,4,5] until the sum is 72. Instead of checking if this equals 72, we can subtract 72, and check if that's a truthy or a falsey value. Any non-zero values are considered truthy, so it will only stop when the sum is 72. In the end, the loop stops and the vector is printed.

\$\endgroup\$
0
\$\begingroup\$

Seriously, 32 bytes (noncompeting)

35k9Ju;)@nktd9-τ4nktW;lJ`\`np@WX

This language post-dates this challenge. Posted to prove the need for a shuffle command and perhaps a cons command. This uses the same solution as CJam roughly:

35k                                 Push [5,3]
   9Ju                              Push a random number n from 1 to 9
      ;)                            Save a copy of it for later use.
        @n                          Make n copies of [5,3]
          (9-τ                      Transform n -> 2*(9-n)
              4n                    Push that many 4's
                kt                  Compile all numbers into a list.
                  W         W       Until the list is empty:
                   ;lJ`\`np@        Pop a random element from it.
                             X      Discard empty list.
\$\endgroup\$
0
\$\begingroup\$

AHK, 76 bytes

Loop{
s=
t=0
Loop,18{
Random,r,3,5
s:=r " "s
t+=r
}
If t=72
Break
}
Send,%s%

It's of the style to just loop forever until it happens to generate a list that totals 72 strokes.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.