Bersiap untuk mati?

22

Latar Belakang

Salah satu sumber ennui dalam permainan peran-bermain di atas meja adalah berurusan dengan gulungan yang melibatkan banyak dadu. Menggunakan mantra Disintegrasi mungkin instan, tetapi menggulung dan menambahkan 40 dadu tentu saja tidak!

Sejumlah saran untuk penanganan ini dibahas di rpg.stackexchange.com . Namun beberapa dari mereka, seperti menggunakan program roller atau dadu rata-rata, menghilangkan kesenangan dan rasa kontrol dari para pemain. Lainnya, seperti menggulirkan 4 dadu dan mengalikan totalnya dengan 10, membuat hasilnya jauh lebih berayun (sementara rata-rata dadu bertingkah berlawanan arah).

Pertanyaan ini menyangkut metode pengurangan jumlah dadu gulungan tanpa mengubah baik hasil rata-rata (rata-rata) atau swinginess (varians).

Notasi dan matematika

Dalam pertanyaan ini, kami akan menggunakan notasi berikut untuk mewakili gulungan dadu:

  • n d k (misalnya 40d6) mengacu pada jumlah n gulungan mati k-sided.
  • n d k * c (mis. 4d6 * 10) menjelaskan mengalikan hasil dengan konstanta c.
  • Kita juga dapat menambahkan gulungan (mis. 4d6 * 10 + 40d6) dan konstanta (mis. 4d6 + 10).

Untuk satu die roll, kami dapat menunjukkan bahwa:

  • Mean : E [1d k ] = (k + 1) / 2
  • Varians : Var (1d k ) = (k-1) (k + 1) / 12

Dengan menggunakan properti dasar mean dan varians, kita dapat lebih jauh menyimpulkan bahwa:

  • Berarti : E [ m d k * a + n d l * b + c ] = saya .e [1d k ] + bn [1d. L ] + c
  • Variance : Var ( m d k * a + n d l * b + c ] = a . ² m .Var (1d k ) + b ². N .Var (1d l )

Tugas

Mengingat tiga bilangan bulat n , k dan r , program anda harus output cara mendekati n d k di paling r gulungan, dengan kendala berikut:

  • Solusinya harus memiliki mean yang sama dan varians sebagai n d k .
  • Solusinya harus mengandung jumlah gulungan yang kemungkinan terbesar kurang dari atau sama dengan r , karena lebih banyak gulungan menghasilkan distribusi yang lebih halus.
  • Anda harus membatasi solusi Anda hanya dengan menggunakan dadu sisi- k , kecuali jika Anda membidik Bonus (lihat di bawah).
  • Jika tidak ada solusi (karena r terlalu kecil), program harus menampilkan string "AKU SEXY SHOELESS GOD OF WAR!".
  • Parameter dilewatkan sebagai string yang dipisahkan oleh spasi.
  • Anda dapat berasumsi bahwa 1 ≤ n ≤ 100, 1 ≤ rn dan k adalah salah satu dari 4, 6, 8, 10, 12 dan 20 (dadu standar yang digunakan di permukaan meja).
  • Outputnya harus dalam format yang dijelaskan dalam Notasi (misalnya 4d6 * 10 + 5), dengan spasi opsional di sekitar + s tetapi tidak di tempat lain. Pengganda satuan juga opsional: 4d6 * 1 dan 4d6 keduanya valid.

Anda dapat menulis program atau fungsi, mengambil input melalui STDIN (atau alternatif terdekat), argumen baris perintah atau argumen fungsi. Hasil harus dicetak ke STDOUT (atau alternatif terdekat) atau dikembalikan sebagai string.

Contohnya

>> "10 6 10"
10d6
>> "10 6 4"
2d6*2+2d6+14
>> "10 6 3"
1d6*3+1d6+21
>> "10 6 2"
1d6*3+1d6+21
>> "10 6 1"
I AM A SEXY SHOELESS GOD OF WAR!

Mencetak gol

Kode terpendek menang. Aturan standar berlaku.

Bonus

-33% (dibulatkan sebelum pengurangan) jika program Anda juga mengembalikan solusi yang menyertakan dadu yang valid selain k (di mana nilai yang valid, seperti disebutkan di atas, adalah 4, 6, 8, 10, 12 dan 20). Jika Anda memilih untuk melakukannya, maka Anda harus selalu mengembalikan solusi seperti itu jika perlu, dan menangani solusi yang menggunakan banyak jenis cetakan. Contoh:

