Cyfrowa logika oparta na siatce (płytki duodyadyczne)

33

Płytki duodyadyczne są rodzajem kwadratowych bloków funkcyjnych które pobierają dwa dane wejściowe, jeden z góry i jeden z lewej strony, i mają dwa wyjścia, jeden po prawej stronie i jeden od spodu. Każde z ich wyjść stanowi osobną funkcję obu wejść.

Na przykład, jeśli #reprezentuje płytki rodzajowe, prawo wyjściowy Rjest funkcją fwejść Ti L, a dno wyjście Bto kolejna funkcja gof Ta L:

 T
L#R         R = f(T, L)
 B          B = g(T, L)

(Kafelki są nazywane „duetem”, ponieważ istnieją dwie funkcje, i „dyadyczne”, ponieważ obie funkcje mają dwa argumenty .)

Płytki mogą być następnie składane razem na siatce, a wyjścia jednego kafelka przechodzą bezpośrednio do wejść sąsiadujących ze sobą kafelków. Tutaj, na przykład, prawe wyjście z lewej #idzie do lewego wejścia z prawej #:

 AB         D = f(f(A, C), B)
C##D        E = g(A, C)
 EF         F = g(f(A, C), B)

Można sobie wyobrazić, że biorąc pod uwagę zestaw płytek duodyadycznych, z których każda ma określoną funkcjonalność, można tworzyć złożone (i potencjalnie przydatne) kompozycje.

W tym wyzwaniu zajmiemy się tylko tradycyjnym zestawem dziesięciu duodyadycznych płytek logicznych , w których wszystkie wejścia i wyjścia są jednobitowymi liczbami binarnymi (zerami lub jedynymi). Użyjemy osobnego znaku ASCII do oznaczenia każdego rodzaju kafelka.

Znaki kafelków i ich relacje wejścia-wyjścia są następujące:
( Tdotyczy górnego wejścia, Llewego wejścia, Rprawego wyjścia, Bdolnego wyjścia).

  1. Zero: 0lub (spacja) → R = 0,B = 0
  2. Jeden: 1R = 1,B = 1
  3. Krzyż: +R = L,B = T
  4. Lustro: \R = T,B = L
  5. Tylko najlepsze: UR = T,B = T
  6. Tylko w lewo: )R = L,B = L
  7. Nie: !R = not L,B = not T
  8. I: &R = L and T,B = L and T
  9. Lub: |R = L or T,B = L or T
  10. Xor: ^R = L xor T,B = L xor T

Wyzwanie

Napisz program lub funkcję, która przyjmuje prostokątną siatkę znaków 0 1+\U)!&|^reprezentującą „obwód” wykonany przy użyciu dziesięciu logicznych płytek duodyadycznych. Musisz także wziąć dwa ciągi znaków 0i 1; jeden będzie lewą kolumną wejściową, a drugi będzie górnym wierszem wejściowym. Twój program / funkcja musi wydrukować / zwrócić dolny wiersz wyjściowy i prawą kolumnę wyjściową (także w 0's i1 ”).

Na przykład w tej siatce

+++
+++

wszystkie wejścia przepływają prosto przez siatkę do wyjść

 ABC
D+++D
E+++E
 ABC

więc wejście 010/ 01miałoby wynik 010/ 01:

 010
0+++0
1+++1
 010

Dokładna wyjście programu będzie [bottom output row]\n[right output column]albo [bottom output row]/[right output column]:

010
01

lub

010/01

Jeśli napisałeś funkcję, możesz zwrócić dwa ciągi w krotce lub liście (lub nadal je wydrukować).

Detale

  • Weź trzy dane wejściowe jako ciągi znaków w jakikolwiek rozsądny sposób (najlepiej w tabeli kolejności, górnym rzędzie, lewej kolumnie): wiersz poleceń, plik tekstowy, sdtin, funkcja arg.
  • Możesz założyć, że wejściowe długości wierszy i kolumn będą pasować do wymiarów siatki i będą zawierać tylko 0„i 1”.
  • Twoja siatka musi używać odpowiednich znaków ( 0 1+\U)!&|^). Pamiętaj o tym 0i oznacz to samo.

