Patlayan Zar Simülasyonu


31

Göreviniz bir tamsayı alan bir program yapmak n > 1ve tek ntaraflı bir kalıp rulosunun çıktısını almaktır. Ancak, bu zar zar patlatma kurallarını takip eder .

Kalıbı yuvarlarken, hangi değeri aldınız kontrol edin. Bu tür bir kalıp için maksimum değeri elde ettiyseniz (d4'te 4 veya 6 olacak şekilde standart d4'te vb.), Tekrar rulo yapın ve yeni ruloyu toplamın üzerine ekleyin. Artık her bir sayı, maksimum sayıyı döndürmediğiniz sürece toplama eklemeye devam eder. Bu son sayı yine de eklenir.

Programınız tek bir tamsayı almalı nve patlayan ntaraflı kalıbı yuvarlamalıdır . İşte neye benzemesi gerektiğini gösteren bir örnek dağıtım n=4. Her nzaman patlayacağından, asla katlarını çıkarmamalısınız .

Yaptığınız herhangi bir özyinelemenin yığın boyutunun sonsuz olduğunu ve rastgele işlevinizin rastgele olma standartlarımızı karşılaması gerektiğini varsayabilirsiniz. ( veya saat / tarih ) . Rastgele fonksiyonunuz aynı zamanda mümkün olduğu kadar üniform olmalı, çünkü geometrik bir dağılıma benzer bir şey, çünkü bunlar hakkında konuştuğumuz zarlar.


1
program mükemmel olmak zorunda mı? Dağıtımının aşırı düşük bir miktarla azalması gibi mi?
Maltysen

Kime: Riker; RE: @ Maltysen'in yukarıdaki yorumu; ya da son derece yüksek miktarda?
Artemis,

Yanıtlar:


36

x86 Makine Kodu (Intel Ivy Bridge ve sonrası için), 17 bayt

31 C9 0F C7 F0 31 D2 F7 F6 42 01 D1 39 F2 74 F2 C3

Yukarıdaki kod baytları, patlayan bir kalıbı simüle eden bir işlevi tanımlar. ESIMaksimum kalıp sayısını belirten, kayıt defterinde geçirilen tek bir girişi alır . ECXRuloların sonucu olan kayıt defterinde tek bir değer döndürür .

