Chuda, wredna maszyna do fasoli

26

Klasycznym przykładem wprowadzenia ludzi w koncepcję dyskretnego rozkładu prawdopodobieństwa jest maszyna do fasoli . Ta maszyna ma dużą liczbę kulek spadających z wąskiego przejścia u góry, po czym uderzają w rzędy przeplatanych szpilek, gdzie na każdym szpilce marmur uderza w lewą lub prawą szpilkę. Na koniec szpilki są gromadzone w pionowych pojemnikach na dole maszyny. Prosty schemat tej maszyny wygląda następująco:

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

Na tym schemacie Ooznacza miejsce, z którego wypadają kulki. Każdy z nich ^jest szpilką, przy której marmur ma 50% szansy na przejście do kwadratu po lewej lub prawej stronie szpilki. Kulki zbierają się następnie w pojemnikach na spodzie urządzenia, a dla wystarczająco dużej liczby kulek wysokość marmurowych stosów w pojemnikach będzie przypominać dyskretny rozkład dwumianowy.

Wyzwanie

W tym wyzwaniu będziesz obliczał wynikowy rozkład prawdopodobieństwa maszyn do fasoli na podstawie diagramów takich jak powyższy. Diagramy są interpretowane jako dwuwymiarowy „program”, przez który przechodzą kulki, w kierunku pól z boku lub pól poniżej bieżącego pola. Gdy kulki osiągną dno maszyny, są one liczone do rozkładu prawdopodobieństwa. Aby było ciekawie, te diagramy będą zawierały kilka dodatkowych pól niż tylko proste źródło i piny. Przykładowy diagram to:

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

Co więcej, teraz wszystkie kulki mają kierunek obrotu. Ten kierunek jest ustalany przez niektóre pola i określa, do którego następnego pola marmur przesuwa się na kilka innych pól.

Zdefiniowane są następujące pola:

  • O: Źródło. Odradza kulki bezpośrednio pod nim. Kierunek tych kulek to 50% w lewo, 50% w prawo. Każde źródło wytwarza taką samą ilość kulek.
  • U: Tonąć. Wszelkie kulki, które wejdą w to pole, są usuwane z maszyny do fasoli.
  • : Pusta przestrzeń. Jeśli marmur dotrze na to pole, przeniesie się na pole poniżej.
  • -: Podłoga. Jeśli marmur dotrze na to pole, przesunie się albo na pole po lewej, albo na pole po prawej, w zależności od bieżącego kierunku.
  • ^: Rozdzielacz. Jeśli marmur dotrze na to pole, ma 50% ruchu do pola po prawej stronie lub pola po lewej stronie rozdzielacza. To także określa kierunek marmuru.
  • v: Przystąpić. Jeśli marmur dotrze na to pole, przeniesie się na pole poniżej.
  • /: Nachylona podkładka. Jeśli marmur dotrze na to pole, przesunie się na pole po lewej stronie podkładki, ustawiając kierunek marmuru.
  • \: Taki sam jak poprzedni, ale po prawej stronie.
  • |: Odbłyśnik. Jeśli marmur dotrze na to pole, odwróci kierunek marmuru i przeniesie marmur na pole w prawo lub w lewo, w oparciu o ten odwrócony kierunek.
  • =: Cannon. Jeśli marmur dotrze na to pole, przesunie go w prawo lub w lewo w bieżącym kierunku, dopóki marmur nie napotka pola, które nie jest , -lub O.
  • <: Taki sam jak poprzedni, ale zawsze ustawi kierunek i przesuwa się w lewo.
  • >: Taki sam jak poprzedni, ale po prawej stronie.

Poniższe gwarancje dotyczą diagramu.

  • Każdy wiersz wejściowy będzie miał dokładnie taką samą długość w polach.
  • Pole znajdujące się najbardziej po lewej i po prawej stronie każdego wiersza zawsze będzie oznaczało |.
  • Schemat nie będzie zawierał żadnych możliwych ścieżek, którymi kulki mogłyby utknąć w maszynie na nieokreśloną liczbę iteracji, takich jak \/lub ^^.
  • Schemat będzie zawierał tylko wyżej wymienione pola.
  • Istnieje jedno lub więcej źródeł

Wynik

Twoim zadaniem będzie wygenerowanie 16-liniowego wykresu słupkowego ASCII o rozkładzie prawdopodobieństwa, w którym kulki wychodzą z dolnej części wykresu, skalowane w taki sposób, aby największe prawdopodobieństwo obejmowało wszystkie 16 znaków. Tak dla następującego problemu:

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

