Bukan Mesin Kacang Rutin Anda

42

Pertimbangkan versi ASCII ini dari mekanisme yang mirip dengan mesin bean atau game plinko / pachinko :

    O

    ^
   \ ^
  ^ ^ \
 \ ^ / ^
U U U U U
1 2 3 4 5

The Oadalah bola yang jatuh ke bawah.

  • Ketika itu mengenai ^, ada kemungkinan 50-50 itu akan ke kiri atau kanan.
  • Ketika itu mengenai /, itu selalu pergi ke kiri.
  • Ketika hits \, itu selalu berjalan dengan benar.

Bola akhirnya jatuh ke salah satu Upalung bernomor di bagian bawah. Pertanyaannya adalah, berapa probabilitasnya pada setiap palung?

Untuk kasus ini, probabilitas yang 0.0, 0.1875, 0.5625, 0.125, dan 0.125, untuk palung 1 sampai 5 masing-masing.

Berikut contoh lain dengan 3 palung bukannya 5. Probabilitas adalah 0.5, 0.5, dan 0.0:

  O

  /
 ^ ^
U U U
1 2 3

Dalam tantangan ini kami akan menggeneralisasikan masalah ini ke suatu mekanisme dengan sejumlah lapisan yang diatur dengan cara apa pun.

Tantangan

Tulis program atau fungsi yang mengambil representasi ASCII dari struktur piramida mekanisme. (Input melalui stdin / baris perintah / fungsi arg.)

Anda dapat mengasumsikan itu datang dengan spasi yang menempatkannya dalam bentuk yang tepat, misalnya

   ^
  \ ^
 ^ ^ \
\ ^ / ^

Atau Anda dapat menganggapnya masuk tanpa spasi sama sekali, misalnya

^
\^
^^\
\^/^

(Jika diinginkan, Anda dapat mengasumsikan ada garis baru dan / atau beberapa pola spasi yang konsisten.)

Struktur piramida input dapat memiliki sejumlah level (alias garis), termasuk nol. Setiap level memiliki satu lagi ^,, /atau \dari yang terakhir, dan ada levels + 1palung di bagian bawah (yang bukan bagian dari input).

Program / fungsi Anda harus mencetak / mengembalikan daftar probabilitas bahwa bola mendarat di setiap palung (dalam urutan palung paling kiri ke palung paling kanan). Ini harus berupa nilai titik apung yang, ketika dicetak, memiliki setidaknya 3 tempat desimal (nol berlebihan atau titik desimal tidak diperlukan; 1baik untuk 1.000, .5baik untuk 0.500, dll.). Jika Anda menulis suatu fungsi, Anda dapat mencetak nilai atau mengembalikan daftar / larik float.

Format daftar cetak yang masuk akal baik-baik saja. misalnya 0.5 0.5 0.0, [0.5 0.5 0.0], [0.5, 0.5, 0.0], {0.5, 0.5, 0.0}, atau 0.5\n0.5\n0.0semua akan baik-baik saja.

Contohnya

0 Level: (bermuara pada satu hal sepele U)

Input: [no input/empty string given]
Keluaran:1.0

1 Tingkat:

Input: ^
Keluaran:0.5 0.5

Input: /
Keluaran:1.0 0.0

Input: \
Keluaran:0.0 1.0

2 Tingkat: (contoh kedua di atas)

Memasukkan:

 /
^ ^

Keluaran: 0.5 0.5 0.0

3 Tingkat:

Memasukkan:

  ^
 ^ ^
^ ^ ^

Keluaran: 0.125 0.375 0.375 0.125

Memasukkan:

  \
 / \
/ / \

Keluaran: 0.0 0.0 0.0 1.0

4 Tingkat: (contoh pertama di atas)

Memasukkan:

   ^
  \ ^
 ^ ^ \
\ ^ / ^

Keluaran: 0.0 0.1875 0.5625 0.125 0.125

7 Tingkat:

Memasukkan:

      ^
     / ^
    ^ ^ /
   / \ / \
  ^ ^ / ^ \
 ^ \ ^ \ / ^
\ ^ ^ ^ \ ^ /

Keluaran: 0.0 0.09375 0.28125 0.4375 0.1875 0.0 0.0 0.0

Mencetak gol

Jawaban terpendek dalam byte menang. Tiebreaker adalah posting sebelumnya.

