Un simple calculateur de porte logique


9

Votre mission, si vous choisissez de l'accepter, est de construire un simple évaluateur de vérité pour les opérateurs logiques suivants:

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

Les tables de vérité sont dans l'ordre suivant:

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

L'entrée viendra comme une simple chaîne de 0, 1 et le symbole. Vous pouvez soit accepter l'entrée en tant que paramètre, soit la lire à l'utilisateur sur stdin. Voici quelques exemples de paires d'entrée / sortie:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

L'opérateur unaire (négation) apparaîtra toujours avant la valeur booléenne, tandis que les opérateurs binaires apparaîtront toujours entre les deux valeurs booléennes. Vous pouvez supposer que toutes les entrées seront valides. Les chaînes sont des chaînes ASCII normales.

Si vous préférez, vous pouvez utiliser T et F plutôt que 1 et 0. -6 pour votre nombre de personnages si vous supportez les deux.

C'est le : le code le plus court dans n'importe quelle langue gagne!


3
Je crois que ^le nom du symbole de devrait dire caret .
FireFly

3
@FireFly Haha, vous avez raison. Trop près du déjeuner! Merci.
asteri

Réponses:


6

APL (45 - 6 = 39)

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

Prend en charge Tet Fen entrée, mais toujours en sortie 0ou 1.

Explication:

  • Z←⍞: lire une ligne et la stocker dans Z
  • L←'TF&|^vx>'⍳Z: récupère l'index 'TF&|^vx>'pour chaque caractère dans Z, donnant 9si le caractère n'est pas dedans 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: recherchez le caractère correspondant dans '10∧∨⍲⍱≠≤*'. (Donc, les personnages qui n'étaient pas dans la première liste deviennent *).
  • ↓⍉Z⍪⍉⍪: transformez-le en une matrice, placez l'original ( Z) dessus et divisez-le en une liste de chaînes, où le premier caractère est l'original et le deuxième caractère est sa traduction, le cas échéant.
  • (1+9≠L)⌷¨: pour chacune de ces chaînes, obtenez le premier caractère s'il n'y a pas de traduction (si L=9à cet endroit) et le deuxième caractère s'il y en a.
  • Exemple: si l'entrée avait été T|0, nous aurions 1∨0maintenant quelle est l'expression APL correspondante
  • : eval

Remarque: ~et =faites déjà la bonne chose afin qu'ils n'aient pas besoin d'être remplacés par quoi que ce soit.


Très agréable! Il s'agit d'une approche de traduction en APL et évaluation, non? Je réfléchissais à une approche basée sur les gérondifs en J, mais je ne sais pas comment diviser intelligemment les opérandes. : \
FireFly

Pourquoi faire une manipulation de matrice alors que vous pouvez simplement ajouter des règles de traduction pour des caractères sans changement comme ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Score 33-6 = 27)
TwiNight

8

C - 165 127

C'était amusant! Table de recherche simple reposant sur un décalage fixe pour la recherche.

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

Pour une raison quelconque getsne j'ai enlevé l'inclure, alors quand se implicitement déclaré ne pas que je devais changer gets(t+2)de (gets(t+2),t)(ou de la même ailleurs, ce qui coûte le plus).


Explication

Tout d'abord, comme les tables de vérité pour les opérateurs ont beaucoup de caractères qui se chevauchent, nous souhaitons stocker les tables de recherche de manière à permettre le chevauchement. Voici comment j'ai choisi de les stocker:

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)

Ensuite, nous voulons mapper les symboles d'opérateur à ces décalages. Pour ce faire, nous stockons les symboles d'opérateur dans la même chaîne à un décalage fixe des données LUT (à savoir, 16 caractères plus tard, c'est-à-dire directement après les données LUT). Le processus de recherche est "trouver l'opérateur dans s, soustraire 16, ajouter left*2+right(opérande gauche / droite). Pour la recherche de" l'opération d'identité "vide, en raison de la façon dont l'entrée est récupérée, l'opérateur dans ce cas se résoudra en tout ce qui t[1]est initialisé pour- -dans notre cas /. Ainsi, nous utilisons /comme clé de table de consultation pour représenter l'opération d'identité. Lorsque nous traitons l' ~opération unaire " left" (pour le calcul de recherche mentionné précédemment) est toujours la même / . /se trouve être un de moins que0ASCII-sage, ce qui signifie que lorsque nous compensons les chiffres ASCII \représentera -1. La barre oblique dans la zone clé de la table de recherche (avant-dernier caractère dans s, c'est-à-dire) est positionnée pour compenser cela.

