Моделювання вибуху кісток


31

Ваше завдання - скласти програму, яка займає ціле число n > 1, і виводить рулон nодностороннього штампу. Однак ця кістка дотримується правил вибуху кісток .

Коли ви закатаєте штамп, перевірте, яке значення ви прокатали. Якщо ви отримали максимум для такої штампу (на стандартному d4, який би був 4, або 6 на d6, і т. Д.), Скрутіть ще раз і додайте новий рулон до цієї суми. Кожен рулон продовжує додаватись до загальної суми, поки ви більше не згорнете максимальне число. Це остаточне число все ж додається.

Ваша програма повинна взяти одне ціле число nі закатати вибухонебезпечну nматрицю. Ось приклад розподілу, щоб показати, як він повинен виглядати n=4. Зауважте, що ви ніколи не повинні виводити жодних кратних чиселn , оскільки вони завжди вибухнуть.

Ви можете припустити, що розмір стека для будь-якої рекурсії, яку ви виконуєте, нескінченний, і ваша випадкова функція повинна відповідати нашим стандартам щодо випадковості (вбудований випадковий генератор або час / дата ). Ваша випадкова функція також повинна бути максимально рівномірною, порівняно з чимось на зразок геометричного розподілу, оскільки це кістки, про які ми говоримо.


1
чи повинна програма бути досконалою? Можливо, може бути розповсюджено його надзвичайно низька кількість?
Мальтісен

До: Рікер; RE: @ коментар Мальтісена вище; чи надзвичайно висока сума?
Артеміда підтримує Моніку

Відповіді:


36

машинний код x86 (для Intel Ivy Bridge та новіших версій), 17 байт

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

Наведені вище байти коду визначають функцію, яка імітує вибухну штамп. Він займає один вхід, переданий в ESIрегістр, із зазначенням максимальної кількості штампу. Він повертає єдине значення вECX регістрі, яке є результатом згортки.

Усередині вона використовує в RDRANDінструкції , щоб згенерувати випадкове число. Для цього використовується генератор випадкових чисел (RNG), який вбудований в апаратне забезпечення на процесорах Intel Ivy Bridge і пізніше (деякі процесори AMD також підтримують цю інструкцію).

Логіка функції в іншому випадку досить проста. Створене випадкове число масштабується, щоб лежати в межах бажаного діапазону, використовуючи стандартну техніку ((rand % dieSize) + 1 ), а потім перевіряється, чи повинно воно спричинити вибух. Кінцевий результат зберігається в реєстрі акумуляторів.

Ось помічена версія, що показує мнемоніку мови збірки:

           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

Я трохи обманюю . Усі стандартні конвенції викликів x86 повертають результат функції в EAXрегістр. Але, у справжньому машинному коді, умовних вимог немає. Ви можете використовувати будь-які регістри, які потрібно для вводу / виводу. Використовуючи ECXдля вихідного регістра, врятували мене 1 байт. Якщо ви хочете використовувати EAX, вставте 1-байтну XCHG eax, ecxінструкцію безпосередньо перед retінструкцією. Це підміняє значення EAXі ECXреєструє, ефективно копіюючи результат з ECXу EAX, і перебираючи ECXзі старим значенням EAX.

Спробуйте в Інтернеті!

Ось еквівалентна функція розшифровані в C, використовуючи в __builtin_ia32_rdrand32_stepхарактеристичної підтримуваний GCC, Clang і ICC для створення RDRANDінструкції:

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

Цікаво, що GCC з -Osпрапором перетворює це майже в той самий машинний код . Він EDIзамість цього займає вхід ESI, який є абсолютно довільним і нічого не змінює щодо коду. Він повинен повернути результат EAX, як я вже згадував раніше, і він використовує більш ефективну (але більшу) MOVінструкцію, щоб зробити це безпосередньо перед RET. В іншому випадку samezies. Це завжди весело, коли процес є повністю оборотним: запишіть код на зборах, перепишіть його на C, запустіть його через компілятор C і отримайте назад свою оригінальну збірку!


12

Python 2 , 66 64 61 байт

-3 байти завдяки xnor

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

Спробуйте в Інтернеті!

Попередній ролик зберігається в ньому c, що дозволяє нам отримати доступ до нього кілька разів без необхідності зберігати його до змінної, що неможливо зробити в лямбда Python. Кожну рекурсію ми перевіряємо, чи перекочували ми вибухаючі кістки.

cініціалізовано до нуля, так c%nце і фальси. У наступних ітераціях це буде фальсифікація лише в тому випадку, якщо вибухові кістки будуть перекинуті.

Python 2 , 55 байт

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

Спробуйте в Інтернеті!

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


2
Рекурсивні функції, де умова розриву заснована на випадковості, завжди матимуть ненульовий шанс переповнення стека. Статистично незначний шанс, але все ж ...
mypetlion

3
Зазвичай, на мій досвід, розмір стека вважається нескінченним у проблемах із гольфним кодом. Оскільки розмір стека збільшується до нескінченності, ймовірність переповнення стека швидко переходить до нуля.
ArBo

ArBo do @mypetlion перед тим, як ввести коментар, щоб ви могли пінг користувача
MilkyWay90,

1
Я думаю, що c*(c<n)може бути c%n.
xnor

@xnor Звичайно, я ідіот ...
ArBo

12

R , 39 байт

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

Спробуйте в Інтернеті!

