Lógica digital baseada em grade (ladrilhos duodádicos)

33

Os blocos duodádicos são tipos de blocos funcionais quadrados que recebem duas entradas, uma do lado superior e outra do lado esquerdo, e têm duas saídas, uma no lado direito e outra no lado inferior. Cada uma de suas saídas é uma função separada de ambas as entradas.

Por exemplo, se #representa um bloco genérico, a saída correta Ré uma função fdas entradas Te L, e a saída inferior Bé outra função gde Te L:

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

(Os blocos são denominados "duo", pois existem duas funções, e "diádico", pois as duas funções têm dois argumentos .)

Os ladrilhos podem então ser compostos juntos em uma grade, as saídas de um ladrilho indo diretamente para as entradas dos ladrilhos vizinhos. Aqui, por exemplo, a saída direita da esquerda #entra na entrada esquerda da direita #:

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

Você pode imaginar que, dado um conjunto de blocos duodádicos, cada um com funcionalidade específica, composições complexas (e potencialmente úteis) possam ser feitas.

Neste desafio, nos preocuparemos apenas com o conjunto tradicional de dez blocos duodádicos baseados em lógica , em que todas as entradas e saídas são números binários de bit único (zeros ou uns). Usaremos um caractere ASCII separado para denotar cada tipo de bloco.

Os caracteres do bloco e suas relações de entrada e saída são os seguintes:
( Té para entrada superior, Lentrada esquerda, Rsaída direita,B saída inferior).

  1. Zero: 0ou (espaço) → R = 0,B = 0
  2. Um: 1R = 1,B = 1
  3. Cruz: +R = L,B = T
  4. Espelho: \R = T,B = L
  5. Somente no topo: UR = T,B = T
  6. Apenas à esquerda: )R = L,B = L
  7. Não: !R = not L,B = not T
  8. E: &R = L and T,B = L and T
  9. Ou: |R = L or T,B = L or T
  10. Xor: ^R = L xor T,B = L xor T

Desafio

Escreva um programa ou função que 0 1+\U)!&|^consiga uma grade retangular de caracteres que represente um "circuito" feito usando os dez ladrilhos duodádicos baseados em lógica. Você também precisa inserir duas cadeias de 0's e 1' s; uma será a coluna de entrada esquerda e a outra será a linha de entrada superior. Seu programa / função precisa imprimir / retornar a linha de saída inferior e a coluna de saída direita (também em 0's e1 ' s).

Por exemplo, nesta grade

+++
+++

todas as entradas fluem diretamente pela grade para as saídas

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

portanto, uma entrada de 010/ 01teria saída 010/ 01:

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

A saída exata do seu programa seria [bottom output row]\n[right output column]ou [bottom output row]/[right output column]:

010
01

ou

010/01

Se você escreveu uma função, você pode retornar as duas strings em uma tupla ou lista (ou ainda imprimi-las).

Detalhes

  • Pegue as três entradas como seqüências de caracteres de qualquer maneira razoável (de preferência na grade de pedidos, linha superior, coluna esquerda): linha de comando, arquivo de texto, sdtin, função arg.
  • Você pode assumir que os comprimentos de linha e coluna de entrada corresponderão às dimensões da grade e conterão apenas 0's e 1' s.
  • Sua grade deve usar os caracteres adequados ( 0 1+\U)!&|^). Lembre-se disso 0e signifique a mesma coisa.

Casos de teste

(Leia E / S como top/ leftbottom/ right.)

Nand:

&!

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

Todos:

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

Qualquer entrada deve resultar em 1111/ 1111.

Xor de Nand: (observe a coluna de espaços finais)

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

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

Ziguezague:

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

O primeiro bit da entrada esquerda se torna o último bit da saída direita. Tudo o resto é 0.

000000000000/ 000000000000000/ 000
000000000000/ 100000000000000/001

Propagação:

)))
UUU
U+U
U+U
UUU

O primeiro bit da entrada esquerda vai para todas as saídas.