Przypadki testowe

(Czytaj I / O jako top/ leftbottom/ right.)

Nand:

&!

00/ 001/ 1
00/ 101/ 1
10/ 001/ 1
10/ 111/0

Wszystkie:

1111
1\+\
1+\+
1\+\

Każde wejście powinno skutkować 1111/ 1111.

Xor z Nand: (zwróć uwagę na kolumnę końcowych spacji)

\)+\ 
U&!& 
+! ! 
\&!& 
   ! 

00000/ 0000000000/ 00000
00000/ 1000000010/ 00000
10000/ 0000000010/ 00000
10000/ 1000000000/00000

Zig zag:

+++\00000000
000\!!!!\000
00000000\+++

Pierwszy bit lewego wejścia staje się ostatnim bitem prawego wyjścia. Wszystko inne jest 0.

000000000000/ 000000000000000/ 000
000000000000/ 100000000000000/001

Propagacja:

)))
UUU
U+U
U+U
UUU

Pierwszy bit lewego wejścia trafia do wszystkich wyjść.

000/ 00000000/ 00000
000/ 10000111/11111

Oto skrót wszystkich przypadków testowych siatki 1 × 1.

Punktacja

Najkrótsze przesłanie w bajtach wygrywa.

Bonus: Jakie fajne „obwody” możesz zrobić?

PS Nie przejmuj się Googlingiem „duodyadycznymi kafelkami”. Wymyśliłem je wczoraj; D
Jeśli chcesz porozmawiać o rozszerzeniu tego pomysłu na pełnoprawny język programowania, odwiedź ten czat .

Hobby Calvina
źródło
11
+1 za fajne wyzwanie, ale także dlatego, że wynalazłeś płytki duodyadyczne, co jest NAPRAWDĘ fajne.
Alex A.
3
+1 Naprawdę całkowicie bezużyteczne jest google: goo.gl/zuqfdW . Niezłe wyzwanie!
BrainSteel
Jestem z nimi. Bardziej interesują mnie twoje kafelki jako język programowania niż to konkretne wyzwanie golfowe. PS: Istnieje 16 możliwych kafelków, więc wymyślenie liter / nazw dla pozostałych sześciu byłoby fajne.
Sparr
Interesujące byłoby posiadanie bloków, które wyjściowo / wejściowe z różnych kierunków, ponieważ w przeciwnym razie nie można wykonać zatrzasku, ponieważ wszystko płynie we właściwym kierunku.
Sp3000,
2
Możesz zmienić T / B na U (p) / D (własne), abyśmy mogli mieć F / B w analogiczny sposób do notacji Kostki Rubika, a następnie. . . kostki trytriadyczne?
Soham Chowdhury

Odpowiedzi:

8

Pyth, 122

Rodzaj potwora. Wykorzystuje po prostu rekurencję, nic fantazyjnego jak programowanie dynamiczne.

D:NGHR@Cm+d[1HG&GH|GHxGH0),[GH!G)[HG!H)x"+\\!1U)&|^"N#aYw)M:@@YGH?hgGtHHv@eYG?egtGHGv@ePYHjkm+0egtleYklePYjkm+0hgbtlePYleY

Demonstracja online .

Wprowadzanie odbywa się w następujący sposób: Najpierw siatka (bez ucieczki, bez dodatkowych symboli), a następnie dwie linie wprowadzania, np. (Zig zag)

+++\00000000
000\!!!!\000
00000000\+++
000000000000
100
Jakube
źródło
8

Mathematica, 331 276 270 267 264 262 252 250 bajtów

