Twoim zadaniem jest stworzenie programu, który przyjmuje liczbę całkowitą n > 1
i generuje rzut jednostronnej n
kostki. Te kości są jednak zgodne z zasadami eksplozji kości .
Kiedy rzucasz kością, sprawdź, jaką wartość rzuciłeś. Jeśli uzyskasz maksimum dla tego rodzaju kości (na standardowym k4, czyli 4 lub 6 na k6 itd.), Rzuć ponownie i dodaj nowy rzut do tej sumy. Każdy rzut kontynuuje dodawanie do sumy, dopóki nie rzucisz już maksymalnej liczby. Ten ostatni numer jest jednak dodawany.
Twój program powinien przyjąć jedną liczbę całkowitą n
i rzucić n
kością eksplodującą . Oto przykładowa dystrybucja pokazująca, jak powinna wyglądać n=4
. Pamiętaj, że nigdy nie powinieneś generować żadnych wielokrotnościn
, ponieważ zawsze będą wybuchać.
Możesz założyć, że rozmiar stosu dla każdej rekurencji, którą wykonujesz, jest nieskończony, a twoja funkcja losowa musi spełniać nasze standardy losowości (wbudowany generator losowy lub czas / data ). Twoja losowa funkcja powinna być również możliwie jak najbardziej jednolita, w przeciwieństwie do rozkładu geometrycznego, ponieważ mówimy o kościach.
Odpowiedzi:
Kod maszynowy x86 (dla Intel Ivy Bridge i nowszych), 17 bajtów
Powyższe bajty kodu definiują funkcję symulującą eksplodującą matrycę. Wymaga pojedynczego wejścia, przekazanego w
ESI
rejestru, wskazującego maksymalną liczbę kości. Zwraca pojedynczą wartość wECX
rejestrze, która jest wynikiem rzutów.Wewnętrznie używa
RDRAND
instrukcji aby wygenerować liczbę losową. Używa to generatora liczb losowych (RNG) wbudowanego w sprzęt procesorów Intel Ivy Bridge i późniejszych (niektóre procesory AMD również obsługują tę instrukcję).Logika funkcji jest poza tym dość prosta. Wygenerowana liczba losowa jest skalowana, aby mieściła się w pożądanym zakresie przy użyciu standardowej techniki (
(rand % dieSize) + 1
), a następnie jest sprawdzana, czy powinna spowodować wybuch. Ostateczny wynik jest przechowywany w rejestrze akumulatorów.Oto wersja z adnotacjami pokazująca mnemoniki języka asemblera:
Trochę oszukuję . Wszystkie standardowe konwencje wywoływania x86 zwracają wynik funkcji do
EAX
rejestru. Ale w prawdziwym kodzie maszynowym nie ma konwencji wywoływania. Możesz użyć dowolnych rejestrów dla wejścia / wyjścia. WykorzystanieECX
rejestru wyjściowego pozwoliło mi zaoszczędzić 1 bajt. Jeśli chcesz użyćEAX
, wstaw 1-bajtowąXCHG eax, ecx
instrukcję bezpośrednio przedret
instrukcją. Ten swapy WartościEAX
iECX
rejestry, skutecznie kopiuje wynik odECX
doEAX
, a koszuECX
ze starej wartościEAX
.Wypróbuj online!
Oto równoważna funkcja transkrybowana w C, przy użyciu funkcji
__builtin_ia32_rdrand32_step
wewnętrznej obsługiwanej przez GCC, Clang i ICC do wygenerowaniaRDRAND
instrukcji:Co ciekawe, GCC z
-Os
flagą przekształca to w prawie dokładnie ten sam kod maszynowy .EDI
Zamiast tego pobiera dane wejścioweESI
, co jest całkowicie arbitralne i nie zmienia nic istotnego w kodzie. Musi zwrócić wynikEAX
, jak wspomniałem wcześniej, i korzysta z bardziej wydajnej (ale większej)MOV
instrukcji, aby to zrobić bezpośrednio przedRET
. W przeciwnym razie same zady. Zawsze jest zabawnie, gdy proces jest w pełni odwracalny: napisz kod w asemblerze, transkrybuj go do C, uruchom go za pomocą kompilatora C i odzyskaj oryginalny zestaw!źródło
Python 2 ,
666461 bajtów-3 bajty dzięki xnor
Wypróbuj online!
Poprzedni zwój jest przechowywany w
c
, co pozwala nam na dostęp do niej wiele razy bez konieczności przechowywania jej w zmiennej, czego nie można zrobić w lambda Pythona. Przy każdej rekursji sprawdzamy, czy rzuciliśmy eksplodującymi kośćmi.c
jest inicjowany na zero, więcc%n
jest tam falsey. W następnych iteracjach będzie to falsey tylko wtedy, gdy rzuci się eksplodującymi kostkami.Python 2 , 55 bajtów
Wypróbuj online!
Moja druga odpowiedź wydaje się być nieco przerobiona, ponieważ wydaje się, że to również działa ... i tak zostawię.
źródło
c*(c<n)
może byćc%n
.R , 39 bajtów
Wypróbuj online!
Objaśnienie: to rozwiązanie pozwala uniknąć pętli rekurencyjnych / while, bezpośrednio obliczając rozkład liczby wybuchów, które wystąpią. Niechn będzie liczbą stron na kości. Jeśli uznajesz sukces za rzut n a porażkę za rzut cokolwiek innego, masz prawdopodobieństwo 1n sukcesu. Całkowita liczba wybuchów to liczba sukcesów przed pierwszą awarią. Odpowiada toGeometric(1−1n) dystrybucja (patrzstrona wikipedia, która określa sukces i porażkę na odwrót). Każda eksplozja prowadzido sumyn . Końcowe rolki następujeUniform(1,2,…,n−1) rozdzielczy, który dodać do całości.
źródło
sample
spełnia kryteria losowości, biorąc pod uwagę jej stronniczość ?sample
brakiem jednolitości, który daje stosunek prawdopodobieństwa maksimum do min wynoszącego 1,03 ... Szokujące, prawda ?!sample
z ? ;-)Perl 6 , 26 bajtów
Wypróbuj online!
Wyjaśnienie
źródło
{sum roll(*,1..$_)...$_>*}
J ,
1611 bajtówWypróbuj online!
Wyjaśnienie
TL; DR
1+?
wykonuje rzut matrycą,(+$:)^:=
powtarza tylko wtedy, gdy równa się wejściowi.Funkcja to ciąg 4 czasowników:
Pociąg ma miejsce, gdy 2 lub więcej czasowników jest połączonych. Tutaj odpowiedź ma postać
f g h j
:Tak zwany „4-pociąg” jest analizowany jako hak i widelec:
Zatem odpowiedź jest równoważna z:
Haki:
(f g) x
ix (f g) y
Monadyczny (jeden argument) hak dwóch czasowników, biorąc pod uwagę argument
x
, obowiązuje następująca równoważność:Na przykład
(* -) 5
ocenia do5 * (- 5)
, który ocenia_25
.Oznacza to, że nasz 4-pociągowy hak
f
i(g h j)
jest równoważny z:Ale co
f
tu robi?(+$:)^:=
jest koniunkcją dwóch czasowników używających koniunkcji Mocy^:
: innym hookiem ((+$:)
) i czasownikiem (=
). Zauważ tutaj, żef
jest drastyczny - ma dwa argumenty (x
i(g h j) x
). Musimy więc sprawdzić, jak się^:
zachowuje. Koniunkcja potęgif^:o
przyjmuje czasownikf
i czasownik lub rzeczowniko
(rzeczownik jest tylko fragmentem danych) i stosujef
o
czasy. Na przykład weźo = 3
. Obowiązują następujące równoważności:Jeśli
o
jest czasownikiem, koniunkcja potęgi po prostu ocenio
argumenty i użyje wyniku rzeczownika jako liczby powtórzeń.Dla naszego czasownika
o
jest=
to czasownik równości. Ocenia się0
dla różnych argumentów i1
dla równych argumentów. Powtarzamy hak(+$:)
raz dla równych argumentów, a nie dla różnych. Dla ułatwienia notacji wyjaśnienia, pozwóly ⇔ ((g h j) x)
. Pamiętaj, że nasz początkowy hak jest równoważny z tym:Po rozwinięciu koniunkcji staje się to:
Jeśli
x
iy
są takie same, staje się to:W przeciwnym razie staje się to:
Teraz widzieliśmy monadyczne widelce. Tutaj mamy dyadyczny widelec:
Tak więc, kiedy
x
iy
są takie same, otrzymujemy:Co to jest
$:
? Odnosi się do całego czasownika i pozwala na rekursję. Oznacza to, że kiedyx
i yare the same, we apply the verb to
yand add
x` do tego.Widły:
(g h j) x
Co robi wewnętrzny widelec? To był
y
nasz ostatni przykład. W przypadku monadycznego rozwidlenia trzech czasowników, z podaniem argumentux
, obowiązuje następująca równoważność:W następnym przykładzie załóżmy, że mamy czasowniki o nazwach
SUM
iDIVIDE
, iLENGTH
które, jak przypuszczasz, mogą mieć. Jeśli połączymy trójkę w rozwidlenie, otrzymamy:Ten widelec ocenia się na średnią
x
(zakładając, żex
jest to lista liczb). W J napisalibyśmy to jako przykład jako+/ % #
.Ostatnia rzecz dotycząca widelców. Gdy skrajnie lewy „ząb” (w naszym symbolicznym przypadku powyżej,
g
) jest rzeczownikiem, jest traktowany jako stała funkcja zwracająca tę wartość.Po tym wszystkim możemy teraz zrozumieć powyższy widelec:
?
Kładąc wszystko razem
Biorąc pod uwagę wszystkie te rzeczy, nasz czasownik jest równoważny z:
To wyraża pożądaną funkcjonalność.
źródło
(+$:)^:=1+?
Galaretka , 7 bajtów
Wypróbuj online!
Wykorzystuje rekurencję. Ponownie uruchamia program (
ß
) i dodaje (+
), jeśli (¡
) liczba losowa (X
) jest równa (=
) wejściu programu.}
sprawia, żeß
akt na wejściu programu i¥
kombajnów+ß}
się w jedno łącze¡
do konsumpcji.Tutaj rozkład 1000 wyników dla n = 6, które zebrałem za pomocą tego programu. Drukowane za pomocą python / matplotlib.
Oto 5000 punktów danych od n = 3 na wykresie semiloga, który pokazuje (w przybliżeniu?) Rozkład wykładniczy.
źródło
Pyth -
1211 bajtówKorzysta z funkcji podczas. Wydaje mi się, że powinna istnieć mądrzejsza odpowiedź, która po prostu symuluje dystrybucję.
Wypróbuj online .
źródło
Python 3 , 80 bajtów
Wypróbuj online!
źródło
r.random()
zdarzy się, że wartość 0.1-r.random()
powinna działać.import ... as _
jest najkrótszy!05AB1E , 10 bajtów
Wypróbuj online lub sprawdź listy .
10 bajtów alternatywnych:
Wypróbuj online lub sprawdź listy .
Although I like the top one more because it got the 'word'
DIÊ
in it, which suits the challenge.Explanation:
źródło
.Γ
or something.Wolfram Language (Mathematica), 50 bytes
Try it online!
źródło
R,
4742 bytesTry it online!
Credit to ArBo's approach.
Still a byte longer than Robin Ryder's, go upvote his!
źródło
if
for 46 bytes, but ended up getting a 52 on one roll which shouldn't be possible with n=4, so I don't know if there's a weird low recursion limit thing happening, but I think it may be buggy. Try it online!Ruby, 35 bytes
Try it online!
źródło
x
variable: Try it online!APL (Dyalog Unicode),
1514 bytesTry it online!
źródło
Haskell,
7776 bytesTry it online!
Thanks to killmous for one byte.
If
<|>
were in the prelude, we could do better withMonadComprehensions
:Haskell, non-competing, 66 bytes
Try it online!
źródło
Python 2, 53 bytes
Try it online!
Uses the
or
short-circuiting idea from ArBo's answer. The expressionrandom()*n//1
generates a number from0
ton-1
, with0
taking the place of a roll ofn
. Theor
takes the that number, except if it's zero (Falsey) it continues on ton+f(n)
.źródło
Japt, 13 bytes
Try it
Port of Arnauld's answer. Figured out how to make a recursive call ;)
Transpiled JS:
źródło
N.g(f)
:)U
. Skipping a line seems to work as well. That's a good trick :)Japt, 12 bytes
It may be shorter than dana's solution, but it's a hell of a lot uglier. I'm only posting it 'cause it seems like forever since we had a Japt solution that started with an empty line.
Try it
źródło
PowerShell, 49 bytes
Try it online!
Iterative method. Sets the input
$args
to$a
and the$l
ast roll (done so we enter the loop at least once). Then, so long as the last roll is-eq
ual to the input, we keep rolling. Inside the loop we accumulate into$o
the last roll, which is updated by creating a range from1
to input$a
and picking aRandom
element thereof. (Honestly, I'm a little surprised that$o+=$l=
works.) Once we're out of the loop, we leave$o
on the pipeline and output is implicit.źródło
Forth (gforth), 72 bytes
Try it online!
Code Explanation
źródło
Batch, 70 bytes
Takes input
n
as a command-line parameter%1
.d
is the current roll,t
the cumulative total. Simply keeps rolling untild
is not equal ton
.źródło
Jelly, 9 bytes
Try it online!
A monadic link that takes n as its argument and returns a number generated by an exploding n-sided die. This generates 256 numbers from 1 to n and returns the first cumulative sum that is not a multiple of n. In theory this could return 256n, but even for a 2-sided die this would happen only one every2256 times.
An alternative that doesn’t have this limitation is:
Jelly, 10 bytes
Try it online!
Note both TIO links generate 400 numbers to show the distribution.
źródło
Python 3,
8172 bytesTry it online!
-9 bytes thanks to ArBo
Explanation
źródło
from random import*
instead.TI-BASIC,
2823 bytes-5 bytes thanks to this meta post!
Input is in
Ans
.Output is in
Ans
and is implicitly printed.Examples:
Explanation:
Notes:
źródło
startTmr
is no longer necessary, this submission will now work for versions of TI-BASIC earlier than the TI-84+SmileBASIC 3, 49 bytes
Function
D N OUT R
implements exploding dice rolls recursively.Ungolfed
Note that in SmileBASIC, functions can have multiple return values. If a function has one return value then
fun in OUT var
andvar = fun(in)
are exactly the same, which is why we can define the function inOUT
form and also call it in an expression in the function body itself. If I had defined the function asDEF D(N)
I would have to explicitly stateRETURN R
in the function body; mixing both syntaxes saved me bytes.źródło
PowerShell, 43 bytes (Iterative method)
Try it online!
PowerShell, 48 bytes (recursive method)
Try it online!
źródło
Jelly, 7 bytes
A monadic Link accepting an integer,
n
, which yields an integer.Try it online! Or see the counts of105 runs
How?
źródło
SmileBASIC, 41 bytes
After reading:
I realized that rather than checking if a dice roll was
n
, you can just repeat while the sum is a multiple ofn
.źródło
AnyDice, 36 bytes
Almost a built-in in the language:
For this to be correct I have to abuse the infinite recursion depth assumption. AnyDice limits the recursion depth with a global property maximum function depth. the explode builtin however uses it's own; explode depth - which defaults to 2.
Would add another 25 bytes; and would not really match the requirements since it's theoretically possible for a dice to explode more than 99 times.
The output of the function is a die, ie. an AnyDice built-in type that is a paring of results and probabilities for the result.
źródło
CJam, 19 bytes
Explanation:
Or in pseudocode:
As a flowchart:
Try it online!
źródło
Excel VBA, 46 bytes
Thanks to @TaylorScott
Executed in the command window.
As a user-defined function.
Excel VBA,
10867 bytesźródło
do
..loop while
loop, and converting the function into an immediate window function. -Do:v=-Int(-[A1]*Rnd):t=t+v:Loop While[A1]=v:?t
- 46 Bytes