No es tu máquina de frijoles de rutina

42

Considere esta versión ASCII de un mecanismo similar a una máquina de frijoles o un juego plinko / pachinko :

    O

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

El Oes una bola que se cae.

  • Cuando golpea a ^, hay una probabilidad de 50-50 de ir hacia la izquierda o hacia la derecha.
  • Cuando golpea a /, siempre sale a la izquierda.
  • Cuando golpea a \, siempre sale bien.

La pelota finalmente cae en uno de los Ucanales numerados en la parte inferior. La pregunta es, ¿cuál es la probabilidad de que termine en cada canal?

Para este caso particular, las probabilidades son 0.0, 0.1875, 0.5625, 0.125, y 0.125, en los canales de 1 a 5 respectivamente.

He aquí otro ejemplo con 3 canales en lugar de 5. Las probabilidades son 0.5, 0.5, y 0.0:

  O

  /
 ^ ^
U U U
1 2 3

En este desafío, generalizaremos este problema a un mecanismo con cualquier número de capas configuradas de cualquier manera.

Reto

Escriba un programa o función que tome la representación ASCII de la estructura piramidal del mecanismo. (Entrada a través de stdin / línea de comando / función arg.)

Puede suponer que viene con espacios que lo ponen en la forma adecuada, por ejemplo

   ^
  \ ^
 ^ ^ \
\ ^ / ^

O puede suponer que viene sin espacios, por ej.

^
\^
^^\
\^/^

(Si lo desea, puede suponer que hay una nueva línea final y / o algún patrón consistente de espacios finales).

La estructura de la pirámide de entrada puede tener cualquier número de niveles (también conocidos como líneas), incluido cero. Cada nivel tiene uno más ^, /o \que el anterior, y hay levels + 1canales en la parte inferior (que no son parte de la entrada).

Su programa / función debe imprimir / devolver la lista de las probabilidades de que la bola caiga en cada uno de los canales (en el orden de la izquierda a la derecha). Estos deben ser valores de coma flotante que, cuando se imprimen, tienen al menos 3 decimales (no se requieren ceros ni puntos decimales superfluos; 1está bien para 1.000, .5está bien para 0.500, etc.). Si escribió una función, puede imprimir los valores o devolver una lista / matriz de los flotantes.

Cualquier formato razonable de lista impresa está bien. por ejemplo 0.5 0.5 0.0, [0.5 0.5 0.0], [0.5, 0.5, 0.0], {0.5, 0.5, 0.0}, o 0.5\n0.5\n0.0todo estaría bien.

Ejemplos

0 niveles: (se reduce a un trivial U)

Entrada: [no input/empty string given]
Salida:1.0

1 nivel:

Entrada: ^
Salida:0.5 0.5

Entrada: /
Salida:1.0 0.0

Entrada: \
Salida:0.0 1.0

2 niveles: (segundo ejemplo anterior)

Entrada:

 /
^ ^

Salida: 0.5 0.5 0.0

3 niveles:

Entrada:

  ^
 ^ ^
^ ^ ^

Salida: 0.125 0.375 0.375 0.125

Entrada:

  \
 / \
/ / \

Salida: 0.0 0.0 0.0 1.0

4 niveles: (primer ejemplo anterior)

Entrada:

   ^
  \ ^
 ^ ^ \
\ ^ / ^

Salida: 0.0 0.1875 0.5625 0.125 0.125

7 niveles:

Entrada:

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

Salida: 0.0 0.09375 0.28125 0.4375 0.1875 0.0 0.0 0.0

Tanteo

La respuesta más corta en bytes gana. Tiebreaker es una publicación anterior.

Pasatiempos de Calvin
fuente
16
Quincunx había mejor responder a esta.
Aficiones de Calvin
"algún patrón consistente de espacios finales": ¿puedo suponer que los espacios finales en la enésima línea codifican la probabilidad de que la pelota caiga en el enésimo cubo?
Random832
44
@ Random832 No. (¿ Realmente crees que volaría?)
Calvin's Hobbies
Hay una razón por la que lo publiqué como un comentario en lugar de una respuesta. Simplemente pensé que era interesante cuán permisivo era este acertijo sobre la entrada; la mayoría de las que he visto dictan el formato de la entrada y / o salida de manera más estricta.
Random832
@ Random832: la entrada y la salida son muy inequívocas. Las lagunas estándar (como codificar la respuesta en la entrada) no necesitan ser abordadas en cada desafío.
Alex A.

Respuestas:

10

CJam, 50 48 45 44 42 40 bytes

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