Print@@@{#[[2;;,-1,2]],#[[-1,2;;,1]]}&@MapIndexed[h=Characters;({r@#2,b@#2}=<|##|>&@@Thread[h@"0 1+\\)U!&|^"->{0,0,1,i={##},{#2,#},##,1-i,1##,Max@i,(#-#2)^2}]&[r[#2-{1,0}],b[#2-{0,1}]]@#{1,1})&,Join[h@{"0"<>#3},h@StringSplit[#2<>"
"<>#,"
"]],{2}]&

Jest prywatnym wykorzystanie znaków Unicode, który Mathematica używa jako indeks górny T, to znaczy, że to operator transpozycji.

Oto bardziej czytelna wersja:

Print @@@ {#[[2 ;;, -1, 2]], #[[-1, 2 ;;, 1]]} &@
  MapIndexed[h = Characters;
   (
     {r@#2, b@#2} = <|##|> & @@ Thread[
            h@"0 1+\\)U!&|^" -> {
              0,
              0,
              1,
              i = {##},
              {#2, #},
              ##,
              1 - i,
              1 ##,
              Max@i,
              (# - #2)^2
              }] & [
          r[#2 - {1, 0}],
          b[#2 - {0, 1}]
          ] @ # {1, 1}
     ) &,
   Join[
    h@{"0" <> #3},
    h@StringSplit[#2 <> "\n" <> #, "\n"]\[Transpose]
   ],
   {2}] &

Jest to nienazwana funkcja, która pobiera trzy ciągi wejściowe grid, górny i lewy i drukuje dolne i prawe wyjścia.

Wyjaśnienie

Przejdźmy krok po kroku (postaram się nie zakładać żadnej wiedzy Mathematica). Trzeba trochę przeczytać kod od początku. Podstawowy algorytm omija linie obliczające każdą funkcję i zapisując wynikif które będą dostępne dla kolejnych kafelków.

Przetwarzanie wejściowe

To jest to:

Join[
  h@{"0" <> #3},
  h@StringSplit[#2 <> "\n" <> #, "\n"]\[Transpose]
]

To tylko dzieli siatkę na zagnieżdżoną listę znaków (zwróć uwagę, że zdefiniowałem hjako alias dla Characterjakiegoś miejsca w kodzie), a następnie wstawia wiersz i kolumnę z danymi wejściowymi. Działa to, ponieważ 1i 0są również nazwami płytek o stałej funkcji, więc ich nałożenie ma taki sam efekt, jak ręczne wprowadzanie danych wejściowych. Ponieważ są to funkcje, technicznie będą pobierać dane spoza sieci, ale ponieważ są to funkcje stałe, nie ma to znaczenia. W lewym górnym rogu wyświetlany jest znak, 0ale jest to dość arbitralne, ponieważ wyniki tego kafelka nigdy nie są używane.

Zwróć także uwagę na transpozycję. Dodawanie kolumn zajmuje więcej znaków niż dodawanie wierszy, więc transponuję siatkę po dodaniu górnego wiersza. Oznacza to, że górna / dolna i lewa / prawa są zamienione na główną część programu, ale są one całkowicie wymienne, więc to nie ma znaczenia. Muszę tylko zwrócić wyniki w prawidłowej kolejności.

Rozwiązywanie siatki

(Ta sekcja jest nieco nieaktualna. Naprawię ją, gdy będę naprawdę pewien, że skończyłem grać w golfa.)

Następnie przeglądamy MapIndexedwewnętrzny poziom tej zagnieżdżonej listy. Wywołuje to funkcję anonimową podaną jako pierwszy argument dla każdego znaku w siatce, dając również listę z bieżącymi dwoma współrzędnymi. Siatka jest przesuwana w kolejności, dzięki czemu możemy bezpiecznie obliczyć każdą komórkę na podstawie poprzednich.

Używamy zmiennych r(ight) i b(ottom) jako tabel wyszukiwania dla wyników każdej komórki. Nasza anonimowa funkcja ma bieżące współrzędne #2, więc otrzymujemy dane wejściowe do dowolnej komórki za pomocą

r[#2 - {1, 0}],
b[#2 - {0, 1}]

Zauważ, że w pierwszym wierszu i kolumnie uzyska to dostęp do niezdefiniowanych wartości ri b. Mathematica tak naprawdę nie ma z tym problemu i po prostu zwróci ci współrzędne, ale i tak odrzucamy ten wynik, ponieważ wszystkie kafelki w tym wierszu / kolumnie są funkcjami stałymi.

Teraz ta rzecz:

<|##|> & @@ Thread[
  h@"0 1+\\U)!&|^" -> {
     z = {0, 0}, z, o = 1 + z, {##}, ...
  }] &

Jest formą golfa

<|"0" -> (z = {0, 0}), " " -> z, "1" -> (o = 1 + z), "+" -> {##}, ... |> &

Która z kolei jest funkcją, która przy dwóch wejściowych kafelkach zwraca skojarzenie (nazwałbyś to hashapą lub tabelą w innych językach), która zawiera wszystkie możliwe wyniki kafelków dla tych dwóch danych wejściowych. Aby zrozumieć, w jaki sposób wszystkie funkcje są implementowane, musisz wiedzieć, że do pierwszego argumentu takiej funkcji można uzyskać dostęp, #a do drugiego za pomocą #2. Ponadto ##udostępnia sekwencję obu argumentów, których można użyć do „splatania” argumentów.

  • 0: jest prosty, po prostu zwracamy stałą, {0, 0}a także przypisujemy ją zdo przyszłego użycia (np. w kafelku spacji).
  • 1: jest w gruncie rzeczy słuszne {1,1}, ale zskrócenie tego jest 1+z. Zapisujemy to również w o, ponieważ przyda się dla wszystkich kafelków, w których oba wyjścia są identyczne.
  • +: Tutaj wykorzystujemy sekwencję. {##}jest taki sam jak {#,#2}i przekazuje oba dane wejściowe bez zmian.
  • \: My zamienić dwa argumenty {#2,#}.
  • U: Teraz możemy skorzystać z o. o#2oznacza {1,1}*#2, że umieściliśmy pierwszy argument w obu wynikach.
  • )Analogicznie dla lewego argumentu: o#.
  • !: Bitowe nie jest irytujące w Mathematica, ale ponieważ mamy tylko kiedykolwiek 0i 1możemy po prostu odjąć od obu wejść 1(a tym samym ich odwrócenie) i przekazać je na: 1-{##}.
  • &: Ten jest całkiem fajny. Najpierw zauważamy, że bitowe i dla 0i 1jest identyczne z mnożeniem. Ponadto o##jest taki sam jak o*#*#2.
  • |: Ponownie używamy równoważnej funkcji. Bitowa lub jest taka sama jak Maxw tym przypadku, więc stosujemy Maxargumenty wejściowe i mnożymy wynik {1,1}.
  • ^: Najkrótsze, jakie znalazłem dla Xora, to wziąć różnicę i ją wyrównać (aby zapewnić pozytywność), więc mamy o(#-#2)^2.

Po zakończeniu tej funkcji i zwróceniu pełnego skojarzenia używamy znaku bieżącej komórki, aby wyciągnąć interesujący nas element i zapisać go w roraz b. Zauważ, że jest to również wartość zwracana przez anonimową funkcję użytą wMapIndexed , więc mapowanie da mi siatkę wszystkich wyników.

Przetwarzanie wyjściowe

MapIndexedzwraca siatkę 3D, w której pierwszy wymiar odpowiada poziomej współrzędnej siatki (pamiętaj o wcześniejszej transpozycji), drugi wymiar odpowiada pionowej współrzędnej siatki, a trzeci wskazuje, czy mamy wynik dolny, czy lewy. Zauważ, że zawiera on również wiersz wejściowy i kolumnę, których musimy się pozbyć. Tak więc uzyskujemy dostęp do dolnego wyjścia dolnego rzędu za pomocą

#[[2;;,-1,2]]

i prawy wynik ostatniej kolumny za pomocą

#[[-1,2;;,1]]

Zauważ, że 2;;jest to zakres od drugiego do ostatniego elementu.

Wreszcie, stosujemy się Printdo obu (wykorzystując @@@jako cukier syntaktyczny dla drugiego poziomu Apply), który po prostu wypisuje wszystkie swoje argumenty jeden za drugim (a ponieważ stosuje się go do dwóch oddzielnych wyrażeń, pojawi się nowa linia między dolnym a dolnym właściwe wyjście).

Martin Ender
źródło
8

C, 332 309 272 270 266 259 247 225 bajtów

#define C(x)*c-x?
i,k,T,L,m;f(c,t,l)char*c,*t,*l;{while(L=l[i]){for(k=0;T=t[k];c++)L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),t[k++]=T;c++;l[i++]=L;}}

Zobacz wyniki online tutaj!

Definiuje to funkcję void f(char*, char*, char*), która powinna przyjąć tablicę jako swoje pierwsze wejście, potem górny rząd danych wejściowych, a następnie lewy rząd danych wejściowych.

Oto, co testowałem:

#include "stdio.h"
int main() {
    char buf[1024],top[33],left[33];
    /* Copy and paste an example circuit as the first input,
       and put a 'Q' immediately after it. 
       Note that the Q is never touched by the function f, and is used
       solely as a delimiter for input. */
    scanf("%[^Q]Q ",buf);
    /* Then enter your top inputs */
    scanf("%[01]%*[^01]", top);
    /* Then your left ones */
    scanf("%[01]", left);
    /* OUTPUT: Bottom\nRight */
    f(buf, top, left);
    return 0;
}

Zatem, wprowadzając 2-bitowy mnożnik Sp3000:

UUUU))))
UU++)))&
UUU+)  U
UU++&))U
U++&+)^U
U)&\&)UU
   U+^UU
   \&UUUQ
11110000
00000000

Otrzymujemy:

00001001
11111111

Z drugiej strony, mając na uwadze pół sumatora Sp3000, chciałbym zobaczyć pełnego sumatora ... Jeden z was to zrobił! Nie sądzę, że system sam w sobie jest językiem programowania, ale był bardzo interesujący. Wydaje się to jednak doskonałym celem dla metagolfa!

Krótkie wyjaśnienie:

Oto rozwikłany, skomentowany kod:

/* We define the first half of the ?: conditional operator because, well,
   it appears over and over again. */
#define C(x)*c-x?
/* i,k are counting variables
   T,L are *current* top and left inputs */
i,k,T,L,m;
f(c,t,l)char*c,*t,*l;{
    /* The outer loop iterates from top to bottom over l and c */
    while(L=l[i]){
        /* Inner loop iterates from left to right over t and c */
        for(k=0;T=t[k];c++)
            /* This line looks awful, but it's just a bunch of character
            comparisons, and sets T and L to the output of the current c */
            L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),
            /* Write our output to our input, it will be used for the next row */
            t[k++]=T;
        c++; /*Absorbs the newline at the end of every row */
        /* Keep track of our right-most outputs, 
        and store them in the handy string passed to the function. */
        l[i++]=L;
    }
    /* Bottom output is now stored entirely in t, as is right output in l */        
}

Powtarzamy c, od lewej do prawej (a następnie od góry do dołu), za tkażdym razem przepisując dane wejściowe i wypychając najbardziej prawy wynik, który jest wpychany do lłańcucha. Możemy sobie wyobrazić, jak to zastąpienie górnym rzędzie cz 1„s oraz0 ” S iteracyjnie i śledzenie bity, które są wypychane z prawej strony.

Oto bardziej wizualna sekwencja, rząd po rzędzie:

 111                                  
1&+^  =>  110 ->0  =>     ->0  =>     0 Thus, "01" has been written to l,
1+&+     1+&+         110 ->1         1
                                  110   And "110" is stored currently in t.

To oczywiście komplikuje się przy różnych symbolach i rozmiarach, ale główna idea jest ważna. Działa to tylko dlatego, że dane nigdy nie płyną w górę ani w lewo.

BrainSteel
źródło
Duży potencjał do gry w golfa! Zacznij od zmiany nagłówka fna f(c,t,l)char*c,*t,*l(nie przejmuj się typem zwrotu).
FUZxxl,
@FUZxxl Ktoś wspomniał o tym na czacie, ale nie mogłem go uruchomić. Czy to zachowanie jest standardowe? LLVM zgłasza co najmniej 2 błędy w tej linii.
BrainSteel
Przepraszam. Powinien być f(c,t,l)char*c,*t,*l;. Nie kompiluj w trybie C11, ponieważ niejawna reguła int, która pozwala nam upuścić typ zwracany, została usunięta w tej wersji.
FUZxxl,
@FUZxxl Wygląda na to, że zawodzi również w C99. W rzeczywistości każdy tryb, w którym ustawiłem kompilator, odrzucał ten kod.
BrainSteel
Czy dodałeś średnik zaraz po *l? Kompiluje się w trybie C99 na moim komputerze.
FUZxxl
7

Python 2, 316 bajtów

Ta funkcja buduje 10 funkcji lambda kafelków, a następnie iteruje siatkę, aktualizując stany logiczne. Następnie drukowane są końcowe pionowe i poziome stany logiczne.

def b(d,j,g):
 h=enumerate;e=dict((s[0],eval('lambda T,L:('+s[1:]+')'))for s in' 0,0#00,0#11,1#+L,T#\\T,L#UT,T#)L,L#!1-L,1-T#&T&L,T&L#|T|L,T|L#^T^L,T^L'.split('#'));j=list(j+'\n');g=list(g)
 for y,k in h(d.split('\n')):
  L=g[y]
  for x,c in h(k):T=j[x];L,B=e[c](int(T),int(L));j[x]=`B`
  g[y]=`L`
 print''.join(j+g)

Nieskluczony kod zawierający testy:

def logic(grid, top, left):
    loop = enumerate;
    func = dict((s[0], eval('lambda T,L:('+s[1:]+')')) for s in ' 0,0#00,0#11,1#+L,T#\\T,L#UT,T#)L,L#!1-L,1-T#&T&L,T&L#|T|L,T|L#^T^L,T^L'.split('#'));
    top = list(top+'\n');
    left = list(left)
    for y,row in loop(grid.split('\n')):
        L = left[y]
        for x,cell in loop(row) :
            T = top[x];
            L, B = func[cell](int(T), int(L));
            top[x] = `B`
        left[y] = `L`
    print ''.join(top + left)

import re
testset = open('test.txt', 'rt').read().strip()
for test in testset.split('\n\n'):
    if test.endswith(':'):
        print '------------------\n'+test
    elif re.match('^[01/\n]+$', test, re.S):
        for run in test.split():
            top, left = run.split('/')
            print 'test', top, left
            logic(grid, top, left)
    else:
        grid = test

test.txtPliku (w tym 2 innych testów według SP3000)

Nand:

&!

00/0
00/1
10/0
10/1

All ones:

1111
1\+\
1+\+
1\+\

1001/1100

Xor from Nand (note the column of trailing spaces):

\)+\ 
U&!& 
+! ! 
\&!& 
   ! 

00000/00000
00000/10000
10000/00000
10000/10000

Half adder:

+))
U&+
U+^

