Можна гольф для гольфу?


53

Вам потрібно створити випадкове поле для гольфу на 18 лунок.

Приклад виводу:

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

Правила:

  • Ваша програма повинна вивести список довжин отворів рівно на 18 отворів
  • Кожен отвір повинен мати довжину 3, 4 або 5
  • Довжина отворів повинна складати до 72 за весь курс
  • Ваша програма повинна бути здатна виробляти всі можливі конфігурації отворів з деякою ненульовою ймовірністю (ймовірності кожної конфігурації не повинні бути рівними, але сміливо вимагайте додаткових кудо, якщо це так)

3
Підтвердьте, 44152809 рішення?
немовля-кролик

1
Мені теж цікаво точна кількість рішень, проте я думаю, що це повинно бути більше 44 мільйонів ... (Я, однак, не математик, проте: | 1 (5) / 1 (3) = 306 можливостей (17 * 18) | 2 (5) / 2 (3) = 69360 poss (17 * 17 * 16 * 15) | 3 (5) / 3 (3) = 11182080 poss (16 * 16 * 16 * 15 * 14 * 13) | що виглядає правильно?
NRGdallas

11
@ немовля-кролик: я можу підтвердити 44152809 рішення шляхом перерахування грубої сили. Крім того , він може бути безпосередньо розраховується наступним чином: так як середній точно 4, і єдині можливості 3, 4або 5, можливо , класи рішень є { 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}. Це можна обчислити по 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. Це означає, що приблизно 11.4%з усіх можливих комбінацій є допустимими рішеннями (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)дає44152809L
Саньєєв Мурти

Відповіді:


29

k ( 18 17 16 символів)

Повернувшись до оригінального підходу, кредитуйте CS на покращення.

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

Інший підхід (17 символів), той самий метод, що і J-рішення, H / T до CS

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

Стара версія:

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

Не сприйнятливий до переповнення стека та працює у фіксованій кількості простору.


Що H / T до CS?
Гарет


Ця програма допомогла мені виявити помилку в моєму інтерпретаторі K - дякую! Раніше я не розумів, що nilads можуть бути застосовані до одного аргументу (який вони ігнорують).
JohnE


15

J, 20 18 17 символів

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

Це працює так само, як і в попередній відповіді, за винятком того, що 9 випадкових цифр або 0, або 1 і заперечуються перед додаванням. Це означає, що існує стільки -1s, скільки є 1s. Додавання 4 дає мені список 3s, 4s та 5s, що додають до 72 кожного разу.

Попередня відповідь:

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

Створює перші 9 отворів випадковим чином ?9#3, потім копіює та інвертує їх (,2-])(перетворює 3 у 5 та 5 на 3), щоб генерувати остаточне 9. Це гарантує, що загальна сума буде 72 (оскільки кожен 3 матиме відповідність 5 середня загальна сума на один отвір складе 4, а 4х18 = 72). Потім він випадковим чином переміщує результат, ({~?~@#)щоб переконатися, що можлива кожна комбінація.


насправді ви не будете генерувати {3,5,4,4,4 ...} вам краще перетасувати весь результат
храповий вирод

@rachetfreak Добре. Я зараз редагую.
Гарет

13

16-розрядний машинний код x86 під MS-DOS - 45 байт

Hexdump:

0E5F576A12595188ECE44088C3E44130D8240374F400C4AAE2EF595E80FC2475DFAC0432CD29B020CD29E2F5C3

Кодований двійковий код Base64:

Dl9XahJZUYjs5ECIw+RBMNgkA3T0AMSq4u9ZXoD8JHXfrAQyzSmwIM0p4vXD

Фактичний вихідний код із коментарями:

 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.

Компілюйте nasm 18h.asm -o 18h.comта працюйте під MS-DOS (або Dosbox) або NTVDM з 32-розрядної версії Windows.

Вибірка зразка:

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

3
любов асемблер ...
woliveirajr

13

Математика 71 68 66 60

6 пропозицій збережено за пропозицією Таллі.

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}

Всі можливі результати можливі, але вони не однаково вірогідні.


Аналіз

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

створює всі 10 можливих розділів (комбінацій, а не перестановок) з 72 на 18 елементів, що складаються з 3-х, 4-х та 5-х.

перегородки


RandomChoice вибирає один із них.

RandomSample повертає перестановку за цим вибором.


Так, я збирався опублікувати майже таку ж відповідь, лише використовуючи RandomChoice замість RandomInteger. Я думаю, що ви можете поголити ще чотирьох персонажів.
Tally

Талі, спасибі. Ваша пропозиція була корисною.
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

Алгоритм схожий на @ sgrieve's.


Та сама проблема, що і в @sgrieve, вище - ніщо не заважає їй перейти через 18 лунок.
gt6989b

3
Це не проблема, команда sample в цьому випадку завжди генерує 18 значень.
sgrieve

8

GolfScript (26 символів)

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

