Czy umiesz grać w golfa?

53

Musisz wygenerować losowe 18-dołkowe pole golfowe.

Przykładowe dane wyjściowe:

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

Zasady:

  • Twój program musi wypisać listę długości otworów dla dokładnie 18 otworów
  • Każdy otwór musi mieć długość 3, 4 lub 5
  • Długości otworów muszą sumować się do 72 dla całego kursu
  • Twój program musi być w stanie wygenerować każdą możliwą konfigurację otworu z pewnym prawdopodobieństwem różnym od zera (prawdopodobieństwo każdej konfiguracji nie musi być równe, ale w takim przypadku możesz śmiało domagać się dodatkowego uznania)
mikera
źródło
3
Proszę potwierdzić, 44152809 rozwiązań?
baby-królik
1
Ja też jestem ciekawy dokładnej liczby rozwiązań, jednak uważam, że powinno to być ponad 44 miliony ... (Nie jestem matematykiem: | 1 (5) / 1 (3) = 306 możliwości (17 * 18) | 2 (5) / 2 (3) = 69360 możliwe (17 * 17 * 16 * 15) | 3 (5) / 3 (3) = 11182080 możliwe (16 * 16 * 16 * 15 * 14 * 13) | robi to wygląda dobrze?
NRGdallas
11
@ baby-rabbit: Potrafię potwierdzić 44 152 809 rozwiązań za pomocą wyliczenia siły. Ponadto, może być bezpośrednio obliczony w ten sposób: skoro średnia jest dokładnie 4, a jedyne możliwości są 3, 4albo 5, zajęcia możliwe rozwiązania są { 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}. Można to obliczyć za pomocą 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. Oznacza to, że w przybliżeniu 11.4%wszystkie możliwe kombinacje są poprawnymi rozwiązaniami (44,152,809 / 3^18).
mellamokb
2
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)daje44152809L
Sanjeev Murty

Odpowiedzi:

29

k ( 18 17 16 znaków)

Wracając do pierwotnego podejścia, uznanie dla CS za ulepszenie.

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

Inne podejście (17 znaków), ta sama metoda co rozwiązanie J, H / T do CS

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

Stara wersja:

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

Niewrażliwy na przepełnienie stosu i działa w ustalonej ilości miejsca.

skeevey
źródło
Co to jest H / T do CS?
Gareth
Ten program pomógł mi odkryć błąd w moim tłumaczu K. Dziękuję! Nie zdawałem sobie wcześniej sprawy, że nilady można zastosować do pojedynczego argumentu (który ignorują).
JohnE
17

K, 28

