Вы можете Гольф Гольф?

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 за весь курс
  • Ваша программа должна иметь возможность производить каждую возможную конфигурацию дырок с некоторой ненулевой вероятностью (вероятности каждой конфигурации не обязательно должны быть равными, но вы можете требовать дополнительных похвал в этом случае)
mikera
источник
3
Пожалуйста, подтвердите, 44152809 решения?
Кролик
1
Мне тоже любопытно точное количество решений, однако я думаю, что оно должно быть больше 44 миллионов ... (однако я не математик: | 1 (5) / 1 (3) = 306 возможностей (17 * 18) | 2 (5) / 2 (3) = 69360 опс (17 * 17 * 16 * 15) | 3 (5) / 3 (3) = 11182080 опс (16 * 16 * 16 * 15 * 14 * 13) | делает это выглядит правильно?
NRGdallas
11
@ baby-rabbit: я могу подтвердить 44 152 809 решений путем перебора. Кроме того , он может быть непосредственно рассчитывается следующим образом: так как средний точно 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
Sanjeev Murty

Ответы:

29

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

Не подвержен переполнению стека и работает в фиксированном объеме пространства.

skeevey
источник
Что такое H / T для CS?
Гарет
Шляпа-подсказка, en.wikipedia.org/wiki/Hat_tip#Metaphor
скивэй
Эта программа помогла мне обнаружить ошибку в моем интерпретаторе K - спасибо! Ранее я не понимал, что nilads можно применять к одному аргументу (который они игнорируют).
JohnE
15

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

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

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

Предыдущий ответ:

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

Генерирует первые 9 лунок случайным образом ?9#3, затем копирует и инвертирует их (,2-])(превращает 3 в 5 и 5 в 3), чтобы сгенерировать финальный 9. Это гарантирует, что итоговое значение будет 72 (так как каждые 3 будут иметь соответствующие 5, среднее общее количество на лунку будет 4 и 4x18 = 72). Затем он случайным образом перемешивает результат, ({~?~@#)чтобы гарантировать, что каждая комбинация возможна.

Gareth
источник
на самом деле вы не будете генерировать {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

Mathematica 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 возвращает перестановку этого выбора.

DavidC
источник
Хе-хе, я как раз собирался опубликовать почти тот же самый ответ, используя только RandomChoice вместо RandomInteger. Я думаю, что вы можете побрить еще 4 персонажа, сделав это.
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.

flodel
источник
Та же проблема, что и у @sgrieve выше - ничто не мешает ему пересечь 18 лунок.
gt6989b
3
Это не проблема, пример команды в этом случае всегда генерирует 18 значений.
'35
8

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

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

Есть некоторые очевидные сходства с решением Ильмари, но также есть и некоторые очевидные различия. В частности, я использую тот факт, что средний номинал равен 4.

Питер Тейлор
источник
Блин, но это точно умный трюк с состоянием цикла. Я придумал {;0{3.rand+.@+}18*])72-}doсам, но не мог понять, как сделать это немного короче оттуда. +1.
Илмари Каронен
7

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

sgrieve
источник
Что мешает программе достичь 72 задолго до создания 18 лунок? Что мешает ему пропустить 72?
DavidC
3
Код всегда будет генерировать 18 лунок, а затем проверить, равна ли сумма 72. Например, если сумма после 16 лунок равна 72, он все равно сгенерирует еще 2 лунки, тем самым увеличив сумму выше 72 и провалив тест.
sgrieve
7

GolfScript, 27 символов

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

Использует тот же метод выборки отклонения, что и в решении Python от 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
sinedcm
источник
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
grawity
источник
2
s!=72можно s-72сохранить один символ И последняя точка с запятой ;aне нужна ни для другого символа.
Джо Тускан
я никогда не видел for(i=x;i;i--)прежде, чем это спасает 2 символа от for(i=0;i<x;i++), спасибо человек!
Математический чиллер
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
daniero
источник
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

Python, 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
Гравитация
Вы правы, это немного укорачивает.
Адриен Плиссон,
Другие советы: 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()функцией. это также то, что делает этот код таким медленным ...
Adrien Plisson
1
Ой, простите, я испортил понимание списка и выражение генератора (я вообще избегаю понимания списка в пользу выражения генератора из-за лучшей производительности итератора). так что даже в 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 убивают меня. Предложения приветствуются.

TwoScoopsofPig
источник
1
Здесь фигурные скобки не нужны, а сумма может быть +=. <?while($s!=72)for($s=$i=0;18>$i;$s+=$a[++$i]=rand(3,5));print_r($a);
Гравитация
Это полезно - я никогда не думал вводить логику в вызов цикла for (и я чувствую себя немного глупо, если не увеличиваю счетчик для суммы).
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 явно позволяет это).
благодарность
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.

JS-верстальщик
источник
2
Вам нужны пробелы до?
Каз
@ Каз Вы правы, это не нужно. :) 62 символа сейчас.
JS-кодер
1
Вы можете использовать, (1..18).map{rand(3)+3}чтобы получить случайный массив;)
Эпидемиан
4

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

(do ((c () (mapcar (лямбда (x) (+ 3 (случайное 3))) (список составителей 18)))) ((= (применить '+ c) 72) c))

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

Это довольно похоже на Python-решение sgrieve.

Начните с c как NIL, проверьте сумму 72, do «функция приращения» для c генерирует список из 18 чисел от 3 до 5, проверьте 72 снова, вспенить, промыть, повторить.

Приятно видеть doи loopприятно играть в гольф вместе.

Wintermute
источник
3

С (123 символа) - усилие на эффективность

Пройдите через wc, и он сгенерирует все 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 парных отверстий.

mikera
источник
3

Python 83

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

Как решение Sgrieve, но без NumPy

Гольф Решение Адриена Плиссона: 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

Выход :

х = 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

Ява (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

С (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 может не потребоваться, потому что шансы, что неинициализированный int будет равен 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 поставляется из пакета GNU coreutils. Также, спасибо Гарету.)

PleaseStand
источник
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);
}
Keiths
источник
new Guid()создает пустой GUID. Для создания уникального GUID вам нужно вызвать статический метод Guid.NewGuid.
Ротсор
И у вас есть две ошибки (так сказать): сравнение должно быть i <n и i> = 18-n, а не наоборот. И вы можете уменьшить размер, используя константу 3 вместо x-1 и 5 вместо x + 1. И тогда вы можете заменить Enumerable.Repeat на Enumerable.Range.
Мормегил,
Под редакцией; все еще 143
символа
Нет 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

Haskell, 104 102 98 символов.

import System.Random
q l|sum l==72=print l|1>0=main
main=mapM(\_->randomRIO(3::Int,5))[1..18]>>=q
Rotsor
источник
[1..n]>>[r]немного короче чем replicate n$r.
перестал поворачиваться против часовой стрелки с
Также изменено sequenceна mapM.
Rotsor
2

Perl, 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 включает завершающий символ новой строки, который требуется.

Kaz
источник
Я вставил коммит, который позволяет заменить (t) на (). :)
Каз
2

APL 12

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

Обратите внимание, что у меня источник индекса установлен в 0, что означает, что массивы начинаются с 0. Вы можете установить это с помощью ⎕IO←0.

Zaq
источник
Вопрос задает программа, которая может произвести любую возможную конфигурацию. Ваши могут производить симметричные. Вы не можете произвести, например, 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и позволяет образец с заменой.

plannapus
источник
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.
Мартин Эндер
источник