000/000
000/100
100/000
100/100

Right shift:

\\\
\++
\++

001/110
010/101
101/100

Wyjście testowe:

------------------
Nand:
test 00 0
01
1
test 00 1
01
1
test 10 0
01
1
test 10 1
11
0
------------------
All ones:
test 1001 1100
1111
1111
------------------
Xor from Nand (note the column of trailing spaces):
test 00000 00000
00000
00000
test 00000 10000
00010
00000
test 10000 00000
00010
00000
test 10000 10000
00000
00000
------------------
Half adder:
test 000 000
000
000
test 000 100
001
101
test 100 000
101
001
test 100 100
110
110
------------------
Right shift:
test 001 110
000
111
test 010 101
101
010
test 101 100
010
110
Logic Knight
źródło
7

Python 2, 384 338 325 bajtów

def f(G,T,L):
 def g(x,y):
  if x>-1<y:l=g(x-1,y)[1];t=g(x,y-1)[0];r=l,t,1-l,0,0,1,t,l,l&t,l|t,l^t;i="+\\!0 1U)&|^".index(G[y*-~W+x]);return((t,l,1-t)+r[3:])[i],r[i]
  return(int((y<0)*T[x]or L[y]),)*2
 H=G.count("\n")+1;W=len(G)/H;return eval('"".join(map(str,[g(%s]for _ in range(%s)])),'*2%('_,H-1)[0','W','W-1,_)[1','H'))