Esto espera que la entrada no tenga espacio y tenga una nueva línea final. Por ejemplo:

^
\^
^^\
\^/^

[0 0.1875 0.5625 0.125 0.125]

Algoritmo

La idea básica es seguir analizando cada carácter (solo hay 4 caracteres diferentes) y realizar diferentes operaciones en la distribución de probabilidad (inicialmente una matriz que contiene 1 elemento de valor 1). Para cada fila de caracteres de entrada (comenzando con el primer carácter en la primera fila), mantenemos una matriz de probabilidad del mismo tamaño. Cada personaje actúa sobre la primera probabilidad de la lista y empuja el par resultante al final de la lista. Después de cada línea, sumamos pares de la lista para obtener el número exacto de elementos como los elementos de la siguiente línea.

Aquí están los cuatro caracteres y las acciones requeridas correspondientes a cada uno:

  • ^: Cuando se produce este personaje, divide la probabilidad actual en dos partes. Por ejemplo, si tenemos esto en la primera línea, tenemos que convertir el [1]a[0.5 0.5]
  • /: Cuando se produce este carácter, debemos <current probability> 0colocar la probabilidad actual en la matriz.
  • \: Cuando se produce este carácter, debemos 0 <current probability>colocar la probabilidad actual en la matriz.
  • \n: Cuando se produce este personaje, tenemos una nueva línea. Por lo tanto, agrupamos todos los pares de los 3 caracteres anteriores y los sumamos para obtener la probabilidad de cada elemento para la siguiente línea. Por ej. [0 0.5 0.25 0.25]se convierte a [0 0.75 0.25]. Tenga en cuenta que el primer y el último elemento tienen un par implícito (con valor 0) antes y después de ellos.

Ahora solo tenemos que identificar el personaje correcto y realizar la acción correcta. Vamos a usar las matemáticas habituales aquí para hacer eso. Los códigos ASCII para ^, \, /y \nson 94, 92, 47, y 10. Después de algunas pruebas, obtenemos esta ecuación simple para convertir estos números en 0, 1, 2 y 3:

"^\/
":ied13f%ed4f%ed

da:

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

En una matriz de longitud 4, la última 4f%sería implícita. Entonces, simplemente hacemos %13el código ASCII del personaje y elegimos la acción correcta de una serie de acciones.

Explicación del código :

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

Pruébalo en línea aquí

Optimizador
fuente
1
¿Cómo se prueba con 0 filas?
Trichoplax 05 de
1
@trichoplax debería funcionar ahora.
Optimizador de
Ahora funciona con entrada vacía :)
trichoplax
15

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

Función que toma como entrada la cadena (se puede formatear muy bien como una pirámide) y devuelve una matriz de flotantes.

Pruébelo en línea: http://ideone.com/kmsZMe

Implementación bastante sencilla. Aquí no tiene golf:

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
fuente
13

Ruby, 140158 bytes

No sigas votando esto cuando haya una mejor versión de ruby . Aquí hay más trucos para ti.

Función sin nombre con un argumento. No debe contener espacios. Puede o no contener una nueva línea final.

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

Pierde 9 bytes al tener que manejar 0 levels(cadena vacía). Todos los casos de prueba funcionan correctamente, vea aquí en ideone .

blutorange
fuente
44
El hecho de que haya una "mejor" respuesta de Ruby no significa que la suya (o cualquier otra respuesta de Ruby para el caso) no valga los votos. :)
Alex A.
Yo mismo voté porque contiene algunos buenos trucos. Me gusta tu multilínea split, por ejemplo.
Cristian Lupascu
12

Pyth, 43 42 41 bytes

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

Esto espera que la entrada esté sin espacios. Pruébelo en línea: Pyth Compiler / Executor

Pyth, 40 bytes (cuestionable)

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

Gracias a @isaacg, por guardar un byte. Tenga en cuenta que esta versión en realidad no funcionó en la versión de Pyth, cuando se hizo la pregunta. Hubo un pequeño error en el compilador. A pesar de que este código no usa nuevas características de Pyth (solo cosas que estuvieron en los documentos de Pyth durante mucho tiempo y deberían haber funcionado), esta podría no ser una respuesta válida. Decide por ti mismo.

Pruébelo en línea: Pyth Compiler / Executor

Explicación:

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

Por ejemplo, si actualmente tengo las probabilidades de entrada G = [0.5, 0.5, 0.0]y la fila H = "^/^"sucede lo siguiente:

  • cremallera ... [(0.5,"^"), (0.5,"/"), (0.0,"^")]
  • crear probabilidades de salida ... [[0.25,0.25], [0.5,0.0], [0.0, 0.0]]
  • 0 + suma ... [0, 0.25, 0.25, 0.5, 0.0, 0.0, 0.0]
  • picar ... [0,0.25], [0.25,0.5], [0.0,0.0], [0.0]]
  • suma ... [0.25, 0.75, 0.0, 0.0]
