Uma máquina de feijão magra e média

26

Um exemplo clássico para apresentar às pessoas o conceito de uma distribuição de probabilidade discreta é a máquina de feijão . Essa máquina tem uma grande quantidade de bolas de gude caindo de uma passagem estreita no topo, após o que atingem fileiras de pinos entrelaçados, onde em cada pino o mármore bate, pode cair à esquerda ou à direita do pino. Finalmente, os pinos são coletados em caixas verticais na parte inferior da máquina. Um diagrama simples desta máquina é assim:

|     O     |
|     ^     |
|    ^ ^    |
|   ^ ^ ^   |
|  ^ ^ ^ ^  |
| ^ ^ ^ ^ ^ |
|_|_|_|_|_|_|

Neste diagrama, o Osignifica o local de onde os mármores caem. Cada ^um deles é um alfinete no qual o mármore tem 50% de chance de se mover para o quadrado à esquerda ou à direita do alfinete. As bolinhas de gude se reúnem nas caixas na parte inferior do dispositivo e, para um número grande de bolinhas, a altura das pilhas de mármore nas caixas será semelhante a uma distribuição binomial discreta.

Desafio

Para esse desafio, você calculará a distribuição de probabilidade resultante de máquinas de bean com base em diagramas como o acima. Os diagramas são interpretados como um 'programa' bidimensional pelo qual os mármores passam, em direção aos campos ao lado ou abaixo do campo atual. Quando os mármores atingem o fundo da máquina, eles são contados para a distribuição de probabilidade. Para mantê-lo interessante, esses diagramas conterão mais alguns campos do que apenas a fonte e os pinos simples. Um diagrama de exemplo é:

|     O     |
|     ^     |
|    ^ /    |
|   ^ | ^   |
|  <^- =  v |
| ^ ^ ^ ^ ^ |

Além disso, agora os mármores agora têm uma direção de rotação. Essa direção é definida por alguns campos e determina para qual próximo campo o mármore se move em vários outros campos.

Os seguintes campos são definidos:

  • O: Fonte. Spawns mármores diretamente abaixo dele. A direção desses mármores é 50% esquerda, 50% direita. Cada fonte produz a mesma quantidade de bolinhas de gude.
  • U: Pia. Quaisquer bolinhas que entram neste campo são removidas da máquina de feijão.
  • : Espaço vazio. Se um mármore chegar a esse campo, ele será movido para o campo abaixo.
  • -: Chão. Se um mármore chegar a esse campo, ele será movido para o campo à esquerda ou para o campo à direita, dependendo da direção atual.
  • ^: Divisor. Se um mármore chegar a esse campo, ele terá 50% de movimento para o campo à direita ou o campo à esquerda do separador. Isso também determina a direção do mármore.
  • v: Junte-se. Se um mármore chegar a esse campo, ele será movido para o campo abaixo.
  • /: Almofada inclinada. Se um mármore chegar a esse campo, ele será movido para o campo à esquerda do bloco, definindo a direção do mármore.
  • \: Igual ao anterior, mas à direita.
  • |: Refletor. Se um mármore chegar a esse campo, ele reverterá a direção do mármore e moverá o mármore para o campo à direita ou à esquerda, com base nessa direção invertida.
  • =: Canhão. Se um mármore chegar a esse campo, ele será movido para a direita ou esquerda na direção atual, até encontrar um campo que não é , -ou O.
  • <: Igual ao anterior, mas sempre definirá a direção e se moverá para a esquerda.
  • >: Igual ao anterior, mas à direita.

As seguintes garantias são dadas em relação ao diagrama.

  • Cada linha de entrada terá exatamente o mesmo comprimento nos campos.
  • O campo mais à esquerda e mais à direita de cada linha será sempre a |.
  • O diagrama não conterá caminhos possíveis pelos quais os mármores podem ficar presos na máquina por uma quantidade indeterminada de iterações, como \/ou ^^.
  • O diagrama conterá apenas os campos acima mencionados.
  • Existem uma ou mais fontes

Resultado

Sua tarefa será gerar um gráfico de barras ASCII de 16 linhas de altura da distribuição de probabilidade na qual os mármores saem do lado inferior do gráfico, redimensionados para que a maior probabilidade cubra todos os 16 caracteres. Portanto, para o seguinte problema:

|     O     |
|     ^     |
|    ^ ^    |
|   ^ ^ ^   |
|  ^ ^ ^ ^  |
| ^ ^ ^ ^ ^ |