Twój program powinien wygenerować następujące rozwiązanie (zwróć uwagę, że powinien mieć taką samą szerokość jak program wejściowy, w tym rury z boku:

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

Przykłady

Oto przykład, który powinien przetestować funkcjonalność wszystkich różnych typów pól:

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

Powinno to spowodować następujące wyniki:

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

Zasady

Zarówno funkcje, jak i pełne programy stanowią prawidłowe odpowiedzi na to wyzwanie. Otrzymasz diagram jako ciąg rozdzielony znakiem nowej linii i powinieneś zwrócić wykres wyjściowy w podanym formacie. Obowiązują domyślne reguły wejścia / wyjścia . Podczas gdy końcowe i końcowe znaki nowej linii są dozwolone w danych wyjściowych, każdy wiersz powinien mieć dokładnie taką samą szerokość jak dane wejściowe.

Aby umożliwić bardziej kreatywne rozwiązania, wymagane jest, aby Twój program wyświetlał poprawny wynik przez ponad 90% czasu dla tego samego diagramu. W końcu to symulacja prawdopodobieństwa.

Punktacja

To jest , więc wygrywa najniższy wynik w bajtach.

CensoredUsername
źródło
O wiele prostsze, ale powiązane .
Peter Taylor
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Dennis
więc v= [space]?
l4m2
@ l4m2 vi [space]różnią się w jaki sposób działa wokół nich armata.
CensoredUsername

Odpowiedzi:

8

Python 3 , 431 429 410 bajtów

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

Wypróbuj online!

Ta odpowiedź to wspólny wysiłek między Kreatorem pszenicy i Cenzorowaną nazwą użytkownika. Dla porównania, to jest algorytm ungolfed.

-2 bajty od pana Xcodera

-19 bajtów od CensoredUsername

Hat Wizard
źródło
-2 bajty, jeśli przełączysz się na Python 2 (instrukcja drukowania)?
caird coinheringaahing
1
O tym powiedziano: 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
Byłem beznadziejnie naiwny, kiedy to powiedziałem. To powiedziawszy, zapewnienie konkurencji w golfa było dość zabawne. Również @cairdcoinheringaahing, instrukcja drukowania Pythona 2 jest instrukcją, a nie wyrażeniem, dlatego nie można jej używać w interpretacji listy. Oznaczałoby to, że oneliner u góry musi zostać podzielony na kilka wcięć, które spowodowałyby, że zysk 2 bajtów po usunięciu go byłby nieważny.
CensoredUsername
4

Python 2 , 731 bajtów

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

Wypróbuj online!

-17 bajtów dzięki cairdowi coinheringaahing

-12 bajtów dzięki Nathanowi Shiraini

-56 bajtów przez przejście do mieszanego wcięcia (Python 2)

-28 dzięki CensoredUsername, ponieważ prawdopodobieństwa są normalizowane na końcu, więc nie jest konieczne, aby końcowe prawdopodobieństwa zawsze sumowały się do 1.

-7 bajtów dzięki kalkulatorowi Feline przy użyciu krótszej elifinstrukcji kończącej .

-218 bajtów poprzez połączenie dwóch funkcji

HyperNeutrino
źródło
1052 bajtów
caird coinheringaahing
@cairdcoinheringaahing Racja, dzięki.
HyperNeutrino
2
W połączeniach do Ri Lpodobnych R(r+1-N,C+N,P,N=N)(pierwsze połączenie z R) nie potrzebujesz N=końca; powinno być R(r+1-N,C+N,P,N)zamiast.
Nathan.Eilisha Shiraini
@NathanShiraini Racja, dzięki.
HyperNeutrino
... zapomniałeś trochę. Ostatnia 2 linia zarówno Li R^^ Ponadto, twój drugi poziom wcięcia to 4 spacje wszędzie, myślę, że możesz to zrobić 2.
Nathan.Eilisha Shiraini
3

C, 569 568 556 bajtów

Grał w golfa

#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));}

Nie golfił

//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));
}

Edycje

Zaoszczędziłem 12 bajtów, zmieniając makro mojego przypadku.

Uwagi

Mój kod używa systemu bazowych liczb całkowitych 3, aby określić, dokąd zmierza marmur i za którym będzie kierowany (w przypadku armat i innych rzeczy).

Próbowałem, więc musiałem pokonać to rozwiązanie Pythona, naprawdę.

dj0wns
źródło
1
Zliczam 568 bajtów; może policzyłeś końcowy znak nowej linii? I cholernie źle się czuję; outgolfed w Pythonie przez C? Jezu ...: P
HyperNeutrino
Masz rację, w pliku pozostawiłem końcowy znak nowego użytkownika. dzięki!
dj0wns