Jakube
fuente
3
Estaba tratando de jugar golf, y me llevó a un error en el compilador. El golf funciona, ahora que he arreglado el error. El golf consiste en reemplazar la lista de listas de 2 valores con una lista, y luego generar el otro valor restando el primer valor de hk. ,K@[ZJhkcJ2)x"\/"ek-JK
isaacg
1
Esta es realmente una línea muy fina cuando la reparación de un error no se cuenta como una versión más nueva del lenguaje (y, por lo tanto, sigue siendo válida para las preguntas formuladas antes de la corrección)
Optimizer
1
@Optimizer Tu derecho. Se agregaron algunas notas a la respuesta, que explican las circunstancias.
Jakube
2
@Optimizer En este caso, parece que una buena regla general es si realmente es una versión más nueva del idioma o una versión más nueva de la implementación del lenguaje que corrige un error, alineando la implementación con la especificación.
Destino
@Desty Por eso mencioné que es una línea muy fina;)
Optimizer
8

C #, 274 247 bytes

Nada sofisticado, programa completo que lee líneas (con o sin espacios, simplemente las elimina) desde STDIN e imprime resultados separados por espacios en 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));}}

Código ordenado con comentarios:

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

Pitón 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)

Actualiza repetidamente el vector de probabilidad Pen respuesta a cada línea. Este nuevo vector de probabilidad Qse crea una entrada a la vez. Itera a través de las nuevas ranuras, y calcula la contribución de la clavija a su derecha como r, al tiempo que calcula la contribución restante a la próxima ranura como p-r.

Espera que cada línea termine en al menos un espacio para evitar un problema en el que las líneas terminen en una barra invertida.

xnor
fuente
La entrada tendrá varias líneas, así que no creo que una sola input()pueda manejar eso.
randomra
no se requiere una nueva línea final para cada línea de la entrada.
Brian Minton
@randomra Escribí esto en Idle y funcionó bien colocando entradas de varias líneas en el indicador de comandos de shell.
xnor
6

Python 3, 138 bytes

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

Funciona con cualquier espacio en blanco, ya que todos se filtran (por if'!'<e).

Método:

  • Mantenemos una lista cada vez más amplia rde las probabilidades de alcanzar cualquier obstáculo y los canales implícitos debajo de ellos. Partimos de la lista [1].
  • Si estamos en el primer obstáculo consecutivo, debemos agregar un extra 0a la lista para el comedero principal. Decidimos si es el primer obstáculo comparando su índice pcon el siguiente número triangular t*-~t/2.
  • Para cada obstáculo agregamos su valor de lista parcialmente al último elemento y parcialmente a un nuevo elemento final. Dividimos el valor de lista en función del carácter de obstáculo ( ^:0.5 0.5; /:1 0; \:0 1). Usamos el siguiente método:
    • Tomar v = ord(char) mod 7 + 1ceder^:4 /:6 \:2
    • v div 3 / 2produce la primera fracción ( ^:0.5 /:1 \:0)
    • v mod 3 / 2produce la segunda fracción ( ^:0.5 /:0 \:1)
  • El resultado son los últimos t + 1elementos de la lista final r.

2 bytes gracias al consejo de chat de @ Sp3000.

randomra
fuente
4

Perl, 78

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

Toma entrada sin espacios.

Trate de mí .

nutki
fuente
1

TI-BASIC, 73 76

Toma entrada una línea a la vez y finaliza cuando se ingresa un espacio por sí solo, porque ni los saltos de línea en cadenas ni las cadenas vacías son legales en 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

Estoy bastante seguro de que obtuve el tamaño correcto (TI-BASIC está tokenizado, por lo que cada comando toma uno o dos bytes: seq () toma uno, inString () toma dos, dim () toma uno, y así sucesivamente. I contó el tamaño manualmente).

Aunque el carácter de barra diagonal inversa es válido en una cadena, tenga en cuenta que no hay forma de ingresar uno desde el interior del programa a menos que haya modificado su calculadora.

lirtosiast
fuente
0

Javascript - 117

Intenté usar la recursión, pero eso fue demasiado largo ...

Sombrero de punta a xnor para la idea de resta, que afeitó a una docena o más de personajes.

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}

Sin golf:

// 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;
}
No es que Charles
fuente