Не ваша машина звичайних бобів


42

Розглянемо ASCII версію механізму , схожого з бобової машини або plinko / пачинко гри:

    O

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

OКуля , який падає вниз.

  • Коли він потрапляє на a ^, є 50-50 шансів, що він піде вліво або вправо.
  • Коли він потрапляє на a /, він завжди йде ліворуч.
  • Коли він потрапляє на a \, він завжди йде правильно.

Зрештою куля потрапляє в одне з пронумерованих Uжолобів на дні. Питання полягає в тому, яка ймовірність, що вона закінчиться в кожному кориті?

Для цього конкретного випадку, ймовірно є 0.0, 0.1875, 0.5625, 0.125і 0.125, по жолобах з 1 по 5 відповідно.

Ось ще один приклад з 3 западинами замість 5. Вірогідність є 0.5, 0.5, і 0.0:

  O

  /
 ^ ^
U U U
1 2 3

У цьому виклику ми узагальнимо цю проблему до механізму з будь-якою кількістю шарів, встановлених будь-яким способом.

Виклик

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

Ви можете припустити, що він поставляється з пробілами, які приводять його в належну форму, наприклад

   ^
  \ ^
 ^ ^ \
\ ^ / ^

Або ви можете припустити, що він входить зовсім без пробілів, наприклад

^
\^
^^\
\^/^

(За бажанням, ви можете припустити, що існує затримка нового рядка та / або деякий узгоджений шаблон пробілів.

Структура вхідної піраміди може мати будь-яку кількість рівнів (ака-ліній), включаючи нуль. Кожен рівень має ще один ^, /або \чим останній, і є levels + 1западини на день (які не є частиною введення).

Ви програма / функція повинні надрукувати / повернути список ймовірностей того, що кулька приземлиться у кожному з жолобів (у порядку, що знаходиться вліво, до крайнього правого корита). Це мають бути значення з плаваючою комою, які при друкуванні містять щонайменше 3 десяткових знаки (зайві нулі чи десяткові крапки не потрібні; 1це нормально 1.000, .5добре для 0.500тощо). Якщо ви написали функцію, ви можете надрукувати значення або повернути список / масив плавців.

Будь-який розумний формат друкованого списку - це добре. наприклад 0.5 0.5 0.0, [0.5 0.5 0.0], [0.5, 0.5, 0.0], {0.5, 0.5, 0.0}або 0.5\n0.5\n0.0все буде в порядку.

Приклади

0 Рівні: (зводиться до однієї тривіальної U)

Вхід: [no input/empty string given]
Вихід:1.0

1 рівень:

Вхід: ^
Вихід:0.5 0.5

Вхід: /
Вихід:1.0 0.0

Вхід: \
Вихід:0.0 1.0

2 рівня: (другий приклад вище)

Вхід:

 /
^ ^

Вихід: 0.5 0.5 0.0

3 рівня:

Вхід:

  ^
 ^ ^
^ ^ ^

Вихід: 0.125 0.375 0.375 0.125

Вхід:

  \
 / \
/ / \

Вихід: 0.0 0.0 0.0 1.0

4 рівня: (перший приклад вище)

Вхід:

   ^
  \ ^
 ^ ^ \
\ ^ / ^

Вихід: 0.0 0.1875 0.5625 0.125 0.125

7 рівнів:

Вхід:

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

Вихід: 0.0 0.09375 0.28125 0.4375 0.1875 0.0 0.0 0.0

Оцінка балів

Виграє найкоротша відповідь у байтах. Tiebreaker - це раніше повідомлення.


16
Quincunx було краще відповісти на цей питання .
Хобі Кальвіна

"деякий узгоджений зразок пробілів" - чи можу я припустити, що проміжки проміжків на N-й лінії кодують ймовірність того, що куля приземлиться в N-му відро?
Випадково832

4
@ Random832 Ні. (Ви справді думаєте, що полетіло б?)
Захоплення Кальвіна

Є причина, що я розмістив це як коментар замість відповіді. Мені просто здалося, що цікаво, наскільки вседозволена ця головоломка щодо введення даних - більшість, що я бачив, диктують формат введення та / або виводу більш суворо.
Випадково832

@ Random832: Введення та вихід дуже однозначні. Стандартні лазівки (наприклад, кодування відповіді на вводі) не потребують вирішення у кожному виклику.
Олексій А.

Відповіді:


10

CJam, 50 48 45 44 42 40 байт

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

Це очікує, що вхід не буде пробілом і матиме зворотний новий рядок. Наприклад:

^
\^
^^\
\^/^

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

Алгоритм

Основна ідея полягає в тому, що ви продовжуєте аналізувати кожен символ (у ньому всього 4 різних символи) і виконувати різні операції з розподілу ймовірностей (спочатку масив, що містить 1 елемент значення 1). Для кожного рядка вхідних символів (починаючи з першого символу в першому рядку) ми підтримуємо масив ймовірностей такого ж розміру. Кожен символ діє за першою ймовірністю зі списку і штовхає отриману пару до кінця списку. Після кожного рядка ми підсумовуємо пари зі списку, щоб отримати точну кількість елементів як елементів у наступному рядку.

Ось чотири символи та необхідні дії, відповідні кожному:

  • ^: Коли цей символ виникає, ви розділите поточну ймовірність на дві частини. Наприклад, якщо у нас це є в першому рядку, ми повинні перетворити [1]на[0.5 0.5]
  • /: Коли це символи трапляються, ми маємо поставити <current probability> 0місце поточної ймовірності в масиві.
  • \: Коли це символи трапляються, ми маємо поставити 0 <current probability>місце поточної ймовірності в масиві.
  • \n: Коли цей персонаж виникає, у нас з'являється новий рядок. Таким чином, ми групуємо всі пари вище 3 символів і підсумовуємо їх, щоб отримати ймовірність кожного елемента для наступного рядка. Для екс. [0 0.5 0.25 0.25]перетворюється на [0 0.75 0.25]. Зауважте, що перший та останній елементи мають неявну пару (оцінюється 0) до і після них.

Тепер нам залишається лише визначити правильний персонаж і виконати правильну дію. Дозвольте тут використовувати звичайну математику. В ASCII - коди ^, \, /і \nє 94, 92, 47, і 10. Після кількох випробувань ми отримуємо це просте рівняння для перетворення цих чисел у 0, 1, 2 і 3:

"^\/
":ied13f%ed4f%ed

дає:

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

У масиві довжиною 4 остання 4f%буде неявною. Тому ми просто робимо %13ASCII код символу і вибираємо правильну дію з масиву дій.

Пояснення коду :

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

Спробуйте його онлайн тут


1
Як ви тестуєте це з 0 рядками?
трихоплакс

1
@trichoplax має працювати зараз.
Оптимізатор

Він працює зараз із порожнім входом :)
trichoplax