Poważnie CH, jeśli to już nie jest zabawka, powinieneś zacząć dzwonić do niektórych fabryk zabawek.

Bardziej golfowi i znacznie mniej wydajni, ale wciąż nie dogonili CarpetPython. Dane wejściowe jak f("1111\n1\\+\\\n1+\\+\n1\\+\\","0101","1010"), wynik to krotka dwóch ciągów. Upewnij się jednak, że na planszy nie ma końcowego nowego wiersza, który to zepsuje.

Program testowy

def f(G,T,L):
 def g(x,y):
  if x>-1<y:l=g(x-1,y)[1];t=g(x,y-1)[0];r=l,t,1-l,0,0,1,t,l,l&t,l|t,l^t;i="+\\!0 1U)&|^".index(G[y*-~W+x]);return((t,l,1-t)+r[3:])[i],r[i]
  return(int((y<0)*T[x]or L[y]),)*2
 H=G.count("\n")+1;W=len(G)/H;return eval('"".join(map(str,[g(%s]for _ in range(%s)])),'*2%('_,H-1)[0','W','W-1,_)[1','H'))


import itertools

G = r"""
+))
U&+
U+^
""".strip("\n")

def test(T, L):
    print f(G, T, L)

def test_all():
    W = len(G[0])
    H = len(G)

    for T in itertools.product([0, 1], repeat=len(G.split("\n")[0])):
        T = "".join(map(str, T))

        for L in itertools.product([0, 1], repeat=len(G.split("\n"))):
            L = "".join(map(str, L))

            print "[T = %s; L = %s]" % (T, L)
            test(T, L)
            print ""