Seu programa deve produzir a seguinte solução (observe que ele deve ter a mesma largura que o programa de entrada, incluindo os tubos ao lado:

     # #     
     # #     
     # #     
     # #     
     # #     
     # #     
     # #     
     # #     
   # # # #  
   # # # #  
   # # # #  
   # # # #  
   # # # #  
   # # # #  
 # # # # # #
 # # # # # # 

Exemplos

A seguir, é apresentado um exemplo que deve testar a funcionalidade de todos os diferentes tipos de campos:

|     O     O         |
|  O  ^ /  <^\\\      |
|    ^ >            ^ |
|   ^ ^ ^            =|
|  ^ ^ | ^    <^   O  |
| ^ > ^ | ^   O ^> v  |
||  ^U  ^  |  =    ^\ |
|  ^ ^ ^ ^U ^\ ---^   |
| = ^   ^     =    v  |

Isso deve resultar na seguinte saída:

                     # 
                     # 
                     # 
                     # 
                   # # 
                   # # 
                   # # 
       # #         # # 
       # #         # # 
       # #         # # 
       # #         # # 
      ## #         # # 
      ## # #       # # 
   # ### # #       # # 
 # # ### # #       # # 
 # # ### # #       # # 

Regras

Tanto as funções quanto os programas completos constituem respostas válidas para esse desafio. Você receberá o diagrama como uma sequência separada por nova linha e retornará o gráfico de saída no formato especificado. Aplicam- se as regras de entrada / saída padrão . Enquanto novas linhas à direita e à esquerda são permitidas na saída, cada linha deve ter exatamente a mesma largura que a entrada.

Para permitir soluções mais criativas, é necessário apenas que seu programa produza o resultado correto mais de 90% do tempo para o mesmo diagrama. Afinal, é uma simulação de probabilidade.

Pontuação

Isso é , então a pontuação mais baixa em bytes vence.

CensoredUsername
fonte
Muito mais simples, mas relacionado .
Peter Taylor
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Dennis
so v= [space]?
L4m2
@ l4m2 ve [space]diferem na maneira como os canhões interagem em torno deles.
CensoredUsername

Respostas:

8

Python 3 , 431 429 410 bytes

def t(a):e=enumerate;p=a.split("\n");o=[0]*len(p[0]);{m(i,j,p,o,1):m(i,j,p,o,-1)for i,r in e(p)for j,c in e(r)if"O"==c};[print("".join(" #"[round(16*r/max(o)+i)>15]for r in o))for i in range(16)]
def m(r,k,p,o,l,x=1):
 while r<len(p):
  c=p[r][k]
  if"^"==c:x/=2;m(r,k-l,p,o,l,x)
  if"U"==c:return
  if c in" vO":r+=1;continue
  l=[1,l,-1,l,-l,1][ord(c)%6];k-=l
  while";"<c<"?"and p[r][k]in" O-":k-=l
 o[k]+=x

Experimente online!

Esta resposta é um esforço colaborativo entre o Wheat Wizard e o CensoredUsername. Para referência, este é o algoritmo não destruído.

-2 bytes do Sr. Xcoder

-19 bytes de CensoredUsername

Assistente de chapéu
fonte
-2 bytes se você alternar para Python 2 (declaração de impressão)?
caird coinheringaahing
1
Disso foi dito: but I can confirm it's doable in 519 characters of python 3 code ;) I don't think I can golf mine much more- CensoredUsername
Stephen
Eu era irremediavelmente ingênuo quando disse isso. Dito isto, a competição de golfe garantida foi bastante divertida. Também @cairdcoinheringaahing, a declaração de impressão do python 2 é uma declaração, não uma expressão e, portanto, não pode ser usada na compreensão de uma lista. Isso significa que o oneliner no topo deve ser dividido em várias linhas recuadas, o que tornaria o ganho de 2 bytes ao removê-lo.
usar o seguinte
4

Python 2 , 731 bytes

i=raw_input
l=i()
c=[]
while l:c,l=c+[l],i()
p=[[0]*len(l)for l in c]+[[0]*max(map(len,c))]
S=lambda r,C,p:r>=0and C>=0and r<len(p)and C<len(p[r])
def U(r,C,P,D,N=0):
 if S(r,C,p):p[r][C]+=P
 if S(r,C,c):
	K=c[r][C]
	if K in' O':U(r+1-N,C+D*N,P,D,N)
	elif'v'==K:U(r+1,C,P,D)
	elif'-'==K:U(r,C+D,P,D,N)
	elif'^'==K:U(r,C-1,P/2,-1);U(r,C+1,P/2,1)
	elif'/'==K:U(r,C-1,P,-1)
	elif'\\'==K:U(r,C+1,P,1)
	elif'='==K:U(r,C+D,P,D,1)
	elif'>'==K:U(r,C+1,P,1,1)
	elif'<'==K:U(r,C-1,P,-1,1)
	elif'|'==K:U(r,C-D,P,-D)
for r in range(len(c)):
 for C in range(len(c[r])):
	if'O'==c[r][C]:U(r+1,C,1.,1);U(r+1,C,1.,-1)
p=p[-1][::-1]
s=16/max(p)
f=['#'*min(int(n*s),16)+' '*min(int(16-n*s),16)for n in p]
print('\n'.join(map(''.join,zip(*f)))[::-1])

Experimente online!

-17 bytes graças a caird coinheringaahing

-12 bytes graças a Nathan Shiraini

-56 bytes alternando para recuo misto (Python 2)

-28 graças ao CensoredUsername porque as probabilidades são normalizadas no final, portanto, não é necessário que as probabilidades finais sempre adicionem até 1.

-7 bytes graças à Calculadora Feline, usando uma elifdeclaração final mais curta .

-218 bytes, mesclando as duas funções

HyperNeutrino
fonte
1052 bytes
caird coinheringaahing
@cairdcoinheringaahing Certo, obrigado.
HyperNeutrino
2
Nas chamadas para Re Lcomo R(r+1-N,C+N,P,N=N)(primeira chamada para R), você não precisa do N=no final; deveria ser em R(r+1-N,C+N,P,N)vez disso.
Nathan.Eilisha Shiraini
@NathanShiraini Certo, obrigado.
HyperNeutrino
... você esqueceu um pouco. A última linha 2 de ambos Le R^^ Além disso, o segundo nível de recuo é de 4 espaços em todos os lugares, eu acho que você poderia fazê-lo 2.
Nathan.Eilisha Shiraini
3

C, 569 568 556 bytes

Golfe

#define A s[1]
#define c(i,j,k) break;case i:x=j;y=k;
w,S,i,j,d,x,y,z;main(int*a,char**s){w=strchr(&A[1],'|')+2-A;a=calloc(w,4);for(;i++<'~~';j=0){for(;A[j];){if(A[z=j++]==79){d=rand()%2;x=4;y=7;z+=w;for(;z<strlen(A);){z+=x%3-1+(y%3-1)*w;switch(A[z]){case 85:goto e;c(32,x/3*(3+1),y/3*(3+1))c(45,d*2+3,7)c(94,(d=rand()%2)*2+3,7)c(118,4,8)c(47,3,7)d=0;c(92,5,7)d=1;c(124,(d=!d)*2+3,7)c(60,x,y)case 62:d=A[z]/2%2;case 61:x=d*8;y=4;}}a[z%w]++;e:;}}}for(i=-1;++i<w;S=a[i]>S?a[i]:S);for(j=17;j-->1;puts(""))for(i=0;i<w-1;printf("%c",a[i++]*16./S+0.6<j?32:35));}

Ungolfed

//Variable Definitions
//direction - marbles current direction, 0 -> left, 1-> right
//arrwidth - width of array
//x - change in x of marble in base 3 - 0 -> Left, 1 -> stay, 2-> right
//y - change in y of marble in base 3 - 0 -> Up, 1 -> stay, 2-> Down
//z - position of marble
//i - iterator on runs of program
//j - iterator on string
//k - iterator on outputstring
//argc - array holding all buckets

#define c(i,j,k) break;case i:x=j;y=k;

arrwidth,scale,i,j,direction,x,y,z;

main(int *argc, char**argv){
  arrwidth=strchr(&A[1],'|')+2 - A; //get width
  argc=calloc(arrwidth,4);
  for(;i++<'~~';j=0){
    for(;A[j];){
      if(A[z=j++] == 79){ //if it finds an O, start sim
        direction=rand()%2;
        x=4;
        y=7;
        z+=arrwidth;
        for(;z<strlen(A);){
          z+=x%3-1 + (y%3-1)*arrwidth;
          switch (A[z]){
            case 85://marble dies dont record
              goto e;
            c(32,x/3*(3+1),y/3*(3+1)) //case ' '
            c(45,direction*2+3,7)    //case -
            c(94,(direction=rand()%2)*2+3,7)    //case ^
            c(118,4,8)    //case v
            c(47,3,7)    //case /
              direction=0;
            c(92,5,7)   //case '\'
              direction=1;
            c(124,(direction=!direction)*2+3,7)
            c(60,x,y)    //case <
            case 62:    //case >
              direction=A[z]/2%2;
            case 61:  //case =
              x=direction*8;
              y=4;
          }
        }
        argc[z%arrwidth]++;
        e:;
      }
    }
  }
  //get output answer in terms of '#'
  for(i=-1;++i<arrwidth;scale=argc[i]>scale?argc[i]:scale);
  for(j=17;j-->1;puts(""))
    for(i=0; i < arrwidth-1;printf("%c",argc[i++]*16./scale+0.6<j?32:35));
}

Edições

Salvei 12 bytes alterando minha macro de caso.

Notas

Meu código usa um sistema de números inteiros de base 3 para determinar para onde o mármore é direcionado e será direcionado depois (para canhões e outras coisas).

Eu tentei, então tive que vencer essa solução python, eu realmente fiz.

dj0wns
fonte
1
Conto 568 bytes; talvez você tenha contado a nova linha à direita? E, caramba, me sinto mal; superado em Python por C? Ei ...: P
HyperNeutrino
Você está correto, deixei uma novidade no arquivo. obrigado!
dj0wns