15

Рубін 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}

Функція, яка приймає за введення рядок (може бути добре відформатована як піраміда) і повертає масив поплавків.

Перевірте це в Інтернеті: http://ideone.com/kmsZMe

Досить просто реалізація. Ось це невольф:

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
}

13

Рубі, 140 158 байт

Не продовжуйте озвучувати це, коли є краща версія для рубіну . Ось ще трюки для вас.

Безіменна функція з одним аргументом. Не повинно містити пробілів. Може містити або не містити зворотного нового рядка.

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

Витрачає 9 байт на обробку 0 levels(порожній рядок). Всі тестові справи працюють правильно, дивіться тут на ideone .


4
Тільки тому, що "краща" відповідь Рубі не означає, що ваша (або будь-яка інша відповідь Рубі з цього приводу) не варто голосувати. :)
Олексій А.

Я сам це схвалив, бо він містить деякі приємні хитрощі. Мені подобається, наприклад, ваша багаторядкова splitлінія.
Крістіан Лупаску

12

Pyth, 43 42 41 байт

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

Це очікує, що вхід не буде пробілами. Спробуйте в Інтернеті: Pyth Compiler / Executor

Pyth, 40 байт (сумнівно)

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

Завдяки @isaacg за збереження одного байта. Зауважте, що ця версія насправді не працювала у версії Pyth, коли питання було задано. У компіляторі виявився крихітний помилок. Незважаючи на те, що цей код не використовує нових можливостей Pyth (лише ті матеріали, які довгий час були в документах Pyth і повинні були працювати), це може бути неправдивою відповіддю. Вирішіть самі.

Спробуйте в Інтернеті: Pyth Compiler / Executor

Пояснення:

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

