Una calculadora de puerta lógica simple

9

Su misión, si elige aceptarla, es construir un evaluador de verdad simple para los siguientes 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

Las tablas de verdad están en el siguiente orden:

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

La entrada vendrá como una cadena simple de 0, 1 y el símbolo. Puede aceptar la entrada como parámetro o leerla del usuario en stdin. Aquí hay algunos pares de entrada / salida de muestra:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

El operador unario (negación) siempre aparecerá antes del valor booleano, mientras que los operadores binarios siempre aparecerán entre los dos valores booleanos. Puede suponer que todas las entradas serán válidas. Las cadenas son cadenas ASCII normales.

Si lo prefieres, puedes usar T y F en lugar de 1 y 0. -6 para tu recuento de personajes si admites ambos.

Esto es : ¡el código más corto en cualquier idioma gana!

asteri
fuente
3
Creo que ^el nombre del símbolo debería decir caret .
FireFly
3
@FireFly Jaja, tienes razón. Demasiado cerca para el almuerzo! Gracias.
asteri

Respuestas:

6

APL (45-6 = 39)

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

Admite Ty Fcomo entrada pero siempre saldrá 0o 1.

Explicación:

  • Z←⍞: lee una línea y guárdala en Z
  • L←'TF&|^vx>'⍳Z: obtener el índice 'TF&|^vx>'para cada carácter Z, dando 9si el personaje no está en 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: encuentra el carácter correspondiente en '10∧∨⍲⍱≠≤*'. (Entonces se convierten en personajes que no estaban en la primera lista *).
  • ↓⍉Z⍪⍉⍪: haga esto en una matriz, coloque el original ( Z) encima y divídalo en una lista de cadenas, donde el primer carácter es el original y el segundo carácter es su traducción, si corresponde.
  • (1+9≠L)⌷¨: para cada una de estas cadenas, obtenga el primer carácter si no hubo traducción (si estaba L=9en ese lugar) y el segundo carácter si la hubo.
  • Ejemplo: si la entrada hubiera sido T|0, ya tendríamos 1∨0cuál es la expresión APL correspondiente
  • : eval

Nota: ~y =ya hacen lo correcto para que no necesiten ser reemplazados por nada.

marinus
fuente
¡Muy agradable! Este es un enfoque de traducir a APL y evaluar, ¿verdad? Estaba reflexionando sobre un enfoque basado en gerundio en J, pero no sé cómo dividir hábilmente los operandos. : \
FireFly
¿Por qué hacer una manipulación matricial cuando simplemente puede agregar reglas de traducción para caracteres sin cambios ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Puntuación 33-6 = 27)
TwiNight
8

C - 165 127

¡Eso fue divertido! Tabla de búsqueda simple basada en un desplazamiento fijo para la búsqueda.

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 alguna razón getsno consigue implícitamente declarado, así que cuando me quité el incluir tuve que cambiar gets(t+2)a (gets(t+2),t)(o de manera similar en otras partes, costando tanto).


Explicación

En primer lugar, dado que las tablas de verdad para los operadores tienen muchos caracteres superpuestos, deseamos almacenar las tablas de búsqueda de una manera que permita la superposición. Así es como elegí almacenarlos:

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)

A continuación, queremos asignar símbolos de operador a estos desplazamientos. Hacemos esto almacenando los símbolos del operador en la misma cadena en un desplazamiento fijo de los datos LUT (es decir, 16 caracteres más tarde, es decir, directamente después de los datos LUT). El proceso de búsqueda es "buscar operador en s, restar 16, sumar left*2+right(operando izquierda / derecha). Para la búsqueda de la" operación de identidad "vacía, debido a cómo se obtiene la entrada, el operador en este caso resolverá lo que t[1]se haya inicializado para- -en nuestro caso /. Por lo tanto, usamos /como la clave de la tabla de búsqueda para representar la operación de identidad. Cuando procesamos la ~operación unaria " left" (para el cálculo de búsqueda mencionado anteriormente) es siempre la misma / . /Resulta que es una menor que0En cuanto a ASCII, significa que cuando compensamos los dígitos ASCII \representaremos -1. La barra diagonal en el área clave de la tabla de búsqueda (penúltimo carácter s, es decir) se coloca para compensar esto.

A continuación, manejo de entrada. La entrada tiene una longitud dinámica, pero sería más fácil si tenemos nombres estáticos específicos para el operando izquierdo, el operador y el operando derecho, independientemente de la entrada. Si pretendemos que podríamos leer la entrada de derecha a izquierda, esto sucedería básicamente de forma automática: el operando derecho es siempre el carácter más a la derecha, el operador (si está presente) es el segundo a la derecha, el operando izquierdo (si está presente) ) es de la tercera a la derecha. Para poder indexar la cadena de esta manera, la usamos strchrpara ubicar el \0terminador ( - 3para simplificar la indexación). Esto muestra por qué t[0]y se t[1]convierte en el operador / operador izquierdo respectivamente cuando la entrada es de 1 o 2 caracteres.