Є кілька очевидних подібностей з рішенням Ільмарі, але також і деякі очевидні відмінності. Зокрема, я використовую той факт, що середній показник - 4.


Чорт, але це впевнений розумний трюк із умовою петлі. Я придумав {;0{3.rand+.@+}18*])72-}doсебе, але не міг зрозуміти, як зробити це звідти коротше. +1.
Ільмарі Каронен

7

Пітон 77

Код

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

Вихід

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

Імпорт дійсно вбиває це рішення. Він використовує numpy, щоб генерувати 18 чисел між 3 і 5 і зберігає генерувати списки, поки сума списку не дорівнює 72.


Що заважає програмі досягти 72 свердловини до створення 18 лунок? Що заважає пропустити 72?
DavidC

3
Код завжди генерує 18 отворів, потім перевірте, чи сума дорівнює 72. Наприклад, якщо сума після 16 отворів становила 72, вона все одно генерувала б ще дві дірки, тим самим просуваючи суму вище 72 і провалюючи тест.
sgrieve

7

GolfScript, 27 символів

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

Використовується той самий метод вибірки відхилення, що і рішення Pyghon sgrieve. Таким чином, кожен дійсний результат насправді є однаково вірогідним.


7

Q (25 символів)

Оригінал (27)

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

Вибірка зразка

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

Трохи коротше (25)

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

7

JavaScript, 66 64 61 символів

Дуже натхненний TwoScoopsofPig (PHP) та Джо Тускан (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!=72можна s-72зберегти одну чару. І остання півколона ;aне потрібна ні для чергових знаків.
Джо Тускан

я ніколи не бачив, for(i=x;i;i--)перш ніж це економить 2 години від for(i=0;i<x;i++), дякую людино!
Math chiller

7

Python 2, 70 байт

from random import*
print sample(([3,5]*randint(0,9)+[4]*99)[:18],18)
редагувати:

Ось ще одна, схожа на рішення sgrieve:

Python 2, 73 байти + однакова ймовірність

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

5

JavaScript, 116 99 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

1
Коли я запускаю це в Chrome 21, я отримую i is not defined.
mellamokb

5

Пітон, 128 120 116 символів

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

import заяви все ще вбивці довжини (23 символи лише для імпортування 2 функції в область імен)

Я сподіваюсь, що результат вам не знадобиться найближчим часом, оскільки цей код спочатку оцінює всі можливі рішення, перш ніж вибір навмання. можливо, найповільніше вирішення цієї проблеми.

я вимагаю зайвих кудосів для однакової ймовірності кожної конфігурації ...


4
import random,itertools
grawity

ви маєте рацію, що трохи скорочуєте речі.
Адрієн Пліссон

Інші поради: import random as r,itertools as iтоді використовуйте rі iзамість randomі itertools. Використовуйте 18*[0]замість range(18), а [3,4,5,6]замість range(3,6):)
Alex L

я використовую python 3: розуміння списку є генератором і не має довжини, що забороняє його використання з choice()функцією. це також робить цей код таким повільним ...
Адрієн Пліссон,

1
ooops, вибачте, я зіпсував розуміння списку та вираження генератора (я взагалі уникаю розуміння списку на користь вираження генератора через кращі показники ітератора). так що навіть у python3 я все-таки можу видалити деякі символи ... @Alex зробив це правильно.
Адрієн Пліссон

4

PHP - 77 символів

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

Так само, як рішення sgrieve, це створює список з 18 дірок, перевіряє загальну номінальну кількість, або друкує його, або відкидає його і повторює спробу. Як не дивно, але наші два рішення однакової довжини.

Швидше прикро, PHP не пропонує функції масиву з якоюсь стислістю імен. Array_sum і print_r вбивають мене. Пропозиції вітаються.


1
Кучеряві брекети тут не потрібні, і сума може бути +=. <?while($s!=72)for($s=$i=0;18>$i;$s+=$a[++$i]=rand(3,5));print_r($a);
grawity

Це корисно - я ніколи не думав вкладати логіку в цикл для виклику циклу (і я відчував себе німим немов за те, щоб не збільшити лічильник на суму).
TwoScoopsofPig

Дякую - але це насправді не те, що я мав на увазі під "фігурними брекетами, не потрібними"; ви могли також видалити їх у вихідному коді:while(array_sum($a)!=72)for($i=0;18>$i;)$a[++$i]=rand(3,5);
grawity

Ну хіба що я біжу проти більш жорсткого php.ini, ніж це, тому що я займаюся гольфом на роботі; він не скаржиться на те, що брекети відсутні / невідповідні. Зазвичай я мав би.
TwoScoopsofPig

Це дивно; 5.4.7 за допомогою E_ALL | E_STRICT ніколи не скаржиться на відсутність {}(оскільки синтаксис PHP явно дозволяє це).
grawity

4

Рубін 1,9 (62 символи)

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

Рейки (55 символів)

У $ rails cREPL (у будь-якій папці Rails):

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