Пояснення: це рішення дозволяє уникнути рекурсії / циклів під час прямого обчислення розподілу кількості вибухів, які відбудуться. Нехай n - кількість сторін на плашці. Якщо ви позначаєте успіх як перекидання n а невдачу як прокручування чого-небудь іншого, то у вас є ймовірність 1n успіху. Загальна кількість вибухів - це кількість успіхів до першої відмови. Це відповідаєGeometric(11n)розповсюдження (див. сторінкувікіпедії, яка визначає успіх і невдачу навпаки). Кожен вибух доводитьnдо загальної кількості. За підсумковим рулоном слідрозподілUniform(1,2,,n1)який ми додаємо до загального.


дуже хороша! Треба любити вбудовані дистрибутиви за випадкові виклики!
Джузеппе

Чи sampleвідповідає стандартам випадковості, враховуючи його упередженість ?
Сіань

@ Xi'an Досить впевнений, що це робить : це вбудований випадковий генератор для дискретних випадкових змінних.
Робін Райдер

Я знаю, знаю, але перевірте посилання, яке я поклав: притаманна дискретизація sampleпризводить до відсутності рівномірності, що дає співвідношення максимум до мінімальної ймовірності до 1,03 ... Шокуюче, чи не так ?!
Сіань

Yes, it is shocking. But then again, how often do you use sample with m231? ;-)
Robin Ryder

9

Perl 6, 26 bytes

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

Try it online!

Explanation

{                        } # 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
Nice, my own solution was {sum roll(*,1..$_)...$_>*}
Jo King

9

J, 16 11 bytes

(+$:)^:=1+?

Try it online!

Explanation

TL;DR 1+? performs the die roll, (+$:)^:= reiterates only when it equals the input.


The function is a train of 4 verbs:

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

A train is when 2 or more verbs are concatenated. Here, the answer is of the form 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.

This means that our 4-train, a hook of f and (g h j), is equivalent to:

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

But what does f do here? (+$:)^:= is a conjunction of two verbs using the Power conjunction ^:: another hook ((+$:)) and a verb (=). Note here that f is dyadic—it has two arguments (x and (g h j) x). So we have to look at how ^: behaves. The power conjunction f^:o takes a verb f and either a verb or a noun o (a noun is just a piece of data) and applies f o times. For example, take o = 3. The following equivalences holds:

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

If o is a verb, the power conjunction will simply evaluate o over the arguments and use the noun result as the repeat count.

Для нашого дієслова o- =це дієслово рівності. Вона оцінюється як 0для різних аргументів, так і 1для рівних аргументів. Ми повторюємо гачок (+$:)один раз для рівних аргументів і не раз для різних. Для зручності позначення для пояснення нехай y ⇔ ((g h j) x). Пам'ятайте, що наш початковий гак рівнозначний цьому:

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

Розширюючи сполучник, це стає:

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

Якщо xі yоднакові, це стає:

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

В іншому випадку це стає:

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

Тепер ми бачили монадичні вилки. Ось у нас діадічна вилка:

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

Отже, коли xі yоднакові, ми отримуємо:

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

Що таке $:? Він відноситься до всього самого дієслова і допускає рекурсію. Це означає, що коли xі y are the same, we apply the verb toy and addx` до нього.

Вилки: (g h j) x

Тепер, що робить внутрішня вилка? Це було yв нашому останньому прикладі. Для монадичної вилки з трьох дієслів, заданих аргументом x, має місце наступна еквівалентність:

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

Для такого прикладу припустимо, що ми дієслова з ім'ям SUM, DIVIDEі LENGTH, що робити то , що ви думаєте , що вони могли б. Якщо ми об'єднаємо трійку у виделку, отримуємо:

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

Ця вилка оцінюється до середнього значення x(припускаючи x, що це список номерів). У J ми насправді запишемо це як приклад як +/ % #.

Останнє про вилки. Коли крайній лівий "зубчик" (у нашому символічному випадку вище g) є іменником, це трактується як постійна функція, що повертає це значення.

Маючи все це на місці, тепер ми можемо зрозуміти вищезгадану вилку:

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

? тут дається випадкове ціле число в діапазоні [0,x), so we need to transform the range to represent dice; incrementing yields the range [1,x].

Putting it all together

Given all these things, our verb is equivalent to:

((+$:)^:=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

This expresses the desired functionality.


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

@ngn Thanks! Incorporated.
Conor O'Brien

7

Jelly, 7 bytes

X+ß}¥=¡

Try it online!

Uses recursion. Runs the program again (ß) and adds (+) if (¡) the random number (X) is equal (=) to the program input. } makes ß act on the program input and ¥ combines +ß} into a single link for ¡ to consume.

Here a distribution of 1000 outputs for n=6 which I collected using this program. Plotted with python/matplotlib. histogram

Here is a 5000 data points from n=3 on a semilog plot which shows the (approximately?) exponential distribution. enter image description here


Nice plots! The distribution you get is a geometric distribution (see my R answer), which is closely related to the exponential distribution.
Robin Ryder

6

Pyth - 12 11 bytes

Uses functional while. I feel like there should be a smarter answer that just simulates the distribution.

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

Try it online.


4

Python 3, 80 bytes

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

Try it online!


1
There's a slight chance for failure if r.random() happens to return 0. 1-r.random() should work, though.
nwellnhof

Though technically that chance is 0
Quintec

1
A rare case where import ... as _ is shortest!
xnor

@xnor indeed! The only other time I remember that winning out in an answer of mine is here
Lynn

4

05AB1E, 10 bytes

[ILΩDIÊ#}O

Try it online or verify the lists.

10 bytes alternative:

[LΩDˆÊ#}¯O

Try it online or verify the lists.

Although I like the top one more because it got the 'word' DIÊ in it, which suits the challenge.

Explanation:

[         # 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)  

Was trying to think of a way to use or something.
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

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