000/ 00000000/ 00000
000/ 10000111/11111

Aqui está uma pasta de todos os casos de teste de grade 1 × 1.

Pontuação

O menor envio em bytes vence.

Bônus: Que "circuitos" legais você pode fazer?

PS: Não se incomode com o Google "azulejos duodádicos". Eu as criei ontem; D
Se você quiser discutir a expansão dessa idéia em uma linguagem de programação completa, venha para esta sala de bate-papo .

Passatempos de Calvin
fonte
11
+1 para um desafio bacana, mas também porque você inventou peças duodádicas, o que é MUITO legal.
Alex A.
3
+1 É realmente inútil pesquisar no google: goo.gl/zuqfdW . Bom desafio!
BrainSteel
Eu estou com eles. Estou muito mais interessado nos seus ladrilhos como linguagem de programação do que neste desafio de golfe em particular. PS: Existem 16 peças possíveis, portanto, apresentar letras / nomes para as outras seis seria legal.
Sparr
Seria interessante ter blocos com saída / entrada de direções diferentes, porque, caso contrário, você não pode fazer uma trava, pois tudo flui na direção inferior direita.
Sp3000
2
Você pode alterar T / B para U (p) / D (próprio), para que possamos ter F / B de maneira análoga à notação do cubo de Rubik, e então. . . cubos tritriadicos?
Soham Chowdhury

Respostas:

8

Pyth, 122

Tipo de monstro. Usa simplesmente recursão, nada extravagante como programação dinâmica.

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

Demonstração online .

A entrada é da seguinte maneira: Primeiro a grade (sem escape, sem símbolos extras) e, em seguida, as duas linhas de entrada, por exemplo (Zig zag)

+++\00000000
000\!!!!\000
00000000\+++
000000000000
100
Jakube
fonte
8

Mathematica, 331 276 270 267 264 262 252 250 bytes

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

o é um caractere Unicode de uso privado que o Mathematica usa como sobrescrito T, ou seja, é o operador de transposição.

Aqui está uma versão mais legível:

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

Esta é uma função sem nome que pega as três seqüências de caracteres para as entradas de grade, superior e esquerda e imprime as saídas inferior e direita.

Explicação

Vamos seguir este passo a passo (tentarei não assumir nenhum conhecimento do Mathematica). Você precisa ler o código de trás para frente. O algoritmo básico apenas varre as linhas computando cada função e armazenando os resultados emf para serem acessados ​​pelos blocos subsequentes.

Processamento de entrada

É esse pedaço:

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

Isso apenas divide a grade em uma lista aninhada de caracteres (observe que eu defini hcomo um alias para Characteralgum lugar no código) e, em seguida, precede uma linha e uma coluna com as entradas. Isso funciona, porque 1e 0também são os nomes dos blocos de função constante; portanto, colocá-los na mesma tem o mesmo efeito que alimentar as entradas manualmente. Como essas são funções, elas tecnicamente receberão sua entrada de fora da grade, mas, como são funções constantes, isso não importa. O canto superior esquerdo recebe uma0 mas isso é bastante arbitrário, pois os resultados desse bloco nunca são usados.

Observe também a transposição. A adição de colunas ocupa mais caracteres do que a adição de linhas, por isso transponho a grade depois de adicionar a linha superior. Isso significa que as partes superior / inferior e esquerda / direita são trocadas pela parte principal do programa, mas são completamente trocáveis, portanto não importa. Eu só preciso garantir os resultados na ordem correta.

Resolvendo a grade

(Esta seção está um pouco desatualizada. Será corrigida assim que tiver certeza de que terminei de jogar golfe).

Em seguida, executamos MapIndexedo nível interno dessa lista aninhada. Isso chama a função anônima fornecida como o primeiro argumento para cada caractere na grade, também fornecendo uma lista com as duas coordenadas atuais. A grade é atravessada em ordem, para que possamos calcular com segurança cada célula com base nas anteriores.