Al unirlo, la salida sería putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), pero una refactorización y un plegado constante en su lugar nos acortan putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).

Luciérnaga
fuente
¿Podría explicar cómo funciona eso?
Johannes Kuhn
La superposición de la tabla de verdad fue una idea brillante. Nunca hubiera pensado en eso yo mismo. :)
asteri
También la lectura de derecha a izquierda. Sabía que la entrada de longitud variable y el posicionamiento plantearían un desafío, y esa es una excelente manera de resolverlo. Realmente excelente pensamiento fuera de la caja. ¿Quieres venir a trabajar en mi equipo de desarrollo? Jaja
asteri
44
Creo que más respuestas deberían tener explicaciones como esta. ¡Ayuda a aquellos de nosotros que todavía estamos aprendiendo un poco considerable! (Y para aquellos que todavía están aprendiendo casi todos significan)
2013
@agweber: Es bueno escuchar eso, estaba un poco preocupado por mi explicación. Y sí, probablemente todos aquí están en una fase de "todavía aprender" ... bueno, al menos sé que lo estoy.
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

Sin golf:

# 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

Creo que la línea foreach necesita alguna explicación:

  • split $argv {} divide la cadena de entrada (en realidad es una lista, pero code-golf) en sus caracteres.
  • string map {{~ 0} 1 {~ 1} 0} ...toma una cuerda y la reemplaza ~ 0por 1y ~ 1con0
  • lassign ... a toma el primer elemento de la lista y lo asigna a la variable a, devuelve el resto.
  • foreach {op b} ... {code}recorre la lista y toma 2 elementos cada vez: opyb
  • set a [$op $a $b]ejecuta el comando en la variable op, almacena el resultado ena
Johannes Kuhn
fuente
3

JavaScript - 107105 caracteres

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
fuente
Jaja bueno. Eso es útil. Ni siquiera pensé en eval()cuando inventé esto. Solo dame un poco para llegar a casa y probarlo.
asteri
1
nand = &~y nor = |~?
Johannes Kuhn
@Johannes: No es realmente &~y |~, pero NAND es solo el inverso de AND. Entonces, invertir uno de los bits también invierte el resultado.
ProgramFOX
3

Befunge- 98-104101 98-6 72

... porque cada tarea necesita una solución esolang ... traducción de mi implementación en C, pero procesando caracteres uno a la vez.

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

Dato curioso: cambie el @to a,$y obtendrá un REPL elegante e interminable en su lugar (sin embargo, si hace esto, notará que la identidad es en realidad "repita el último comando con lhs = 0 y rhs = input", que por defecto es el predeterminado a la identidad ) El REPL ya no existe.

Ungolfed (versión 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 $

Editar: inspirado en la solución de @jpjacobs, ahora confío en la posición de los personajes en la LUT para representar tablas de verdad. Por ejemplo, |está en la posición 1110 2 = 14 porque corresponde a la tabla de verdad para |.

Luciérnaga
fuente
Eso es loco. Ok, cada solución en Befunge es una locura.
Johannes Kuhn
2

J - 65 67-6 = 61

No más el b. Adverbio. Sin contar la asignación de la función: 67 caracteres para la versión TF, 63 para la versión no TF:

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

LgcTF maneja tanto 0 como 1, así como T y F.

Admite toda la sintaxis de J en términos de trenes, paréntesis y evalúa estrictamente de derecha a izquierda (no hay otras reglas de precedencia).

No se pueden usar todos los caracteres que no están en la lista de operadores + Z, otros actuarán como en el estándar J (incluidas las variables).

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

Posdata 263

La idea de Firefly traducida a 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

Sangrado:

%!

{
    (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
fuente
1

Befunge-93, 86 personajes

Funciona haciendo hash el segundo símbolo de la entrada (encontrar una función que sea compacta y evitar colisiones fue un trabajo) para una coordenada ay, y tomando el primer y el tercer símbolo de cada módulo 2 como los dos bits menos significativos de la coordenada x, luego recuperando cualquier valor que esté en la posición indicada. Una mejor función hash o un método más compacto de almacenamiento / direccionamiento de las tablas de verdad son solo dos formas posibles de reducir la longitud.

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







1001
0001
1101
1

0
0110



1110
1000


0111
MDS
fuente