test("000", "000")
test("000", "100")
test("100", "000")
test("100", "100")

Możesz również przetestować wszystkie możliwe przypadki za pomocą test_all() .

Dodatkowe przypadki testowe

Pół sumatora

Oto pół sumatora, który dodaje lewe górne bity, generując <input bit> <carry> <sum>:

+))
U&+
U+^

Testy:

000 / 000  ->  000 / 000
000 / 100  ->  001 / 101
100 / 000  ->  101 / 001
100 / 100  ->  110 / 110

Wyjście powinno być takie samo, nawet jeśli drugi / trzeci bit wejść zostanie zmieniony.

Prawa zmiana

Biorąc pod uwagę abc / def, wyniki te fab / cde:

\\\
\++
\++

Testy:

001 / 110 -> 000 / 111
010 / 101 -> 101 / 010
101 / 100 -> 010 / 110

3-bitowy sortownik

Sortuje pierwsze trzy bity góry na ostatnie trzy bity dołu. Właściwe wyjście to śmieci.

UUU)))
UU)U U
U&UU U
U+|&)U
\UU++|
 \)&UU
  \+|U
   UUU

Testy:

000000 / 00000000 -> 000000 / 00000000
001000 / 00000000 -> 000001 / 11111111
010000 / 00000000 -> 000001 / 00001111
011000 / 00000000 -> 000011 / 11111111
100000 / 00000000 -> 000001 / 00001111
101000 / 00000000 -> 000011 / 11111111
110000 / 00000000 -> 000011 / 00001111
111000 / 00000000 -> 000111 / 11111111