>> "7 4 3"
3d6+7
Uri Granta
sumber
6
+1 Untuk referensi OotS. ;) (Yah dan karena itu tantangan yang sangat menyenangkan, sebenarnya.)
Martin Ender
1
Mungkin menggunakan kemampuan $ \ LaTeX $ kami yang baru untuk mengumpulkan pertanyaan ini?
orlp
2
@UriZarfaty: Saya memperbarui formula Anda untuk menggunakan LaTeX. Semoga itu baik-baik saja. Jika Anda tidak menyukainya, Anda dapat memutar kembali posnya dan kembali seperti semula.
Alex A.
1
Saya telah memutar kembali hasil edit LaTeX, karena sayangnya, itu akan dinonaktifkan lagi untuk saat ini .
Martin Ender
1
#SadPanda - Saya pikir ini akan menjadi referensi kode tantangan untuk "Halo. Nama saya Inigo Montoya. Anda membunuh ayah saya. Bersiaplah untuk mati."
scunliffe

Jawaban:

5

GolfScript ( 163 143 133 byte)

~@:^\?,{^base 0-}%{0\{.*+}/^=},.{{,}$-1=..&{[[1$[1$]/,(3$@]'d*+'1/]zip}%^@{-}/@)*.2/\1&'.5'*}{];'I AM A SEXY SHOELESS GOD OF WAR!'}if

Demo online

Ketika tidak mencampur jenis dadu, masalah berkurang menjadi mengekspresikan nsebagai jumlah tidak lebih dari rkotak, dan ktidak relevan kecuali untuk perhitungan konstanta di akhir. Sebagian besar jawaban ini adalah pembukuan diperlukan untuk mengekspresikan hasil dalam format yang diinginkan: perhitungan yang sebenarnya adalah ^\?,{^base}%{0\{.*+}/^=},untuk menemukan faktor-faktor perkalian a, b, dll .; dan ^@{-}/@)*.2/untuk menghitung konstanta.

Pembedahan

~                # Stack: n k r
@:^\?,{          # Store n in ^, and for 0 to n**r
  ^base 0-       #   convert to base n and remove 0s.
}%               # Stack: k [arrays of up to r values from 1 to n-1]
{0\{.*+}/^=},    # Filter them to arrays whose sum of squares is n,
                 #   i.e. to multipliers which have the right variance
.{               # If any multiplier array passes the filter...
  {,}$-1=        #   Pick one with the greater number of rolls
                 #   Stack: k [multipliers]
  ..&{           #   Map each distinct multiplier a...
    [[           #     Gather in nested array for later zip
      1$[1$]/,(  #       Split a copy of the multipliers around a to count the as
                 #       Let's denote that count as m
                 #       Stack: k [multipliers] a [ [ m
      3$@        #       Copy k and rotate the a inside the nested array
     ]           #       Stack: k [multipliers] [ [m k a]
      'd*+'1/    #       Push an array ['d' '*' '+'] and close nested array
    ]zip         #       Giving [[m 'd'] [k '*'] [a '+']]
                 #       which will be printed as mdk*a+
  }%             #   Stack: k [multipliers] [string representations of dice]
  ^@{-}/@)*      #   Compute (n - sum(multipliers)) * (k + 1)
                 #   That's twice the constant we need to add to fix the mean
  .2/\1&'.5'*    #   And convert it to a renderable form, including .5 if needed
}{               # Otherwise clear the stack and push the error message
  ];'I AM A SEXY SHOELESS GOD OF WAR!'
}if
Peter Taylor
sumber
1

Python, 487 461 452 - 33% = 303 byte

Karena tidak ada orang lain yang melakukannya, berikut adalah solusi yang menangani berbagai jenis dadu. Seperti solusi lain, ia menghasilkan serangkaian solusi yang mungkin dan menyaringnya. Ia menggunakan fakta bahwa (k + 1) (k-1) = k ^ 2-1 dan dua celah semi dalam spec (oops!): Kurangnya larangan untuk mencetak bentuk berlebihan 0d k * a (yang menyimpan semua 5 byte!), dan kurangnya menjalankan pembatasan waktu (itu menjadi lambat cukup cepat, meskipun menjalankan semua contoh yang diberikan).

from itertools import*
N,K,R=map(int,input().split())
S=lambda l:sum([x[0]for x in l])
s=[x for x in product(*[[(n,k,a)for n in range(N*(K**2-1)/((k**2-1)*a**2)+1)]for a in range(1,N+1)for k in[4,6,8,10,12,20]if a**2<=N])if sum([n*(k**2-1)*a**2 for n,k,a in x])==N*K**2-N and S(x)<=R]
if s:s=max(s,key=S);print"+".join(["%sd%s*%s"%x for x in s]+[str(int(N*(K+1)/2.-sum([n*a*(k+1)/2.for n,k,a in s])))])
else:print"I AM A SEXY SHOELESS GOD OF WAR!"

Untuk hasil yang lebih cantik, tambahkan if x[0]setelah "%sd%s*%s"%x for x in s:

>> "7 4 3"
3d6+7
>> "10 6 3"
1d6*1+1d8*1+1d8*2+18
>> "10 6 2"
1d6*1+1d6*3+21
>> "10 6 1"
I AM A SEXY SHOELESS GOD OF WAR!
Uri Granta
sumber