Dahili olarak, rastgele bir sayı üretmek için RDRANDtalimatı kullanır . Bu, Intel Ivy Bridge işlemcilerinde donanıma yerleşik bir rastgele sayı üreteci (RNG) kullanır ve daha sonra (bazı AMD CPU'ları da bu talimatı destekler).

Fonksiyonun mantığı, aksi takdirde oldukça basittir. Üretilen rastgele sayı, standart teknik ( (rand % dieSize) + 1) kullanılarak istenen aralıkta olacak şekilde ölçeklendirilir ve ardından patlamaya neden olup olmayacağı kontrol edilir. Nihai sonuç bir akümülatör kaydında tutulur.

Assembly dili hatırlatıcılarını gösteren açıklamalı bir sürüm:

           unsigned int RollExplodingDie(unsigned int dieSize)
31 C9        xor     ecx, ecx    ; zero-out ECX, which accumulates the final result
           Roll:
0F C7 F0     rdrand  eax         ; generate a random number in EAX
31 D2        xor     edx, edx    ; zero-out EDX (in preparation for unsigned division)
F7 F6        div     esi         ; divide EDX:EAX by ESI (the die size)
                                 ;   EAX receives the quotient; EDX receives the remainder
42           inc     edx         ; increment the remainder
01 D1        add     ecx, edx    ; add this roll result to the accumulator
39 F2        cmp     edx, esi    ; see if this roll result should cause an explosion
74 F2        jz      Roll        ; if so, re-roll; otherwise, fall through
C3           ret                 ; return, with result in ECX register

Hile ediyorum biraz . Tüm standart x86 çağrı kuralları, bir işlevin sonucunu EAXkayıt defterinde döndürür . Ancak, gerçek makine kodunda, arama kuralları yoktur. Giriş / çıkış için istediğiniz kayıtları kullanabilirsiniz. Kullanımı ECXçıkış yazmacının bana 1 byte kurtardı. Kullanmak istiyorsanız EAX, XCHG eax, ecxtalimattan hemen önce 1 baytlık bir talimat ekleyin ret. Bu swap değerleri EAXve ECXkayıt, etkili bir sonucunu kopyalama ECXiçine EAXve harman ECXeski değer ile EAX.

Çevrimiçi deneyin!

İşte kullanarak C transkripsiyonu eşdeğer fonksiyon, var içsel üretmek için GCC, Clang ve ICC tarafından desteklenen talimat:__builtin_ia32_rdrand32_stepRDRAND

#include <immintrin.h>

unsigned int RollExplodingDie(unsigned int dieSize)
{
    unsigned int result = 0;
Roll:
    unsigned int roll;
    __builtin_ia32_rdrand32_step(&roll);
    roll    = ((roll % dieSize) + 1);
    result += roll;
    if (roll == dieSize)   goto Roll;
    return result;
}

İlginç şekilde, bayraklı GCC, -Osbunu neredeyse tamamen aynı makine koduna dönüştürür . Girdiyi EDIyerine alır ESI, tamamen keyfidir ve kodla ilgili hiçbir şey değiştirmez. Daha EAXönce de belirttiğim gibi sonucu döndürmelidir ve bunu MOVhemen önce yapmak için daha verimli (ancak daha büyük) talimatı kullanır RET. Aksi takdirde sameziler. İşlem tamamen tersinir olduğunda her zaman eğlencelidir: kodu montaja yazın, C'ye kopyalayın, C derleyicisinden geçirin ve orijinal montajınızı geri alın!


12

Python 2 , 66 64 61 bayt

Xnor sayesinde -3 bayt

f=lambda n,c=0:c%n or c+f(n,randint(1,n))
from random import*

Çevrimiçi deneyin!

Önceki rulo saklanır c bir Python lambdada yapılamayan bir değişkende saklamak zorunda kalmadan defalarca erişmemize izin verir. Her tekrarlamada patlayan zar atıp atmadığımızı kontrol ediyoruz.

c sıfır olarak başlatılır, yani c%n orada falsey. Sonraki yinelemelerde, sadece patlayan zarlar yuvarlanırsa yanlış olur.

Python 2,55 bayt

f=lambda n:randint(1,n)%n or n+f(n)
from random import*

Çevrimiçi deneyin!

Diğer cevabım biraz fazla mühendislikten görünüyor, çünkü bu da işe yarıyor gibi görünüyor ... Yine de bırakacağım.


2
Kırılma koşulunun rasgeleliğe dayandığı özyinelemeli işlevler her zaman sıfır olmayan yığın taşması şansına sahip olacaktır. İstatistiksel olarak önemsiz bir şans, ama yine de ...
mypetlion

3
Genelde, yığın boyutumun deneyimimdeki kod golfü mücadelesinde sonsuz olduğu varsayılmaktadır. Yığın boyutu sonsuzluğa arttıkça, yığma taşması olasılığı hızla sıfıra dönüşür.
ArBo

Yorumunuzu yazmadan önce ArBo @mypetlion yapın, böylece kullanıcıyı ping edebilirsiniz
MilkyWay90

1
Bence c*(c<n)olabilir c%n.
xnor

@xnor Tabii ki, ben bir aptalım ...
ArBo

12

R , 39 bayt

n=scan();n*rgeom(1,1-1/n)+sample(n-1,1)

Çevrimiçi deneyin!

Açıklama: bu çözüm, oluşacak patlama sayısının dağılımını doğrudan hesaplayarak tekrarlar / döngülerden kaçınır. n ölüme taraf sayısı olalım . Başarıyı n yuvarlamak, başka bir şeyi yuvarlamak olarak başarısızlık olarak belirtirseniz , olasılık 1nbaşarı n . Toplam patlama sayısı, ilk başarısızlıktan önceki başarı sayısıdır. Bir Bu tekabülGeometric(11n)dağıtım (başarı ve başarısızlığı tam tersi yönde tanımlayanwikipedia sayfasınabakınız). Her patlamatoplamıngetirir. Son rulo bir aşağıdakiUniform(1,2,,n1)biz toplam eklemek dağılımı.


çok hoş! Rastgele zorluklar için yerleşik dağıtımları seviyorum !
Giuseppe

Does sampleverilen rasgelelikten standartlarını karşılamak onun önyargı ?
Xi'an,

Xi'an @ Oldukça emin öyle : o Dahili bağımsız rastgele değişkenler için rastgele jeneratörü.
Robin Ryder

Biliyorum, biliyorum ama koyduğum bağlantıyı kontrol et: doğası gereği takdirsizlik, sample1,03'e kadar çıkarak maksimum - min olasılık arasındaki bir tekdüzelik eksikliğine yol açar ... Şok değil mi ?!
Xi'an

samplem231

9

Perl 6, 26 bytes

{sum {roll 1..$_:}...*-$_}

Try it online!

açıklama

{                        } # Anonymous block
                  ...      # Sequence constructor
     {roll 1..$_:}         #   Next elem is random int between 1 and n
                           #   (Called as 0-ary function with the original
                           #   $_ for the 1st elem, then as 1-ary function
                           #   with $_ set to the previous elem which
                           #   equals n.)
                     *-$_  #   Until elem not equal to n (non-zero difference)
 sum                       # Sum all elements

2
Güzel, benim kendi çözümüm{sum roll(*,1..$_)...$_>*}
Jo King,

9

J , 16 11 bayt

(+$:)^:=1+?

Çevrimiçi deneyin!

açıklama

TL; DR 1+? , kalıp rulosunu gerçekleştirir, (+$:)^:=yalnızca girişe eşit olduğunda tekrar eder.


Fonksiyon 4 fiilden oluşan bir trendir:

             ┌─ + 
         ┌───┴─ $:
  ┌─ ^: ─┴─ =     
  │               
──┤      ┌─ 1     
  └──────┼─ +     
         └─ ?     

Bir tren 2 veya daha fazla fiilin birleştirildiği zamandır. Burada cevap şu şekildedir f g h j:

(+$:)^:=  1  +  ?
    f     g  h  j

A so-called "4-train" is parsed as a hook and a fork:

f g h j   ⇔   f (g h j)

Thus, the answer is equivalent to:

(+$:)^:= (1 + ?)

Hooks: (f g) x and x (f g) y

A monadic (one-argument) hook of two verbs, given an argument x, the following equivalence holds:

(f g) x   ⇔   x f (g x)

For example, (* -) 5 evaluates to 5 * (- 5), which evaluates to _25.

Bu, 4 kancamızın bir kancası fve (g h j)eşdeğeri anlamına gelir:

(f (g h j)) x   ⇔   x f ((g h j) x)

Ama fburada ne yapar ? Güç bağlantısını (+$:)^:=kullanarak iki fiilin bir birleşimidir : başka bir kanca ( ) ve bir fiil ( ). Burada not : didik - bunun iki argümanı ( ve ) vardır. Bu yüzden nasıl davrandığına bakmalıyız . Güç bağlantısı bir fiil alır ve bir fiil veya bir isim (bir isim sadece bir veri parçasıdır) ve zaman uygular . Örneğin, al . Aşağıdaki eşitlikler geçerlidir:^:(+$:)=fx(g h j) x^:f^:ofof oo = 3

(f^:3) x     ⇔   f (f (f x))
x (f^:3) y   ⇔   x f (x f (x f y))

Eğer obir fiildir, güç birlikte basitçe değerlendirecek oargümanları tekrar tekrar sayısı olarak isim sonucu kullanın.

Bizim fiil için, oolduğu =, eşitlik fiil. Bu değerlendirilen 0farklı bağımsız değişkenler için ve 1eşit bağımsız değişkenler için. Kancayı (+$:)eşit argümanlar için bir kez ve farklı olanlar için bir kez tekrarlamayız . Açıklama için gösterim kolaylığı için, izin verin y ⇔ ((g h j) x). İlk kancamızın buna eşdeğer olduğunu unutmayın:

x   (+$:)^:=   ((g h j) x)
x   (+$:)^:=   y

Bağlantının genişletilmesi, bu olur:

x ((+$:)^:(x = y)) y

Aynı xve eğer y, bu olur:

x (+$:)^:1 y   ⇔   x (+$:) y

Aksi takdirde, bu olur:

x (+$:)^:0 y   ⇔   y

Şimdi, monadik çatal gördük. Burada iki çatallı bir çatalımız var:

x (f g) y   ⇔   x f (g y)

Öyleyse, ne zaman xve yaynıyız:

x (+$:) y   ⇔   x + ($: y)

Nedir $:? Tüm fiilin kendisine atıfta bulunur ve özyinelemeye izin verir. Bunun anlamı ne zaman xve are the same, we apply the verb toyand add buna x`.

çatallar: (g h j) x

Şimdi, iç çatal ne yapar? Bu yson örneğimizdi. Üç fiilli bir monadik çatal için, bir argüman verildiğinde x, aşağıdaki eşdeğerlik geçerlidir:

(g h j) x   ⇔   (g x) h (j x)

Bu sonraki Örneğin, fiiller adında var varsayalım SUM, DIVIDEve LENGTHsen onlar olabilir ne dersiniz, hangi. Üçünü bir çatalı birleştirirsek, şunu elde ederiz:

(SUM DIVIDE LENGTH) x   ⇔   (SUM x) DIVIDE (LENGTH x)

Bu çatal, x( xbir sayılar listesi olduğunu varsayarak) ortalamasını değerlendirir . J'de bunu gerçekten örnek olarak yazardık +/ % #.

Çatallar hakkında son bir şey. En soldaki "tine" (yukarıdaki sembolik durumumuzda g) bir isim olduğunda, bu değeri döndüren sabit bir işlev olarak değerlendirilir.

Bütün bunlar yerinde iken, yukarıdaki çatalı anlayabiliriz:

(1 + ?) x   ⇔   (1 x) + (? x)
            ⇔   1 + (? x)

? Burada aralıktaki rastgele bir tamsayı verir [0,x)bu yüzden zarı temsil etmek için aralığı dönüştürmemiz gerekir; artış, menzili verir[1,x].

Hepsini bir araya koy

Tüm bunlar göz önüne alındığında, fiilimiz şuna eşittir:

((+$:)^:=1+?) x   ⇔   ((+$:)^:= 1 + ?) x
                  ⇔   ((+$:)^:= (1 + ?)) x
                  ⇔   x ((+$:)^:=) (1 + ?) x
                  ⇔   x ((+$:)^:=) (1 + (? x))
                  ⇔   x (+$:)^:(x = (1 + (? x))
(let y = 1 + (? x))
if x = y          ⇒   x + $: y
otherwise         ⇒   y

Bu istenen işlevselliği ifade eder.


1
(+$:)^:=1+?­­
01

@ ngn Teşekkürler! Anonim.
Conor O'Brien,

7

Jöle , 7 bayt

X+ß}¥=¡

Çevrimiçi deneyin!

Özyineleme kullanır. Programı tekrar çalıştırır ( ß) ve ( +) ¡rasgele sayı ( X) =program girişine eşit ( ) ise ( ) ekler . }yapar ßprogramı giriş ve üzerinde hareket ¥biçerdöver+ß} için tek bir bağlantı içine ¡tüketmek.

İşte bu programı kullanarak topladığım n = 6 için 1000 çıkış dağılımı . Python / matplotlib ile çizilir. histogram

İşte (yaklaşık?) Üstel dağılımını gösteren bir semilog arsa üzerinde n = 3 olan 5000 veri noktası. enter image description here


Güzel araziler! Alacağınız dağılım , üstel dağılımla yakından ilgili olan geometrik bir dağılımdır ( R cevabımı inceleyiniz ) .
Robin Ryder

6

Pyth - 12 11 bayt

Fonksiyonel iken kullanır. Dağılımı simüle eden daha akıllıca bir cevap olması gerektiğini düşünüyorum.

-.W!%HQ+hOQ

-         (Q)         Subtract Q. This is because we start Z at Q to save a char
 .W                   While, functionally
  !                   Logical not. In this case, it checks for 0
   %HQ                Current val mod input
  +     (Z)           Add to current val
   h                  Plus 1
    OQ                Random val in [0, input)

Çevrimiçi deneyin .


4

Python 3 , 80 bayt

import random as r,math
lambda n:int(-math.log(r.random(),n))*n+r.randint(1,n-1)

Çevrimiçi deneyin!


1
Olursa, başarısızlık için küçük bir şans var. r.random()0 ise 1-r.random(), işe yaramalı.
nwellnhof

Her ne kadar teknik olarak bu şans 0
Quintec

1
En import ... as _kısa olan nadir bir durum !
xnor

@xnor gerçekten! Bir cevabında kazandığımı hatırladığım diğer zamanlar burada
Lynn

4

05AB1E , 10 bayt

[ILΩDIÊ#}O

Çevrimiçi deneyin veya listeleri doğrulayın .

10 bayt alternatif:

[LΩDˆÊ#}¯O

Çevrimiçi deneyin veya listeleri doğrulayın .

Yine de birincisini daha çok sevmeme rağmen “kelime” aldı DIÊ in it, which suits the challenge.

Açıklama:

[         # Start an infinite loop:
 IL       #  Create a list in the range [1, input]
   Ω      #  Pop and push a random value from this list
    D     #  Duplicate it
     IÊ   #  If it's NOT equal to the input:
       #  #   Stop the infinite loop
}O        # After the loop: sum all values on the stack
          # (which is output implicitly as result)

[         # Start an infinite loop
 L        #  Create a list in the range [1, (implicit) input]
  Ω       #  Pop and push a random value from this list
   Dˆ     #  Add a copy to the global_array
     Ê    #  If it's NOT equal to the (implicit) input:
      #   #   Stop the infinite loop
        # After the loop: push the global_array
  O       # Pop and push its sum
          # (which is output implicitly as result)  

Kullanmanın bir yolunu veya başka bir şeyi düşünmeye çalışıyordu .
Magic Octopus Urn


3

R, 47 42 bytes

function(n){while(!F%%n)F=F+sample(n,1)
F}

Try it online!

Credit to ArBo's approach.

Still a byte longer than Robin Ryder's, go upvote his!


Interesting, I reworked this to a recursive 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!
CriminallyVulgar

I tried a recursive and got a 54 byte solution. Then tried something similar to yours for 44 Try it online!
Aaron Hayman



3

Haskell, 77 76 bytes

import System.Random
f x=randomRIO(1,x)>>=(x!)
x!y|y<x=pure y|0<1=(y+)<$>f x

Try it online!

Thanks to killmous for one byte.

If <|> were in the prelude, we could do better with MonadComprehensions:

Haskell, non-competing, 66 bytes

import System.Random
f x=do y<-randomRIO(1,x);[y|y<x]<|>(y+)<$>f x

Try it online!


1
You can save a byte if you define g as an infix function.
killmous

1
@killmous, thanks. At first glance I figured that would be the same or worse, but it's better.
dfeuer

3

Python 2, 53 bytes

f=lambda n:random()*n//1or n+f(n)
from random import*

Try it online!

Uses the or short-circuiting idea from ArBo's answer. The expression random()*n//1 generates a number from 0 to n-1, with 0 taking the place of a roll of n. The or takes the that number, except if it's zero (Falsey) it continues on to n+f(n).


It seems your answer was already up when I edited in my shorter one... I didn't see this, but if you want me to delete it because it's quite alike I will.
ArBo


3

Japt, 13 bytes

ö)g@¶°X?X+ß:X

Try it

Port of Arnauld's answer. Figured out how to make a recursive call ;)

Transpiled JS:

// U: Implicit input
// ö: generate a random number [0,U)
(U.ö())
  // g: run the result through a function
  .g(function(X, Y, Z) {
    // increment the result and compare to input
    return U === (++X)
      // if they are the same, roll again and add to current roll
      ? (X + rp())
      // if they are different, use current roll
      : X
   })

1
Very nice use of N.g(f) :)
Shaggy

Took a stab at this meself and ended up with 12 bytes but I don't want to post it 'cause I like your solution too much!
Shaggy

Post it as a different answer :)
dana

It may be shorter, but it's a hell of a lot uglier than yours: petershaggynoble.github.io/Japt-Interpreter/…
Shaggy

I see - yeah I was trying to come up with a way not to pollute U. Skipping a line seems to work as well. That's a good trick :)
dana

3

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.


ö
>°V©VªV+ß

Try it


2

PowerShell, 49 bytes

for($a=$l="$args";$a-eq$l){$o+=$l=1..$a|Random}$o

Try it online!

Iterative method. Sets the input $args to $a and the $last roll (done so we enter the loop at least once). Then, so long as the last roll is -equal to the input, we keep rolling. Inside the loop we accumulate into $o the last roll, which is updated by creating a range from 1 to input $a and picking a Random 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.


2

Forth (gforth), 72 bytes

include random.fs
: f >r 0 begin i random 1+ >r i + r> i < until rdrop ;

Try it online!

Code Explanation

include random.fs      \ include library file for random
: f                    \ start a new word definition
  >r                   \ stick the input on the return stack (for easy access)
  0                    \ add a counter to hold the sum
  begin                \ start an indefinite loop
    i random 1+        \ generate a random number from 1 to n
    >r i + r>          \ add the result to the counter, use the return stack to save a few bytes
    i <                \ check if result was less than n
  until                \ end the loop if it was, otherwise go back to begin
  rdrop                \ remove n from the return stack
;                      \ end the word definition

2

Batch, 70 bytes

@set t=0
:g
@set/at+=d=%random%%%%1+1
@if %d%==%1 goto g
@echo %t%

Takes input n as a command-line parameter %1. d is the current roll, t the cumulative total. Simply keeps rolling until d is not equal to n.


2

Jelly, 9 bytes

x⁹X€Ä%ƇµḢ

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 every 2256 times.

An alternative that doesn’t have this limitation is:

Jelly, 10 bytes

X³X¤+¥³ḍ¥¿

Try it online!

Note both TIO links generate 400 numbers to show the distribution.


2

Python 3, 81 72 bytes

from random import*
def f(x,a=0):
 while a%x<1:a+=randint(1,x)
 return a

Try it online!

-9 bytes thanks to ArBo

Explanation

import random             #load the random module              
def explodeDice(num):     #main function
    ans = 0                     #set answer to 0
    while a % num != 0:         #while a isn't a multiple of the input
        ans += random.randint(1, num) #add the next dice roll to answer
    return ans                  #return the answer

You can save 1 byte by using from random import* instead.
orthoplex

1
You can get this down to 74 bytes using this recursive solution
Reinstate Monica

1
@squid You can save 1 byte like this.
orthoplex

1
@orthoplex and then you can shorten the if/else, and make it a one-liner. Starts to look like my solution then ;)
ArBo

1
@ArBo Yea that's why I didn't change to recursive, didn't want to just copy you.
Artemis supports Monica

2

TI-BASIC, 28 23 bytes

-5 bytes thanks to this meta post!

Ans→N:0:Repeat fPart(Ans/N:Ans+randInt(1,N:End:Ans

Input is in Ans.
Output is in Ans and is implicitly printed.

Examples:

4
              4
prgmCDGF11
              5
6
              6
prgmCDGF11
              3

Explanation:

Ans→N:0:Repeat fPart(Ans/N:Ans+randInt(1,N:End:Ans   ;full logic

Ans→N                                                ;store the input in "N"
      0                                              ;leave 0 in "Ans"
        Repeat fPart(Ans/N                 End       ;loop until the sum
                                                     ; is not a multiple of
                                                     ; the input
                               randInt(1,N           ;generate a random
                                                     ; integer in [1,N]
                           Ans+                      ;then add it to "Ans"
                                               Ans   ;leave the sum in "Ans"
                                                     ;implicitly print "Ans"

Notes:

  • TI-BASIC is a tokenized language. Character count does not equal byte count.

Since startTmr is no longer necessary, this submission will now work for versions of TI-BASIC earlier than the TI-84+
Tau

2

SmileBASIC 3, 49 bytes

Function D N OUT R implements exploding dice rolls recursively.

DEF D N OUT R
R=RND(N)+1IF R==N THEN R=R+D(N)
END

Ungolfed

DEF D N OUT R  'N is sides and R is output param (shorter than using RETURN in this case)
 R=RND(N)+1  'random number in [1, N]
 IF R==N THEN R=R+D(N)  'if roll is same as N then roll again and add
END

Note that in SmileBASIC, functions can have multiple return values. If a function has one return value then fun in OUT var and var = fun(in) are exactly the same, which is why we can define the function in OUT form and also call it in an expression in the function body itself. If I had defined the function as DEF D(N) I would have to explicitly state RETURN R in the function body; mixing both syntaxes saved me bytes.



2

Jelly, 7 bytes

X=п⁸S_

A monadic Link accepting an integer, n, which yields an integer.

Try it online! Or see the counts of 105 runs

How?

X=п⁸S_ - Link: integer, n
  п    - Collect up while...
 =  ⁸   - ...condition: equal to chain's left argument, n
X       - ...next value: random number in [1..n]
     S  - sum
      _ - subtract n (since the collection starts with [n])

2

SmileBASIC, 41 bytes

INPUT N@L
S=S+RND(N)+1ON S MOD N GOTO@L?S

After reading:

Note that you should never output any multiples of n, since they will always explode.

I realized that rather than checking if a dice roll was n, you can just repeat while the sum is a multiple of n.


2

AnyDice, 36 bytes

Almost a built-in in the language:

function:f I:n{result: [explode dI]}

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.

set "explode depth" to 99

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.


1
I think I'm OK with it not exploding much, the 36 byte one is fine by me. I didn't say no builtins and I'm ok with having them here, since it's not like your 1 or 0 byte answer is winning. But welcome to the site!
Rɪᴋᴇʀ

2

CJam, 19 bytes

qi{__mr)_T+:T;=}g;T

Explanation:

T is pre-set to 0

qi{__mr)_T+:T;=}g;T - whole code
qi                  - read input as integer (n) | Stack: n
  {            }    - block
   __               - Duplicate twice | Stack: n n n
     mr)            - Choose a random number from 1 to n (r). Since 'mr' picks a
                      number from 0 to n-1, the number has to be incremented with ')' 
                      Stack: n n r
        _           - Duplicate |  Stack: n n r r
         T          - push T | Stack: n n r r T
          +         - add the random number to T (t) | Stack: n n r t
           :T;      - pop the value and store in T | Stack: n n r
              =     - are the top two stack values the same (c) | Stack: n c
               }
                g   - do while loop that pops the condition from the stack after each
                      iteration | Stack: n
                 ;  - pop the top stack element and discard | Stack: T
                  T - push T | Stack: T
                    - implicit output

Or in pseudocode:

input n
var sum = 0
do {
    var random_number = pick random number from 1 to n
    sum = sum + random_number
} while (random_number == n)
output n

As a flowchart:

Flowchart of code

Try it online!


2

Excel VBA, 46 bytes

Thanks to @TaylorScott

Do:v=-Int(-[A1]*Rnd):t=t+v:Loop While[A1]=v:?t

Executed in the command window.

As a user-defined function.

Excel VBA, 108 67 bytes

Function z(i)
Do
v=Int((i*Rnd)+1)
z=z+v
Loop While v=i
End Function

You can get this down quite a bit by using a 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
Taylor Scott

1
@TaylorScott Thanks, I forgot that Do x While y existed in Excel VBA.
william porter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.