{$[72=+/s:18?3 4 5;s;.z.s`]}
tartin
źródło
15

J, 20 18 17 znaków

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

Działa to w taki sam sposób, jak poprzednia odpowiedź, z tym wyjątkiem, że 9 losowych cyfr ma wartość 0 lub 1 i są negowane przed dodaniem. Oznacza to, że jest ich tyle, -1ile jest 1. Dodanie 4 daje mi listę 3S, 4S i 5S, które sumują się do 72 za każdym razem.

Poprzednia odpowiedź:

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

Generuje pierwsze 9 dołków losowo ?9#3, a następnie kopiuje i odwraca je (,2-])(zamienia 3 w 5, a 5 w 3), aby wygenerować końcową 9. To gwarantuje, że suma wyniesie 72 (ponieważ każde 3 będzie miało pasujące 5 średnia suma na dołek wyniesie 4 i 4x18 = 72). Następnie losowo tasuje wynik, ({~?~@#)aby upewnić się, że każda kombinacja jest możliwa.

Gareth
źródło
właściwie nie wygenerujesz {3,5,4,4,4 ...}, lepiej jest tasować cały wynik
maniak zapadkowy
@rachetfreak Dobra uwaga. Będę teraz edytować.
Gareth,
13

16-bitowy kod maszynowy x86 w systemie MS-DOS - 45 bajtów

Hexdump:

0E5F576A12595188ECE44088C3E44130D8240374F400C4AAE2EF595E80FC2475DFAC0432CD29B020CD29E2F5C3

Kod binarny Base64:

Dl9XahJZUYjs5ECIw+RBMNgkA3T0AMSq4u9ZXoD8JHXfrAQyzSmwIM0p4vXD

Rzeczywisty kod źródłowy z kilkoma komentarzami:

 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.

Skompiluj nasm 18h.asm -o 18h.comi uruchom pod MS-DOS (lub Dosbox) lub NTVDM z 32-bitowej wersji Windows.

Przykładowe dane wyjściowe:

4 5 4 5 4 5 3 4 3 4 3 4 4 5 4 3 5 3
Jonas Gulle
źródło
3
love asembler ...
woliveirajr
13

Mathematica 71 68 66 60

Z 6 znakami zapisanymi według sugestii Tally.

RandomSample@RandomChoice@IntegerPartitions[72, {18}, {3, 4, 5}]

{5, 4, 3, 3, 5, 3, 5, 5, 3, 3, 4, 5, 3, 5, 4, 4, 5, 3}

Wszystkie możliwe wyniki są możliwe, ale nie są równie prawdopodobne.


Analiza

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

produkuje wszystkie 10 możliwych partycji (kombinacje, nie permutacje) 72 na 18 elementów składających się z 3, 4 i 5.

partycje


RandomChoice wybiera jeden z nich.

RandomSample zwraca permutację tego wyboru.

DavidC
źródło
Hehe, właśnie miałem opublikować prawie taką samą odpowiedź, używając tylko RandomChoice zamiast RandomInteger. Myślę, że możesz w ten sposób ogolić 4 kolejne postacie.
Tally
Tally, dzięki. Twoja sugestia była pomocna.
DavidC
8

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

Algorytm jest podobny do @ sgrieve's.

flodel
źródło
Taki sam problem, jak powyżej @ grieve - nic nie stoi na przeszkodzie, aby przejść w 18 dołkach.
gt6989b,
3
To nie jest problem, przykładowe polecenie w tym przypadku zawsze generuje 18 wartości.
sgrieve
8

GolfScript (26 znaków)

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

Istnieją pewne oczywiste podobieństwa z rozwiązaniem Ilmari, ale także pewne oczywiste różnice. W szczególności wykorzystuję fakt, że średnia wartość par wynosi 4.

Peter Taylor
źródło
Cholera, ale z pewnością jest to sprytna sztuczka z warunkiem pętli. Wymyśliłem {;0{3.rand+.@+}18*])72-}dosiebie, ale nie mogłem wymyślić, jak to zrobić dalej. +1.
Ilmari Karonen,
7

Python 77

Kod

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

Wynik

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

Import naprawdę zabija to rozwiązanie. Używa numpy do generowania 18 liczb między 3 a 5 i ciągle generuje listy, dopóki suma listy nie wyniesie 72.

sgrieve
źródło
Co uniemożliwia programowi osiągnięcie dobrze 72 pozycji przed wygenerowaniem 18 dołków? Co zapobiega pomijaniu 72?
DavidC,
3
Kod zawsze generuje 18 dołków, a następnie sprawdza, czy suma wynosi 72. Na przykład, jeśli suma po 16 dołkach wyniosła 72, nadal generowałby kolejne 2 dołki, przesuwając sumę powyżej 72 i nieudany test.
sgrieve
7

GolfScript, 27 znaków

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

Używa tej samej metody próbkowania odrzucenia, co rozwiązanie Pythona w sgrieve. Zatem każde prawidłowe wyjście jest równie prawdopodobne.

Ilmari Karonen
źródło
7

Q (25 znaków)

Oryginał (27)

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

Próbka wyjściowa

4 4 3 3 4 5 4 3 4 5 5 3 5 5 5 4 3 3

Nieznacznie krótszy (25)

{72<>sum x}{x:18?3 4 5}/0
sinedcm
źródło
7

JavaScript, 66 64 61 znaków

Mocno zainspirowany TwoScoopsofPig (PHP) i 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
grawitacja
źródło
2
s!=72można s-72uratować jeden znak. Ostatni środkowy dwukropek ;anie jest też potrzebny na kolejny znak.
Joe Tuskan,
nigdy for(i=x;i;i--)przedtem nie widziałem , żeby oszczędził 2 znaki for(i=0;i<x;i++), dzięki stary!
Agregat matematyczny
7

Python 2, 70 bajtów

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

Oto kolejny, podobny do rozwiązania sgrieve:

Python 2, 73 bajty + równe prawdopodobieństwo

from random import*
a=[]
while sum(a)-72:a=sample([3,4,5]*18,18)
print a
daniero
źródło
5

JavaScript, 116 99 65 bajtów

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
Joe Tuskan
źródło
1
Gdy uruchamiam to w Chrome 21, otrzymuję i is not defined.
mellamokb
5

Python, 128 120 116 znaków

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

import instrukcje wciąż są zabójcami długości (23 znaków tylko w celu zaimportowania 2 funkcji w przestrzeni nazw)

Mam nadzieję, że nie będziesz potrzebować wyniku w najbliższej przyszłości, ponieważ ten kod najpierw ocenia wszystkie możliwe rozwiązania, zanim wybierzesz jedno losowo. być może najwolniejsze rozwiązanie tego problemu.

Zgłaszam dodatkowe podziękowania za równe prawdopodobieństwo każdej konfiguracji ...

Adrien Plisson
źródło
4
import random,itertools
grawity
masz rację, to trochę skraca.
Adrien Plisson,
Inne wskazówki: import random as r,itertools as inastępnie użyj ri izamiast randomi itertools. Użyj 18*[0]zamiast range(18)i [3,4,5,6]zamiast range(3,6):)
Alex L
Używam Pythona 3: rozumienie listy jest generatorem i nie ma długości, co zabrania jego używania z choice()funkcją. to również powoduje, że ten kod jest tak wolny ...
Adrien Plisson
1
ooops, przepraszam, pomyliłem się ze zrozumieniem listy i wyrażeniem generatora (generalnie unikam rozumienia listy na korzyść wyrażenia generatora ze względu na lepszą wydajność iteratora). więc nawet w python3 nadal mogę usunąć niektóre znaki ... @Alex zrobił to dobrze.
Adrien Plisson,
4

PHP - 77 znaków

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

Podobnie jak w przypadku rozwiązania sgrieve, buduje listę 18 dołków, sprawdza całkowitą wartość par i drukuje ją lub odrzuca i próbuje ponownie. Co dziwne, nasze dwa rozwiązania są tej samej długości.

Dosyć denerwujące jest to, że PHP nie oferuje funkcji tablicowych o zwięzłej nazwie. Zabijają mnie Array_sum i print_r. Sugestie mile widziane.

TwoScoopsofPig
źródło
1
Nawiasy klamrowe nie są tutaj potrzebne, a suma może być +=. <?while($s!=72)for($s=$i=0;18>$i;$s+=$a[++$i]=rand(3,5));print_r($a);
grawity
Jest to przydatne - nigdy nie myślałem o umieszczeniu logiki w wywołaniu pętli for (i czuję się trochę głupio, że nie zwiększyłem licznika sumy).
TwoScoopsofPig
Dzięki - ale tak naprawdę nie miałem na myśli tego, że „nawiasy klamrowe nie są potrzebne”; mogłeś je również usunąć w oryginalnym kodzie:while(array_sum($a)!=72)for($i=0;18>$i;)$a[++$i]=rand(3,5);
grawity
No cóż, mam do czynienia z bardziej rygorystycznym php.ini niż tym, ponieważ gram w golfa w pracy; nie narzeka bez końca na brakujące / niedopasowane nawiasy klamrowe. Normalnie bym to zrobił.
TwoScoopsofPig
To dziwne; 5.4.7 z E_ALL | E_STRICT nigdy nie narzeka na brakujące dane {}(ponieważ składnia PHP wyraźnie na to pozwala).
grawity
4

Ruby 1.9 (62 znaki)

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

Szyny (55 znaków)

W $ rails cREPL (w dowolnym folderze Rails):

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

Uwaga: Działa z Ruby 1.8, jeśli używasz shuffle[0]zamiast sample.

koder js
źródło
2
Czy potrzebujesz do tego czasu odstępu?
Kaz.
@Kaz Masz rację, to nie jest potrzebne. :) Teraz 62 znaki.
js-coder
1
Możesz użyć, (1..18).map{rand(3)+3}aby uzyskać losową tablicę;)
epidemia
4

Lisp ( 78 69 znaków)

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

Jest raczej podobny do rozwiązania Pythona w sgrieve.

Zacznij od c jako NIL, sprawdź sumę 72, do„funkcja inkrementacji” dla c generuje listę 18 liczb od 3 do 5, sprawdź ponownie 72, spień, spłucz, powtórz.

Oglądanie doi loopfajna gra w golfa jest odświeżające .

Wintermute
źródło
3

C (123 znaki) - wysiłek na rzecz wydajności

Przeciągnij przez wc, a wygeneruje wszystkie 44152809 rozwiązania w ciągu 10 sekund ...

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);}

No cóż - nie przeczytałem poprawnie pytania - ale biorąc pod uwagę, że generujemy wszystkie rozwiązania, wybranie losowego z jednakowym prawdopodobieństwem jest ćwiczeniem skryptowym: P

króliczek
źródło
3

Clojure - 55

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

Całkiem fajna sztuczka .... wykorzystuje matematyczną strukturę problemu, że musi być dokładnie tyle samo 3 dołków, co 5 dołków.

mikera
źródło
3

Python 83

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

Jak rozwiązanie sgrieve, ale bez numpy

Gra w golfa Adrien Plisson: 120-> 108 znaków

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

Wyjście :

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

Alex L.
źródło
Ładne podejście, ale możesz zaoszczędzić 4 bajty, pisząc randi([3,5],1,18)zamiast3+floor(rand(1,18)*3)
brainkz
3

Java (61 znaków)

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

Przykładowe dane wyjściowe:

5 4 3 4 5 3 4 4 3 5 4 4 4 4 3 4 4 5
Kwazar
źródło
Nie jestem ekspertem od Java, ale czy nie powinna istnieć deklaracja s i ja i jakieś wywołanie do System # println (..)?
hiergiltdiestfu
To tylko fragment kodu, a nie program. I faktycznie wygląda bardzo podobnie do wersji C @JoeIbanez.
Franz D.
2

C (94 znaki)

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]);

s=0Na linii 1, nie może być wymagane, bo jakie są szanse niezainicjowany int będzie równa 72? Po prostu nie lubię odczytywać niezainicjowanych wartości w prostej C. Ponadto prawdopodobnie wymaga to uruchomienia rand()funkcji.

wynik

3 3 3 4 5 5 3 3 4 5 5 4 3 4 5 5 5 3 
Joe Ibanez
źródło
Więc w zasadzie będziesz zapętlał losowe ciągi 18 liczb w zakresie od 3 do 5, aż jeden z nich równa się 72? Dobra wydajność nie jest wymagana.
KeithS,
5
@KeithS Aby być uczciwym, robią to większość odpowiedzi na to pytanie.
Gareth,
2

Skrypt powłoki Bash (65 znaków)

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

( shuf pochodzi z pakietu coreutils GNU. Również dzięki Gareth.)

Proszę wstać
źródło
2

C # (143 spacje):

()=>{
  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);
}
KeithS
źródło
new Guid()tworzy pusty GUID. Aby faktycznie wygenerować unikalny identyfikator GUID, musisz wywołać metodę statyczną Guid.NewGuid.
Rotsor
I masz dwa błędy jeden po drugim (że tak powiem): porównania powinny być i <n i i> = 18-n, a nie na odwrót. I możesz zmniejszyć rozmiar, używając stałej 3 zamiast x-1 i 5 zamiast x + 1. A potem możesz zastąpić Enumerable.Repeat przez Enumerable.Range.
Mormegil
Edytowane; wciąż 143 znaki
KeithS
Nie ma Math.Random, to jest System.Random.
CodesInChaos
Kolejne podejście do C # (143 znaki):var r=new Random();for(;;){var e=Enumerable.Range(1,18).Select(i=>r.Next(3,6)).ToList();if(e.Sum()==72){e.ForEach(i=>Console.Write(i));break;}}
thepirat000
2

Haskell, 104 102 98 znaków.

import System.Random
q l|sum l==72=print l|1>0=main
main=mapM(\_->randomRIO(3::Int,5))[1..18]>>=q
Rotsor
źródło
[1..n]>>[r]jest nieco krótszy niż replicate n$r.
przestał się obracać w lewo o
Zmieniono również sequencena mapM.
Rotsor
2

Perl, 74

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

Alternatywne rozwiązanie:

@q=((3,5)x($a=int rand 9),(4,4)x(9-$a));%t=map{(rand,$_)}(0..17);print"@q[@t{sort keys%t}]"
o_o
źródło
2

TXR (99 znaków)

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

To wyrażenie generuje nieskończoną leniwą listę liczb losowych od 3 do 5:

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

Reszta logiki to prosta pętla, która sprawdza, czy pierwszych 18 elementów tej listy sumuje się do 72. Jeśli nie, usuwa element i próbuje ponownie. forPętla zawiera ukryte blok nazwie nilwięc (return ...)mogą być stosowane do zakończenia pętli i wartość.

Zauważ, że długość 99 znaków zawiera końcowy znak nowej linii, który jest wymagany.

Kaz
źródło
Wstawiłem zatwierdzenie, które pozwala na zastąpienie (t) przez (). :)
Kaz.
2

APL 12

4+{⍵,-⍵}?9⍴2

Zauważ, że mam indeks pochodzenia ustawiony na 0, co oznacza, że ​​tablice zaczynają się od 0. Możesz ustawić to za pomocą ⎕IO←0.

Zaq
źródło
Pytanie dotyczy programu, który może wygenerować każdą możliwą konfigurację. Twoi mogą produkować te symetryczne. Nie możesz wyprodukować na przykład 555455555333333343, przynajmniej tak mi się wydaje.
Moris Zucca
2

R, 42 bajty

a=0;while(sum(a)-72)a=sample(3:5,18,r=T);a

sample, domyślnie rysuje równomiernie wśród możliwych wartości (tutaj 3 4 5). r=Toznacza replace=TRUEi pozwala na próbkę z wymianą.

plannapus
źródło
2

CJam, 17 14 bajtów

CJam jest nowszy od tego wyzwania, ale i tak nie jest to najkrótsza odpowiedź, więc to naprawdę nie ma znaczenia.

Z5]Amr*I4e]mrp

Sprawdź to tutaj.

Aby utrzymać łącznie 72, każdy 3musi być sparowany z 5. Oto, jak to działa:

Z5]            e# Push [3 5].
   Amr         e# Get a random number between 0 and 9.
      *        e# Repeat the [3 5] array that many times.
       I4e]    e# Pad the array to size 18 with 4s.
           mr  e# Shuffle the array.
             p e# Print it.
Martin Ender
źródło