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)

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.


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


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.


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

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.


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.


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.


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.


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.


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

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

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

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

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 ...


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.


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.


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 .


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


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.


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


Ł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

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 

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


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

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

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}]"

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.


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.


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ą.


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.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.