Hobi Calvin
sumber
16
Quincunx telah lebih baik menjawab ini.
Calvin Hobbies
"beberapa pola spasi trailing yang konsisten" - dapatkah saya berasumsi bahwa ruang trailing pada garis N menyandikan probabilitas bola untuk mendarat di ember Nth?
Random832
4
@ Random832 No. (Apakah Anda benar-benar berpikir itu akan terbang?)
Hobi Calvin
Ada alasan saya mempostingnya sebagai komentar dan bukan jawaban. Saya hanya berpikir itu menarik betapa permisif teka-teki ini tentang input - sebagian besar yang saya lihat mendikte format input dan / atau output lebih ketat.
Random832
@ Random832: Input dan output sangat jelas. Celah standar (seperti menyandikan jawaban pada input) tidak perlu ditangani dalam setiap tantangan.
Alex A.

Jawaban:

10

CJam, 50 48 45 44 42 40 byte

1]q{iD%"(+0 0+( (\Y/::+ (d2/_a+"S/=~+}/p

Ini mengharapkan input menjadi tanpa ruang dan memiliki baris baru. Sebagai contoh:

^
\^
^^\
\^/^

[0 0,1875 0,5625 0,125 0,125]

Algoritma

Ide dasarnya adalah bahwa Anda terus mengurai setiap karakter (hanya ada 4 karakter yang berbeda) dan melakukan operasi yang berbeda pada distribusi probabilitas (awalnya sebuah array yang mengandung 1 elemen nilai 1). Untuk setiap baris karakter input (dimulai dengan karakter pertama di baris pertama), kami mempertahankan array probabilitas dengan ukuran yang sama. Setiap karakter bertindak berdasarkan probabilitas pertama dari daftar dan mendorong pasangan yang dihasilkan ke akhir daftar. Setelah setiap baris, kami menjumlahkan pasangan dari daftar untuk mendapatkan jumlah item yang tepat sebagai item pada baris berikutnya.

Berikut adalah empat karakter dan tindakan yang diperlukan yang sesuai untuk masing-masing:

  • ^: Ketika karakter ini terjadi, Anda membagi probabilitas saat ini menjadi dua bagian. Misalnya, jika kita memiliki ini di baris pertama, kita harus mengonversikan [1]ke[0.5 0.5]
  • /: Ketika karakter ini muncul, kita harus menempatkan <current probability> 0probabilitas saat ini dalam array.
  • \: Ketika karakter ini muncul, kita harus menempatkan 0 <current probability>probabilitas saat ini dalam array.
  • \n: Ketika karakter ini muncul, kami memiliki baris baru. Dengan demikian kami mengelompokkan semua pasangan dari 3 karakter di atas dan menjumlahkannya untuk mendapatkan probabilitas setiap item untuk baris berikutnya. Misalnya [0 0.5 0.25 0.25]dikonversi menjadi [0 0.75 0.25]. Perhatikan bahwa item pertama dan terakhir memiliki pasangan implisit (dihargai 0) sebelum dan sesudahnya.

Sekarang kita hanya perlu mengidentifikasi karakter yang tepat dan melakukan tindakan yang benar. Mari kita gunakan matematika biasa di sini untuk melakukan itu. Kode ASCII untuk ^, \, /dan \nadalah 94, 92, 47, dan 10. Setelah beberapa percobaan, kami mendapatkan persamaan sederhana ini untuk mengubah angka-angka ini menjadi 0, 1, 2 dan 3:

"^\/
":ied13f%ed4f%ed

memberi:

Stack: [[94 92 47 10]]
Stack: [[3 1 8 10]]
Stack: [[3 1 0 2]]
3102

Dalam array dengan panjang 4, yang terakhir 4f%akan menjadi implisit. Jadi kita cukup lakukan %13pada kode ASCII dari karakter dan memilih tindakan yang tepat dari berbagai tindakan.

Penjelasan kode :

1]                                 e# Initial probability array with 1 probability
  q{                          }/   e# Read the whole input and iterate char by char
    iD%                            e# mod the ASCII code of the character with 13
"(+0 0+( (\Y/::+ (d2/_a+"S/        e# This is our actions array in order of [\ / \n ^]
                           =~      e# We pick the correct action and eval it
                             +     e# Evaling each action will leave one number out of the
                                   e# pairs out of the array. So we put it back in
                                p  e# Print the final probability array