Наприклад, якщо у мене зараз є вхідні ймовірності G = [0.5, 0.5, 0.0]і рядок, H = "^/^"відбувається таке:

  • zip ... [(0.5,"^"), (0.5,"/"), (0.0,"^")]
  • створити вихідні ймовірності ... [[0.25,0.25], [0.5,0.0], [0.0, 0.0]]
  • 0 + сума ... [0, 0.25, 0.25, 0.5, 0.0, 0.0, 0.0]
  • рубати ... [0,0.25], [0.25,0.5], [0.0,0.0], [0.0]]
  • сума ... [0.25, 0.75, 0.0, 0.0]

3
Я намагався це зробити в гольф, і це призвело до помилок у компіляторі. Гольф працює, тепер, коли я виправив помилку. Гольф повинен замінити список двозначних списків одним списком, а потім генерувати інше значення, віднімаючи перше значення від hk. ,K@[ZJhkcJ2)x"\/"ek-JK
isaacg

1
Це дійсно тонка лінія, коли виправлення помилки не зараховується до нової версії мови (і, таким чином, все ще дійсна для питань, заданих перед виправленням)
Optimizer

1
@Optimizer Ваше право. До відповіді додано кілька приміток, які пояснюють обставини.
Якубе

2
@Optimizer У цьому випадку здається, що хорошим правилом є те, чи справді це новіша версія мови чи новіша версія мовної реалізації, яка виправляє помилку, приводячи реалізацію ближче до специфікації.
Десті

@Desty Саме тому я згадав, що це тонка лінія;)
оптимізатор

8

C #, 274 247 байт

Нічого фантазійного, повна програма, яка читає рядки (з пробілами або без них, вона просто знімає їх) зі STDIN і друкує результати, розділені пробілом, на 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));}}

Код Тідьє з коментарями:

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

7

Пітон 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)

Неодноразово оновлює вектор ймовірності Pу відповідь на кожен рядок. Цей новий вектор вірогідності Qстворюється одночасно. Ітератується через нові слоти і обчислює внесок від прив’язки праворуч як r, а також обчислюючи решту внесок у майбутній слот як p-r.

Очікує, що кожен рядок закінчиться принаймні в одному просторі, щоб уникнути проблеми, коли рядки закінчуються на зворотному куті.


Вхід матиме декілька рядків, тому я не думаю, що жоден input()може впоратися з цим.
randomra

останній рядок не потрібен для кожного рядка вводу.
Брайан Мінтон

@randomra Я написав це в режимі очікування, і він спрацював чудово, вводячи багаторядкові введення в підказку оболонки.
xnor

6

Пітон 3, 138 байт

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:]

Працює з будь-якими пробілами, оскільки всі вони відфільтровані (за if'!'<e).

Спосіб:

  • Ми зберігаємо постійно розширюється перелік rймовірностей досягнення будь-яких перешкод та неявних жолобів під ними. Починаємо зі списку [1].
  • Якщо ми перебуваємо на першій перешкоді поспіль, нам потрібно додати додатковий 0список до головного корита. Ми вирішуємо, чи це перша перешкода, порівнявши її індекс pіз наступним трикутним числом t*-~t/2.
  • Для кожної перешкоди ми додаємо її значення списку частково до останнього елемента та частково до нового останнього елемента. Ділимо значення списку на основі символу перешкоди ( ^:0.5 0.5; /:1 0; \:0 1). Ми використовуємо наступний метод:
    • Візьміть v = ord(char) mod 7 + 1урожайність^:4 /:6 \:2
    • v div 3 / 2виходить перша фракція ( ^:0.5 /:1 \:0)
    • v mod 3 / 2виходить друга фракція ( ^:0.5 /:0 \:1)
  • Результат - останні t + 1елементи остаточного списку r.

2 байти завдяки пораді в чаті @ Sp3000.


4

Перл, 78

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

Здійснює введення даних без пробілів.

Спробуй мене .


1

TI-BASIC, 73 76

Здійснює введення по одному рядку за один раз і закінчується, коли пробіл вводиться самостійно, оскільки жоден розрив рядків у рядках та порожні рядки не є законними в 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

Я впевнений, що я отримав правильний розмір (TI-BASIC є токенізованим, тому кожна команда бере один або два байти - seq () бере один, inString () займає два, dim () займає один, і так далі. I підраховували розмір вручну.)

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


0

Javascript - 117

Спробував за допомогою рекурсії, але це було занадто довго ...

Капелюх підказка xnor для ідеї віднімання, яка збрила десяток і більше символів.

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}

Безголівки:

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