Uma calculadora simples de porta lógica

9

Sua missão, se você optar por aceitá-la, é construir um avaliador simples da verdade para os seguintes operadores lógicos:

----------------------------------------------------------------------------------
  Logical Name          |  Gate Name   |  Symbol  |  Symbol Name  |  Truth Table
----------------------------------------------------------------------------------
  Identity              |  is          |          |  (none)       |  10
  Negation              |  not         |    ~     |  tilde        |  01
  Conjunction           |  and         |    &     |  ampersand    |  1000
  Disjunction           |  or          |    |     |  pipe         |  1110
  Negative Conjunction  |  nand        |    ^     |  caret        |  0111
  Joint Denial          |  nor         |    v     |  "vee"        |  0001
  Exclusive Disjunction |  xor         |    x     |  "ecks"       |  0110
  Equivalence           |  equals/xnor |    =     |  equals       |  1001
  Implication           |  implies     |    >     |  greater than |  1011

As tabelas de verdade estão na seguinte ordem:

  1. 1 1
  2. 1 0
  3. 0 1
  4. 0 0

A entrada virá como uma sequência simples de 0, 1 e o símbolo. Você pode aceitar a entrada como um parâmetro ou lê-la do usuário no stdin. Aqui estão alguns pares de entrada / saída de amostra:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

O operador unário (negação) sempre aparecerá antes do valor booleano, enquanto os operadores binários sempre aparecerão entre os dois valores booleanos. Você pode assumir que todas as entradas serão válidas. Strings são regulares ASCII.

Se preferir, você pode usar T e F em vez de 1 e 0. -6 para a contagem de caracteres, se você suportar os dois.

Este é o : o código mais curto em qualquer idioma vence!

asteri
fonte
3
Eu acredito que ^o nome do símbolo deve dizer sinal de intercalação .
FireFly
3
@FireFly Haha, você está certo. Muito perto do almoço! Obrigado.
Asteri # 7/13

Respostas:

6

APL (45 - 6 = 39)

⍎(1+9≠L)⌷¨↓⍉Z⍪⍉⍪'10∧∨⍲⍱≠≤*'[L←'TF&|^vx>'⍳Z←⍞]

Suporta Te Fcomo entrada, mas sempre exibirá 0ou 1.

Explicação:

  • Z←⍞: leia uma linha e guarde-a em Z
  • L←'TF&|^vx>'⍳Z: obtém o índice 'TF&|^vx>'para cada caractere Z, indicando 9se o caractere não está 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: encontre o caractere correspondente em '10∧∨⍲⍱≠≤*'. (Assim, os personagens que não estavam na primeira lista se tornam *).
  • ↓⍉Z⍪⍉⍪: faça isso em uma matriz, coloque o original ( Z) em cima e divida-o em uma lista de cadeias, onde o primeiro caractere é o original e o segundo caractere é a sua tradução, se houver.
  • (1+9≠L)⌷¨: para cada uma dessas cadeias, obtenha o primeiro caractere se não houver tradução (se estiver L=9nesse local) e o segundo caractere se houver.
  • Exemplo: se a entrada tivesse sido T|0, teríamos 1∨0agora qual é a expressão APL correspondente
  • : eval

Nota: ~e =já faça a coisa certa para que eles não precisem ser substituídos por nada.

marinus
fonte
Muito agradável! Essa é uma abordagem de conversão para APL e avaliação, certo? Eu estava pensando em uma abordagem baseada em gerúndio em J, mas não sei como dividir os operandos de maneira inteligente. : \
FireFly
Por que a manipulação de matrizes quando você pode simplesmente adicionar regras de conversão para caracteres que não mudam ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Pontuação 33-6 = 27)
TwiNight 14/10
8

C - 165 127

Foi divertido! Tabela de pesquisa simples que depende de um deslocamento fixo para a pesquisa.

main(){
  char*s="100011001110110v& x = |^> /~",
       t[6]="0/xxx",
      *u= strchr((gets(t+2),t),0)-3;
  putchar(strchr(s,u[1])[*u*2+u[2]-159]);
}

Por algum motivo gets, não é declarado implicitamente; portanto, quando removi o include, tive que mudargets(t+2) para (gets(t+2),t)(ou similarmente em outro lugar, custando tanto).


Explicação

Antes de tudo, como as tabelas verdadeiras para os operadores têm muitos caracteres sobrepostos, queremos armazenar as tabelas de pesquisa de uma maneira que permitamos a sobreposição. Aqui está como eu escolhi armazená-los:

v    &    x    =    |    ^    >       ~     (operation)
1000 0001 0110 1001 0111 1110 1101 01 10    (truth table [order 00,01,10,11])
0    1    3    5    7    8    9    B  D     (offset in LUT below)