Usamos as variáveis r(ight) e b(ottom) como tabelas de pesquisa para os resultados de cada célula. Nossa função anônima possui as coordenadas atuais em#2 , obtemos as entradas para qualquer célula com

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

Observe que na primeira linha e coluna isso acessará valores indefinidos de r eb . O Mathematica realmente não tem um problema com isso e apenas devolve suas coordenadas, mas descartamos esse resultado de qualquer maneira, pois todos os blocos nessa linha / coluna são funções constantes.

Agora essa coisa:

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

É uma forma de golfe

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

Por sua vez, é uma função que, dadas as duas entradas do bloco, retorna uma Associação (você chamaria de hashmap ou tabela em outros idiomas), que contém todos os resultados possíveis do bloco para essas duas entradas. Para entender como todas as funções são implementadas, você precisa saber que o primeiro argumento dessa função pode ser acessado com #e o segundo com #2. Além disso,## fornece uma sequência de ambos os argumentos que podem ser usados ​​para "dividir" os argumentos.

  • 0: é simples, basta retornar uma constante {0, 0}e também atribuí-la az para uso futuro (por exemplo, no espaço).
  • 1: é essencialmente justo {1,1}, mas zreduzi-lo para isso 1+z. Também salvamos isso o, porque será útil para todos os blocos em que ambas as saídas são idênticas.
  • +: Aqui fazemos uso da sequência. {##}é o mesmo {#,#2}e passa as duas entradas inalteradas.
  • \: Trocamos os dois argumentos, {#2,#} ,.
  • U: Agora podemos fazer uso o. o#2significa{1,1}*#2 que apenas colocamos o argumento principal em ambas as saídas.
  • ): Analogamente para o argumento da esquerda: o# .
  • !: Bitwise not não é chato no Mathematica, mas como só temos 0e 1podemos subtrair ambas as entradas 1(invertendo-as) e repassá-las:1-{##} .
  • &: Este é bastante bacana. Primeiro, notamos que bit a bit e para 0e 1é idêntico à multiplicação. Além disso, o##é o mesmo queo*#*#2 .
  • |: Novamente, usamos uma função equivalente. Bit a bit ou é o mesmo que Maxneste caso, então aplicamos Maxaos argumentos de entrada e multiplicamos o resultado em {1,1}.
  • ^: O mais curto que encontrei para o xor é pegar a diferença e quadrá-la (para garantir a positividade), então temos o(#-#2)^2.

Após essa função concluir e retornar a associação completa, usamos o caractere da célula atual para extrair o elemento em que estamos interessados ​​e armazená-lo re b. Observe que esse também é o valor de retorno da função anônima usada noMapIndexed , portanto, o mapeamento me fornecerá uma grade de todos os resultados.

Processamento de saída

MapIndexedretorna uma grade 3D, onde a primeira dimensão corresponde à coordenada da grade horizontal (lembre-se da transposição anterior), a segunda dimensão corresponde à coordenada da grade vertical e a terceira indica se temos uma saída inferior ou esquerda. Observe que isso também contém a linha e a coluna de entrada das quais precisamos nos livrar. Então, acessamos a saída inferior da linha inferior com

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

e a saída correta da coluna final com

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

Observe que 2;;é um intervalo do segundo ao último elemento.

Por fim, aplicamos Printa ambos (usando @@@como o açúcar sintático para o segundo nível Apply), que apenas imprime todos os seus argumentos lado a lado (e, como é aplicado a duas expressões separadas, haverá uma nova linha entre inferior e saída direita).

Martin Ender
fonte
8

C, 332 309 272 270 266 259 247 225 bytes

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

Veja os resultados online aqui!

Isso define uma função void f(char*, char*, char*), que deve considerar o quadro como sua primeira entrada, a linha superior da entrada e a linha esquerda da entrada.

Aqui está o que eu costumava testá-lo:

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

Assim, inserindo o multiplicador de 2 bits do Sp3000:

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

Nós temos:

00001001
11111111

Em outra nota, com o meio adicionador do Sp3000 em mente, eu gostaria de ver um adicionador completo ... Um de vocês conseguiu! Eu não acho que o sistema se sustente por si só como uma linguagem de programação, mas tem sido muito interessante. Este parece ser um excelente alvo para o metagolfe!

Uma breve explicação:

Aqui está o código comentado e desvendado:

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

Repetimos c, da esquerda para a direita (de cima para baixo), reescrevendo as tentradas a cada vez e pressionando uma saída mais à direita, que é inserida na lstring. Podemos imaginar isso substituindo a linha superior de ccom 1s e 0iterativamente, e acompanhando os bits que são empurrados para a direita.

Aqui está uma sequência mais visual, linha por linha:

 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.

Obviamente, isso se torna mais complicado com símbolos e tamanhos diferentes, mas a ideia central é válida. Isso funciona apenas porque os dados nunca fluem para cima ou para a esquerda.

BrainSteel
fonte
Muito potencial para jogar golfe! Comece alterando o cabeçalho de fpara f(c,t,l)char*c,*t,*l(não dê a mínima para o tipo de retorno).
FUZxxl 20/03/2015
@FUZxxl Alguém mencionou isso no chat, mas não consegui fazê-lo funcionar. Esse comportamento é padrão? O LLVM lança pelo menos 2 erros nessa linha.
BrainSteel
Desculpe. Deveria ter sido f(c,t,l)char*c,*t,*l;. Não compile no modo C11, pois a regra int implícita que nos permite descartar o tipo de retorno foi descartada nessa revisão.
FUZxxl 21/03/2015
@FUZxxl Parece também falhar no C99. De fato, todos os modos em que defini o compilador rejeitaram esse código.
BrainSteel
Você adicionou o ponto e vírgula logo após *l? Compila no modo C99 na minha máquina.
FUZxxl 21/03/2015
7

Python 2, 316 bytes

Essa função cria 10 funções lambda de bloco e itera pela grade, atualizando os estados lógicos. Os estados lógicos verticais e horizontais finais são impressos.

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)

O código não protegido, incluindo testes:

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

O test.txtarquivo (incluindo outros 2 testes do 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

A saída do teste:

------------------
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
Cavaleiro Lógico
fonte
7

Python 2, 384 338 325 bytes

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

Sério CH, se este ainda não é um brinquedo, você deve começar a ligar para algumas fábricas de brinquedos.

Mais jogado e muito menos eficiente agora, mas ainda não alcançou o CarpetPython. Entrada como f("1111\n1\\+\\\n1+\\+\n1\\+\\","0101","1010"), saída é uma tupla de duas strings. Certifique-se de que o quadro não tenha uma nova linha à direita, o que quebrará as coisas.

Programa de teste

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

Você também pode testar todos os casos possíveis com test_all().

Casos de teste extras

Meio adicionador

Aqui está um meio somador que adiciona os bits superiores esquerdos, produzindo <input bit> <carry> <sum>:

+))
U&+
U+^

Testes:

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

A saída deve ser a mesma, mesmo que os segundos / terceiros bits das entradas sejam alterados.

Deslocamento para a direita

Dado abc / def, isso gera fab / cde:

\\\
\++
\++

Testes:

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

Classificador de 3 bits

Classifica os três primeiros bits do topo nos últimos três bits do fundo. A saída correta é lixo.

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

Testes:

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

Multiplicador de 2 por 2 bits

Toma o 1º / 2º bits de topo como o primeiro número e o 3º / 4º bits de topo como o segundo número. Saídas para os últimos quatro bits da parte inferior. A saída correta é lixo.

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

Edit: Jogou fora uma coluna e duas linhas.

Testes:

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
fonte
1

R, 524 517

Provavelmente há muito espaço para reduzir isso no momento, mas isso tem sido realmente interessante de se fazer. Existem duas funções. A função d é o trabalhador ef é o comparador.

A função d é chamada com 3 strings, Gates, Top e Left. Os Gates são colocados em uma matriz determinada pela largura.

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

Formatado um pouco

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

Alguns testes

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