Cobalah online di sini

Pengoptimal
sumber
1
Bagaimana Anda mengujinya dengan 0 baris?
trichoplax
1
@trichoplax harus bekerja sekarang.
Pengoptimal
Ini bekerja sekarang dengan input kosong :)
trichoplax
15

Ruby 140

->s{r=[1.0]
s.lines.map{|l|n=[i=0.0]*(r.size+1)
l.scan(/\S/).map{|e|a,b=e>?/?e>?]?[0.5]*2:[0,1]:[1,0]
z=r[i]
n[i]+=z*a
n[i+=1]+=z*b}
r=n}
r}

Fungsi yang mengambil input string (dapat diformat dengan baik sebagai piramida) dan mengembalikan array pelampung.

Uji secara online: http://ideone.com/kmsZMe

Implementasi yang cukup mudah. Ini dia ungolfed:

F = -> input {
  probabilities = [1.0]

  input.lines.each { |line|

    new_probabilities = [0.0] * (probabilities.size+1)
    elements = line.scan /\S/
    elements.map.with_index{|el, i|
      deltas = el > '/' ? (el > ']' ? [0.5,0.5] : [0,1]) : [1,0]

      d1, d2 = deltas

      new_probabilities[i] += probabilities[i] * d1
      new_probabilities[i + 1] += probabilities[i] * d2
    }
    probabilities = new_probabilities
  }
  return probabilities
}
Cristian Lupascu
sumber
13

Ruby, 140 158 byte

Jangan terus memilih ini ketika ada versi ruby ​​yang lebih baik . Ini ada lebih banyak trik untuk Anda.

Fungsi tanpa nama dengan satu argumen. Tidak boleh mengandung spasi apa pun. Mungkin atau mungkin tidak mengandung baris baru.

->s{Z=(s.split'
')<<[]
K=[]
F=->i,j,f{k=Z[i][j]
K[i]||=0
k==?^?2.times{|m|F[i+1,j+m,f/2]}:!k ?K[j]+=f :F[i+1,j+(k==?/?0:1),f]}
F[0,0,1.0]
K}

Membuang 9 byte karena harus menangani 0 levels(string kosong). Semua test case bekerja dengan benar, lihat di sini di ideone .

blutorange
sumber
4
Hanya karena ada jawaban Ruby "yang lebih baik" tidak berarti jawaban Anda (atau jawaban Ruby lainnya) tidak pantas dinilai. :)
Alex A.
Saya membatalkan ini sendiri karena mengandung beberapa trik yang bagus. Saya suka multiline Anda split, misalnya.
Cristian Lupascu
12

Pyth, 43 42 41 byte

umsdc+0sm@c[ZJhkJZKcJ2K)2x"\/"ekC,GH2.z]1

Ini mengharapkan input tanpa spasi. Cobalah secara online: Pyth Compiler / Executor

Pyth, 40 byte (dipertanyakan)

umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1

Terima kasih kepada @isaacg, karena telah menghemat satu byte. Perhatikan bahwa versi ini tidak benar-benar berfungsi dalam versi Pyth, ketika pertanyaan diajukan. Ada bug kecil di kompiler. Meskipun kode ini tidak menggunakan fitur baru Pyth (hanya hal-hal yang sudah ada dalam dokumen Pyth untuk waktu yang lama dan seharusnya berfungsi), ini mungkin bukan jawaban yang valid. Putuskan sendiri.

Cobalah secara online: Pyth Compiler / Executor

Penjelasan:

umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1   
u                                   .z]1  reduce G, starting with G = [1], for H in all_input():
                               C,GH         zip(G,H)
        m                                   map each pair k to:
            [ZJhkcJ2)                         create a list [0, k[0], k[0]/2]
                     x"\/"ek                  index of k[1] in "\/" (-1 for "^")
          K@                                  take the correspondent element of the list and store in K
         ,                  -JK               create a pair (K, k[0]-K)                                                      
     +0s                                    sum and insert 0 at the begin
    c                              2        chop into pairs
 msd                                        sum up each pair
                                            G gets updated with this new list