Примітка. Це працює з Ruby 1.8, якщо ви використовуєте shuffle[0]замість цього sample.


2
Вам потрібен пробіл навколо?
Каз

@Kaz Ви маєте рацію, це не потрібно. :) Зараз 62 символи.
js-coder

1
Ви можете використовувати (1..18).map{rand(3)+3}для отримання випадкового масиву;)
епідемія

4

Лісп ( 78 69 символів)

(do ((c () (mapcar (лямбда (x) (+ 3 (випадковий 3))) (make-list 18)))) ((= (застосувати '+ c) 72) c))

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

Він досить схожий на рішення Pyghon sgrieve.

Почніть з c як NIL, перевірте суму 72, do"функція приросту" для c генерує список з 18 чисел між 3 і 5, ще раз перевірте на 72, мийте, промийте, повторіть.

Це освіжаюче бачити doі loopгарно грати в гольф разом.


3

C (123 знаків) - зусилля щодо ефективності

Трубопровід через туалет, і він генерує всі 44152809 рішення протягом 10 секунд ...

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

О, добре - не прочитав питання належним чином - але, враховуючи, що ми генеруємо всі рішення, то вибір випадкового з однаковою ймовірністю - це сценарій вправ: P


3

Clojure - 55

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

Досить цікавий трюк .... експлуатує математичну структуру проблеми, що повинно бути рівно стільки 3 отворів, скільки 5 норів.


3

Пітон 83

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

Як рішення sgrieve, але без нумету

Рішення для гольфінгу Адрієна Пліссона: 120-> 108 символів

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

Вихід :

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


Гарний підхід, але ви можете зберегти 4 байти, набравши randi([3,5],1,18)замість3+floor(rand(1,18)*3)
brainkz

3

Java (61 символів)

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

Вибірка зразка:

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

Я не експерт по Java, але чи не повинно бути декларації s і i, а також якийсь виклик до System # println (..)?
hiergiltdiestfu

Це просто фрагмент коду, а не програма. І це насправді дуже схоже на версію @ C @JoeIbanez.
Франц Д.

2

C (94 знаків)

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=0На лінії 1 може не знадобитися, оскільки які шанси неініціалізованих ІНТ буде дорівнює 72? Мені просто не подобається читати неініціалізовані значення прямо в C. Також це, мабуть, вимагає висівання rand()функції.

вихід

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

Так що в основному ви збираєтеся прокручувати випадкові рядки з 18 чисел від 3 до 5, поки один не стане рівним 72? Ефективність хорошої речі не є необхідним.
KeithS

5
@KeithS Чесно кажучи, саме цим і займається більшість відповідей на це питання.
Гарет

2

Сценарій Bash shell (65 символів)

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

( shuf походить від пакета coreutils GNU. Також, дякую Гарет.)


2

C # (143 пробіли):

()=>{
  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()створює порожній GUID. Щоб створити унікальний GUID, вам потрібно викликати статичний метод Guid.NewGuid.
Ротсор

І у вас є дві помилки один за одним (так би мовити): порівняння повинні бути i <n та i> = 18-n, а не навпаки. І ви можете зменшити розмір, використовуючи константу 3 замість x-1 і 5 замість x + 1. І тоді ви можете замінити Enumerable.Repeat на Enumerable.Range.
Мормегіл

Відредаговано; ще 143 символи
KeithS

Немає Math.Random, це System.Random.
CodesInChaos

Ще один підхід C # (143 символи):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

Перл, 74

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

Альтернативне рішення:

@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 знаків)

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

Цей вираз породжує нескінченний лінивий список випадкових чисел від 3 до 5:

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

Інша логіка - це простий цикл, який перевіряє, чи досягає перших 18 елементів цього списку до 72. Якщо ні, він спливає елемент і намагається знову. forЦикл містить неявний блок , званий nilі так (return ...)може бути використаний для завершення циклу і повернення значення.

Зауважте, що довжина 99 символів включає завершальний новий рядок, який необхідний.


Я вкладаю коміту, яка дозволяє (t) замінити на (). :)
Каз

2

12 APL

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

Зауважте, що у мене початкове значення індексу встановлено на 0, тобто масиви починаються з 0. Ви можете встановити це за допомогою ⎕IO←0.


Питання задає програму, яка може виробляти всі можливі конфігурації. Ваші можуть виробляти симетричні. Ви не можете створити, наприклад, 555455555333333343, принаймні, мені так здається.
Моріс Зукка

2

R, 42 байти

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

sample, за замовчуванням, рівномірно малює серед можливих значень (тут 3 4 5). r=Tрозшифровує replace=TRUEта дозволяє зразок із заміною.


2

CJam, 17 14 байт

CJam є новішим, ніж ця проблема, але це все одно не найкоротша відповідь, так що насправді це не має значення.

Z5]Amr*I4e]mrp

Перевірте це тут.

Щоб зберегти загальну кількість 72, кожен 3повинен бути сполучений з 5. Отже, ось як це працює:

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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.