Mnożnik 2-bitowy na 2-bitowy

Traktuje pierwszy / drugi bit góry jako pierwszą liczbę, a trzeci / czwarty bit góry jako drugą liczbę. Wyjście do ostatnich czterech bitów dołu. Właściwe wyjście to śmieci.

UUUU))))
UU++)))&
UUU+)  U
UU++&))U
U++&+)^U
U)&\&)UU
   U+^UU
   \&UUU

Edycja: wyodrębniono kolumnę i dwa rzędy.

Testy:

00000000 / 00000000 -> 00000000 / 00000000
00010000 / 00000000 -> 00000000 / 10000000
00100000 / 00000000 -> 00000000 / 00000000
00110000 / 00000000 -> 00000000 / 10000000
01000000 / 00000000 -> 00000000 / 00000000
01010000 / 00000000 -> 00000001 / 11111111
01100000 / 00000000 -> 00000010 / 00000000
01110000 / 00000000 -> 00000011 / 11111111
10000000 / 00000000 -> 00000000 / 00000000
10010000 / 00000000 -> 00000010 / 10000000
10100000 / 00000000 -> 00000100 / 00000000
10110000 / 00000000 -> 00000110 / 10000000
11000000 / 00000000 -> 00000000 / 00000000
11010000 / 00000000 -> 00000011 / 11111111
11100000 / 00000000 -> 00000110 / 00000000
11110000 / 00000000 -> 00001001 / 11111111
Sp3000
źródło
1