Ensuite, la gestion des entrées. L'entrée a une longueur dynamique, mais ce serait plus facile si nous avons des noms statiques spécifiques pour l'opérande gauche, l'opérateur et l'opérande droit, quelle que soit l'entrée. Si nous prétendons que nous pourrions lire l'entrée de droite à gauche, cela se produira essentiellement de manière automagique - l'opérande de droite est toujours le caractère le plus à droite, l'opérateur (s'il est présent) est de gauche à droite, l'opérande de gauche (s'il est présent ) est le troisième à droite. Afin de pouvoir indexer la chaîne comme ceci, nous utilisons strchrpour localiser le \0terminateur ( - 3pour simplifier l'indexation). Cela montre pourquoi t[0]et t[1]devient l'opérande / opérateur gauche respectivement lorsque l'entrée est de 1 ou 2 caractères.

En le rassemblant, la sortie serait putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), mais un refactoring et un pliage constant nous raccourcissent putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).


Pourriez-vous expliquer comment cela fonctionne?
Johannes Kuhn

Le chevauchement de la table de vérité était une idée géniale. Je n'aurais jamais pensé à ça moi-même. :)
asteri

Aussi la lecture de droite à gauche. Je savais que l'entrée et le positionnement à longueur variable poseraient un défi, et c'est un excellent moyen de le résoudre. Vraiment une excellente pensée prête à l'emploi. Vous souhaitez venir travailler dans mon équipe de développement? Haha
asteri

4
Je pense que plus de réponses devraient avoir des explications comme celle-ci. Aide ceux d'entre nous qui apprennent encore beaucoup! (Et par ceux qui apprennent encore à peu près tout le monde)
agweber

@agweber: C'est bon à entendre, j'étais un peu inquiet de mon explication. Et oui, probablement tout le monde ici est dans une phase "d'apprentissage en cours" .. enfin, au moins je sais que je le suis.
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

Non 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

Je pense que la ligne foreach a besoin d'explications:

  • split $argv {} divise la chaîne d'entrée (c'est en fait une liste, mais code-golf) en ses caractères.
  • string map {{~ 0} 1 {~ 1} 0} ...prend une chaîne et remplace ~ 0par 1et ~ 1par0
  • lassign ... a prend le premier élément de la liste et l'assigne à la variable a, renvoie le reste.
  • foreach {op b} ... {code}parcourt la liste et prend 2 éléments à chaque fois: opetb
  • set a [$op $a $b]exécute la commande dans la variable op, stocke le résultat dansa

3

JavaScript - 107 105 caractères

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)

Haha, chouette. C'est pratique. Je n'ai même pas pensé à eval()quand j'ai inventé ça. Donnez-moi juste un peu pour rentrer à la maison et tester.
asteri

1
nand = &~et nor = |~?
Johannes Kuhn

@Johannes: Ce n'est pas vraiment &~et |~, mais NAND est juste l'inverse de AND. Ainsi, inverser l'un des bits inverse également le résultat.
ProgramFOX

3

Befunge- 98-104101 98-6 72

... parce que chaque tâche a besoin d'une solution esolang .. traduction de mon implémentation C, mais traitement des caractères un par un à la place.

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

Fait amusant: changez le @en a,$et vous obtenez un REPL sans fin fantaisie à la place (cependant, si vous faites cela, vous remarquerez que l'identité est en fait "répéter la dernière commande avec lhs = 0 et rhs = input", ce qui arrive par défaut à l'identité ). Le REPL n'est plus.

Non golfé (version antérieure):

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: inspiré par la solution de @jpjacobs, je me fie maintenant à la position des caractères dans la LUT pour représenter les tables de vérité. Par exemple, |est sur la position 1110 2 = 14 car cela correspond à la table de vérité pour |.


C'est fou. Ok, chaque solution dans befunge est folle.
Johannes Kuhn

2

J - 65 67-6 = 61

Plus le b. Adverbe. Sans compter l'affectation de la fonction: 67 caractères pour la version TF, 63 pour la version non TF:

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

LgcTF gère à la fois 0 et 1 ainsi que T et F.

Prend en charge toute la syntaxe de J en termes de trains, de parenthèses et évalue strictement de droite à gauche (pas d'autres règles de priorité).

Tous les caractères ne figurant pas dans la liste d'opérateurs + Z ne peuvent pas être utilisés, les autres agiront comme dans le standard J (y compris les variables).

Usage:

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

1

Post-scriptum 263

L'idée de Firefly traduite en 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

Dentelé:

%!

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

1

Befunge-93, 86 personnages

Fonctionne en hachant le deuxième symbole de l'entrée (trouver une fonction à la fois compacte et évitée les collisions était un travail) pour la coordonnée ay, et en prenant les premier et troisième symboles chaque modulo 2 comme les deux bits les moins significatifs de la coordonnée x, puis récupérer n'importe quelle valeur à la position indiquée. Une meilleure fonction de hachage ou une méthode plus compacte de stockage / adressage des tables de vérité ne sont que deux façons possibles de réduire la longueur.

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







1001
0001
1101
1

0
0110



1110
1000


0111
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.