Misalnya jika saya saat ini memiliki probabilitas input G = [0.5, 0.5, 0.0]dan baris H = "^/^"yang terjadi sebagai berikut:

  • zip ... [(0.5,"^"), (0.5,"/"), (0.0,"^")]
  • buat probabilitas keluaran ... [[0.25,0.25], [0.5,0.0], [0.0, 0.0]]
  • 0 + jumlah ... [0, 0.25, 0.25, 0.5, 0.0, 0.0, 0.0]
  • memotong ... [0,0.25], [0.25,0.5], [0.0,0.0], [0.0]]
  • jumlah ... [0.25, 0.75, 0.0, 0.0]
Jakube
sumber
3
Saya mencoba bermain golf ini, dan itu membawa saya ke bug di kompiler. Golf berfungsi, sekarang saya sudah memperbaiki bug. Golf adalah untuk mengganti daftar daftar 2-nilai dengan satu daftar, dan kemudian menghasilkan nilai lainnya dengan mengurangi nilai pertama dari hk. ,K@[ZJhkcJ2)x"\/"ek-JK
isaacg
1
Ini benar-benar garis yang bagus ketika Anda memperbaiki bug tidak dihitung sebagai versi bahasa yang lebih baru (dan dengan demikian masih berlaku untuk pertanyaan yang diajukan sebelum perbaikan)
Pengoptimal
1
@Optimizer Hak Anda. Menambahkan beberapa catatan pada jawabannya, yang menjelaskan situasinya.
Jakube
2
@Optimizer Dalam kasus ini, sepertinya aturan praktis yang baik adalah apakah itu benar-benar versi bahasa yang lebih baru atau versi yang lebih baru dari implementasi bahasa yang memperbaiki bug, membawa implementasi lebih dekat dengan spesifikasi.
Desty
@ Kejujuran Itulah sebabnya saya menyebutkan bahwa ini garis yang bagus;)
Pengoptimal
8

C #, 274 247 byte

Tidak ada yang mewah, program lengkap yang membaca garis (dengan atau tanpa spasi, hanya menghapusnya) dari STDIN, dan mencetak hasil yang dipisahkan ruang ke STDOUT.

using Q=System.Console;class P{static void Main(){decimal[]k={1},t;string L;for(int l=0,i;(L=Q.ReadLine())!=null;k=t)for(L=L.Replace(" ",""),t=new decimal[++l+1],i=0;i<l;)t[i]+=k[i]-(t[i+1]=(8-L[i]%8)/2*k[i++]/2);Q.WriteLine(string.Join(" ",k));}}

Kode lebih rapi dengan komentar:

using Q=System.Console;

class P
{
    // / 47
    // \ 92
    // ^ 94

    static void Main()
    {
        decimal[]k={1},t; // k is old array, t is new array

        string L; // L is the current line, R is the current result (1 if no rows)
        for(int l=0,i; // l is length of old array, i is index in old array
            (L=Q.ReadLine())!=null; // for each line of input
            k=t) // swap array over
            for(L=L.Replace(" ",""), // remove spaces
                t=new decimal[++l+1], // create a new array
                i=0;

                i<l;) // for each position

                t[i]+=k[i]-( // add to left position (for last time)
                        t[i+1]=(8-L[i]%8)/2*k[i++]/2 // assign right position (k is decimal)
                    );

        Q.WriteLine(string.Join(" ",k)); // print result
    }
}
VisualMelon
sumber
7

Python 3, 113

P=[1]
for C in input().split():
 l,*Q=0,
 for p,c in zip(P,C):r=p*"\^/".find(c)/2;Q+=l+r,;l=p-r
 P=Q+[l]
print(P)

Pembaruan vektor probabilitas secara berulang Pdalam menanggapi setiap baris. Vektor probabilitas baru Qini dibuat satu entri pada satu waktu. Iterasi melalui slot baru, dan hitung kontribusi dari pasak ke kanan sebagai r, sementara juga menghitung kontribusi yang tersisa untuk slot yang akan datang sebagai p-r.

Mengharapkan setiap baris berakhir di setidaknya satu ruang untuk menghindari masalah di mana garis berakhir dengan garis miring terbalik.

Tidak
sumber
Input akan memiliki beberapa baris jadi saya tidak berpikir satu pun input()bisa mengatasinya.
randomra
baris tambahan tidak diperlukan untuk setiap baris input.
Brian Minton
@randomra Saya menulis ini di Idle dan bekerja dengan baik memasukkan input multi-line ke prompt shell.
xnor
6