R 524 517

Prawdopodobnie dużo miejsca na zmniejszenie tego w tej chwili, ale było to naprawdę interesujące. Istnieją dwie funkcje. Funkcja d jest pracownikiem, a f jest urządzeniem porównującym.

Funkcja d jest wywoływana z 3 ciągami znaków, bramkami, górnym i lewym. Bramy są umieszczane w matrycy określonej przez szerokość.

I=strtoi;S=strsplit;m=matrix;f=function(L,T,G){O=I(c(0,1,L,T,!L,!T,L&T,L|T,xor(L,T)));X=which(S(' 01+\\U)!&|^','')[[1]]==G);M=m(c(1,1,1,2,1,1,3,2,2,4,3,4,5,4,3,6,4,4,7,3,3,8,5,6,9,7,7,10,8,8,11,9,9),nrow=3);return(c(O[M[2,X]],O[M[3,X]]))};d=function(G,U,L){W=nchar(U);H=nchar(L);U=c(list(I(S(U,'')[[1]])),rep(NA,H));L=c(list(I(S(L,'')[[1]])),rep(NA,W));G=m((S(G,'')[[1]]),nrow=W);for(i in 1:H)for(n in 1:W){X=f(L[[n]][i],U[[i]][n],G[n,i]);L[[n+1]][i]=X[1];U[[i+1]][n]=X[2]};cat(U[[H+1]],' / ',L[[W+1]],sep='',fill=T)}

Trochę sformatowany

I=strtoi;S=strsplit;m=matrix;
f=function(L,T,G){
    O=I(c(0,1,L,T,!L,!T,L&T,L|T,xor(L,T)));
    X=which(S(' 01+\\U)!&|^','')[[1]]==G);
    M=m(c(1,1,1,2,1,1,3,2,2,4,3,4,5,4,3,6,4,4,7,3,3,8,5,6,9,7,7,10,8,8,11,9,9),nrow=3);
    return(c(O[M[2,X]],O[M[3,X]]))
};
d=function(G,U,L){
    W=nchar(U);H=nchar(L);
    U=c(list(I(S(U,'')[[1]])),rep(NA,H));
    L=c(list(I(S(L,'')[[1]])),rep(NA,W));
    G=m((S(G,'')[[1]]),nrow=W);
    for(i in 1:H)
        for(n in 1:W){
            X=f(L[[n]][i],U[[i]][n],G[n,i]);
            L[[n+1]][i]=X[1];
            U[[i+1]][n]=X[2]
        };
    cat(U[[H+1]],' / ',L[[W+1]],sep='',fill=T)
}

Niektóre testy

> d('&!','00','0')
01 / 1
> d('&!','00','1')
01 / 1
> d('&!','10','0')
01 / 1
> d('&!','10','1')
11 / 0
> d('\\)+\\ U&!& +! ! \\&!&    ! ','00000','00000')
00000 / 00000
> d('\\)+\\ U&!& +! ! \\&!&    ! ','00000','10000')
00010 / 00000
> d('\\)+\\ U&!& +! ! \\&!&    ! ','10000','00000')
00010 / 00000
> d('\\)+\\ U&!& +! ! \\&!&    ! ','10000','10000')
00000 / 00000
> d('+++\\00000000000\\!!!!\\00000000000\\+++','000000000000','100')
000000000000 / 001
> d('+++\\00000000000\\!!!!\\00000000000\\+++','000000000000','000')
000000000000 / 000
> d('+))U&+U+^','000','000')
000 / 000
> d('+))U&+U+^','000','100')
001 / 101
> d('+))U&+U+^','100','000')
101 / 001
> d('+))U&+U+^','100','100')
110 / 110
MickyT
źródło