0123456789ABCDE   (offsets)
100011001110110   (values)

Em seguida, queremos mapear os símbolos do operador para esses deslocamentos. Fazemos isso armazenando os símbolos do operador na mesma string em um deslocamento fixo dos dados do LUT (ou seja, 16 caracteres depois, ou seja, diretamente após os dados do LUT). O processo de pesquisa é "localizar operador em s, subtrair 16, adicionar left*2+right(operando esquerdo / direito). Para a pesquisa da" operação de identidade "vazia, devido à maneira como a entrada é buscada, o operador nesse caso resolverá o que t[1]for inicializado para- -no nosso caso /. Assim, utilizamos /como a chave tabela de pesquisa para representar a operação de identidade. quando processar o unário ~operação "left " (para o cálculo de pesquisa mencionado anteriormente) é sempre esta mesma / . /passa a ser um a menos que0Em termos ASCII, significa que quando compensarmos os dígitos ASCII \representará -1. A barra na área de chave da tabela de pesquisa (penúltimo caractere s, isto é) é posicionada para compensar isso.

Em seguida, manipulação de entrada. A entrada possui comprimento dinâmico, mas seria mais fácil se tivéssemos nomes estáticos específicos para o operando esquerdo, operador e operando direito, independentemente da entrada. Se fingirmos que poderíamos ler a entrada da direita para a esquerda, isso basicamente aconteceria automagicamente - o operando direito é sempre o caractere mais à direita, o operador (se presente) é a segunda à direita, o operando esquerdo (se presente) ) é a terceira à direita. Para poder indexar a string como esta, usamos strchrpara localizar o \0terminador ( - 3para simplificar a indexação). Isso mostra o porquê t[0]e t[1]se torna o operando / operador esquerdo, respectivamente, quando a entrada possui 1 ou 2 caracteres.

Juntando tudo, a saída seria putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), mas algumas refatorações e dobragens constantes nos deixam mais curtos putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).

FireFly
fonte
Você poderia explicar como isso funciona?
Johannes Kuhn
A sobreposição da mesa da verdade foi uma ideia brilhante. Eu nunca teria pensado nisso. :)
Asteri
Também a leitura da direita para a esquerda. Eu sabia que a entrada de comprimento variável e o posicionamento representariam um desafio, e essa é uma ótima maneira de resolvê-lo. Realmente excelente pensamento pronto para uso. Quer vir trabalhar na minha equipe de desenvolvimento? Haha
asteri 07/10
4
Eu acho que mais respostas devem ter explicações como essa. Ajuda aqueles de nós que ainda estão aprendendo um pouco considerável! (E por aqueles que ainda estão aprendendo praticamente meio a todos)
agweber
@agweber: É bom ouvir isso, fiquei um pouco preocupado com a minha explicação. E sim, provavelmente todos aqui estão em uma fase "ainda aprendendo" ... bem, pelo menos eu sei que estou.
FireFly
4

Tcl, 212 208-6 = 202

proc o n\ e {proc $n a\ b expr\ $e}
o > {$a<=$b}
o v {!($a|$b)}
o x {$a^$b}
o ^ {!($a&$b)}
namespace pat tcl::mathop 
lmap o\ b [lassign [split [string map {~0 1 ~1 0} $argv] {}] a] {set a [$o $a $b]}
puts $a

Ungolfed:

# Defines an operator
proc operator {name expression} {
    proc $name {a b} "expr $expression"
}
operator > {$a<=$b}
operator v {!($a|$b)}
operator x {$a^$b}
operator ^ {!($a&$b)}
# Call the commands in ::tcl::mathop if the command is not in the global namespace
namespace path tcl::mathop
# lmap instead foreach
# assume that we only got 1 argument.
foreach {op b} [lassign [string map {{~ 0} 1 {~ 1} 0} [split $argv {}]] a] {
   set a [$op $a $b]
}
puts $a

Eu acho que a linha foreach precisa de alguma explicação:

  • split $argv {} divide a string de entrada (na verdade é uma lista, mas codifica golfe) em seus caracteres.
  • string map {{~ 0} 1 {~ 1} 0} ...pega uma string e substitui ~ 0por 1e ~ 1por0
  • lassign ... a pega o primeiro elemento da lista e o atribui à variável a, retorna o restante.
  • foreach {op b} ... {code}percorre a lista e utiliza 2 elementos de cada vez: opeb
  • set a [$op $a $b]executa o comando na variável op, armazena o resultado ema
Johannes Kuhn
fonte
3