Python 3, 138 byte

def f(s):
 r=[1];p=t=0
 for e in s:
  if'!'<e:b=p==t*-~t/2;r+=[0]*b;t+=b;v=ord(e)%7+1;a=r[p]/2;r[-1]+=v//3*a;r+=v%3*a,;p+=1
 return r[~t:]

Bekerja dengan spasi putih karena mereka semua disaring (oleh if'!'<e).

Metode:

  • Kami terus mengembangkan daftar rprobabilitas untuk mencapai hambatan dan palung implisit di bawahnya. Kami mulai dari daftar [1].
  • Jika kita berada pada hambatan pertama berturut-turut, kita perlu menambahkan ekstra 0ke daftar untuk palung terkemuka. Kami memutuskan apakah ini merupakan hambatan pertama dengan membandingkan indeksnya pdengan angka segitiga berikutnya t*-~t/2.
  • Untuk setiap hambatan kami menambahkan nilai daftar sebagian ke elemen terakhir dan sebagian ke elemen trailing baru. Kami membagi nilai daftar berdasarkan karakter kendala ( ^:0.5 0.5; /:1 0; \:0 1). Kami menggunakan metode berikut:
    • Ambil v = ord(char) mod 7 + 1hasil^:4 /:6 \:2
    • v div 3 / 2menghasilkan fraksi pertama ( ^:0.5 /:1 \:0)
    • v mod 3 / 2menghasilkan fraksi kedua ( ^:0.5 /:0 \:1)
  • Hasilnya adalah t + 1elemen terakhir dari daftar akhir r.

2 byte berkat saran obrolan @ Sp3000.

randomra
sumber
4

Perl, 78

#!perl -p0a
@r=($/=1);$^=.5;@r=map$r-$l+($l=$$_*($r=shift@r)),/./g,$r=$l=0for@F;$_="@r"

Mengambil input tanpa spasi.

Coba saya .

nutki
sumber
1

TI-BASIC, 73 76

Mengambil input satu baris pada satu waktu, dan berakhir ketika spasi dimasukkan dengan sendirinya, karena tidak ada putus baris dalam string atau string kosong yang sah dalam TI-BASIC.

{1→X
Input Str1
While Str1≠"  //one space
.5seq(inString("^/",sub(Str1,I,1)),I,1,dim(Ans
augment(Ans∟X,{0})+augment({0},∟X-∟XAns→X
Input Str1
End
∟X

Saya cukup yakin saya mendapatkan ukuran yang benar (TI-BASIC adalah tokenized, jadi setiap perintah mengambil satu atau dua byte — seq () mengambil satu, inString () mengambil dua, redup () membutuhkan satu, dan seterusnya. Saya menghitung ukuran secara manual.)

Meskipun karakter backslash valid dalam sebuah string, perhatikan bahwa tidak ada cara untuk memasukkan satu dari dalam program kecuali Anda telah memodifikasi kalkulator Anda.

lirtosiast
sumber
0

Javascript - 117

Sudah mencoba menggunakan rekursi, tapi itu terlalu lama ...

Hat tip untuk xnor untuk ide pengurangan, yang mencukur selusin atau lebih karakter.

w=s=>{a=[1];s.split('\n').map(m=>{for(b=[i=0];z=a[i],f=m[i];b[i++]+=z-b[i])b[i+1]=f>']'?z/2:f<':'?0:z;a=b})
return a}

Tidak Disatukan:

// s must not have spaces
w=s=>{
  // a is the current probability array
  a=[1];
  s.split('\n').map(
    // for each row of input...
    m=>{
      b=[0];  // b is the next row's probability array
      for(i=0; i<m.length;){
        z=a[i]; // z = probability
        f=m[i]; // f = letter
                                  // let's assume i == 0
        b[i+1] = (f>']') ? z/2 :  // if f == '^', b[1] = z/2
          (f<':' ? 0 :            // else if f == '/', b[1] = 0 
            z);                   // else b[1] = z
        b[i++]+=z-b[i];           // then add (z-b[1]) to b[0]
      }
      a=z-b    // increment current probability array
    }
  )
  return a;
}
Bukan itu Charles
sumber