JavaScript - 107 105 caracteres

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
fonte
Haha, legal. Isso é útil. Nem sequer pensei em eval()quando eu inventei isso. Apenas me dê um pouco para chegar em casa e testá-lo.
Asteri # 7/13
11
nand = &~e nem = |~?
Johannes Kuhn,
@ Johannes: Não é realmente &~e |~, mas NAND é apenas o inverso de AND. Inverter um dos bits também inverte o resultado.
ProgramFOX
3

Befunge-98 - 104 101 98-6 72

... porque toda tarefa precisa de uma solução esolang .. tradução da minha implementação C, mas processando caracteres um de cada vez.

#v~
2_vp5a00+*2%2\p10\%
0:<+1_v#-g5\g1
1_|#:\</2\-
.@>2%
 v   ~x^&=.>  |

Curiosidade: mude @para a,$e você obtém um REPL sofisticado e interminável (no entanto, se você fizer isso, perceberá que a identidade é realmente "repita o último comando com lhs = 0 e rhs = input", que por padrão é a identidade. ) O REPL não existe mais.

Ungolfed (versão anterior):

v10001100111011v& x = |^>~
  $       1111111111222222
 1234567890123456789012345

 [read input]
> ~ :a- #v_   $ 21g " "- + 0g , @

v p11:   <
   ↑save chr

0 ←lup   [traverse LUT]
> 1+  :11g  \0g -! #v_
 v                  <
    lup chr acc
v>  :3` #v_  $"0"-\2*+

               v>   . , a,
 v       <
v> 9+9+ 21p $

Edit: inspirado na solução @jpjacobs, agora confio na posição dos caracteres na LUT para representar tabelas de verdade. Por exemplo, |está na posição 1110 2 = 14 porque isso corresponde à tabela verdade para |.

FireFly
fonte
Isso é louco. Ok, toda solução no befunge é louca.
Johannes Kuhn,
2

J - 65 67-6 = 61

Não mais o b. Advérbio. Sem contar a atribuição da função: 67 caracteres para a versão TF, 63 para a versão não TF:

lgcTF =:".@({&('*+-+-<*01',.3 6#'.:')"1@n^:(9>n=:'&|~xv>^FT'&i.)@{.&.>&.;:)
lgc   =:".@({&('*+-+-<*',.3 4#'.:')"1@n^:(7>n=:'&|~xv>^'&i.)@{.&.>&.;:)

LgcTF lida com 0 e 1, bem como com T e F.

Suporta toda a sintaxe de J em termos de trens, parênteses e avalia estritamente da direita para a esquerda (nenhuma outra regra de precedência).

Todos os caracteres que não estão na lista de operadores + Z não podem ser usados, outros atuarão como no padrão J (incluindo variáveis).

Uso:

NB.Assign TF anyhow
T=:1 [ F=: 0
lgc 'T & F'
0
lgc ' T ~@& F' NB. negation after and = nand
NB. make a truth table
d=: 0 1
lgc 'd ~@|/ d'
1 0
0 0 
NB. and so on... 
jpjacobs
fonte
1

Postscript 263

A ideia de Firefly foi traduzida para Postscript.

{(0/xxx)dup 2 3 getinterval(%lineedit)(r)file exch 
readstring pop length 1 sub 3
getinterval(100011001110110v& x = |^> /~)dup
2 index 1 1 getinterval search pop exch pop exch pop 
length 3 2 roll{}forall exch pop exch 2 mul add 159 sub add 
1 getinterval =}loop

Recuado:

%!

{
    (0/xxx) dup 2 3 getinterval
    (%lineedit)(r)file exch % (0/xxx) file (xxx)
    readstring pop
    length % (0/xxx) len(x|xx|xxx)
    1 sub 3 getinterval % (0/x)|(/xx)|(xxx)
    (100011001110110v& x = |^> /~) dup
    2 index 1 1 getinterval search pop % (0/x)|(/xx)|(xxx) s post match pre
    exch pop exch pop % (xxx) s pre
    length 
    3 2 roll {} forall exch pop % s len(pre) u_0 u_2
    exch 2 mul add 159 sub add % s ind
    1 getinterval
    = flush
} loop
luser droog
fonte
1

Befunge-93, 86 caracteres

Funciona com hash do segundo símbolo da entrada (encontrar uma função que seja compacta e evitar colisões foi um pouco trabalhoso) para todas as coordenadas e pegar o primeiro e o terceiro símbolos de cada módulo 2 como os dois bits menos significativos da coordenada x; recuperando qualquer valor que esteja na posição indicada. Uma função de hash melhor ou um método mais compacto de armazenar / endereçar as tabelas verdadeiras são apenas duas maneiras possíveis de reduzir o comprimento.

~~~\:8/\5%:++00p2%\2%2*+00gg,@
0 1







1001
0001
1101
1

0
0110



1110
1000


0111
MDS
fonte