Ein einfacher Logikgatterrechner

9

Wenn Sie sich dafür entscheiden, dies zu akzeptieren, besteht Ihre Mission darin, einen einfachen Wahrheitsbewerter für die folgenden logischen Operatoren zu erstellen:

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

Wahrheitstabellen sind in der folgenden Reihenfolge:

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

Die Eingabe erfolgt als einfache Zeichenfolge aus 0, 1 und dem Symbol. Sie können Eingaben entweder als Parameter akzeptieren oder vom Benutzer auf stdin lesen. Hier sind einige Beispiele für Eingabe- / Ausgabepaare:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

Der unäre Operator (Negation) wird immer vor dem booleschen Wert angezeigt, während die binären Operatoren immer zwischen den beiden booleschen Werten angezeigt werden. Sie können davon ausgehen, dass alle Eingaben gültig sind. Strings sind reguläre ASCII-Strings.

Wenn Sie es vorziehen, können Sie T und F anstelle von 1 und 0 verwenden. -6 für Ihre Zeichenanzahl, wenn Sie beide unterstützen.

Das ist : Der kürzeste Code in jeder Sprache gewinnt!

Asteri
quelle
3
Ich glaube ^, der Symbolname sollte Caret sagen .
FireFly
3
@ FireFly Haha, du hast recht. Zu nah am Mittagessen! Vielen Dank.
Asteri

Antworten:

6

APL (45 - 6 = 39)

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

Unterstützt Tund Fals Eingabe, wird aber immer 0oder ausgegeben 1.

Erläuterung:

  • Z←⍞: Lesen Sie eine Zeile und speichern Sie sie in Z
  • L←'TF&|^vx>'⍳Z: Geben Sie den Index 'TF&|^vx>'für jedes Zeichen ein Zund geben Sie an, 9ob das Zeichen nicht vorhanden ist 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: finde das entsprechende Zeichen in '10∧∨⍲⍱≠≤*'. (So ​​werden Zeichen, die nicht in der ersten Liste waren *).
  • ↓⍉Z⍪⍉⍪: Machen Sie dies zu einer Matrix, legen Sie das Original ( Z) darauf und teilen Sie es in eine Liste von Zeichenfolgen auf, wobei das erste Zeichen das Original und das zweite Zeichen die Übersetzung ist, falls vorhanden.
  • (1+9≠L)⌷¨: Holen Sie sich für jede dieser Zeichenfolgen das erste Zeichen, wenn keine Übersetzung vorhanden war (falls vorhanden L=9), und das zweite Zeichen, falls vorhanden.
  • Beispiel: Wenn die Eingabe gewesen wäre T|0, hätten wir 1∨0inzwischen den entsprechenden APL-Ausdruck
  • : eval

Hinweis: ~und =tun Sie bereits das Richtige, damit sie nicht durch irgendetwas ersetzt werden müssen.

Marinus
quelle
Sehr schön! Dies ist ein Übersetzungs-zu-APL-und-Eval-Ansatz, richtig? Ich habe über einen gerundbasierten Ansatz in J nachgedacht, aber ich weiß nicht, wie ich die Operanden geschickt aufteilen soll. : \
FireFly
Warum Matrixmanipulation, wenn Sie einfach Übersetzungsregeln für unveränderte Zeichen wie hinzufügen können ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Punktzahl 33-6 = 27)
TwiNight
8

C - 165 127

Das hat Spaß gemacht! Einfache Nachschlagetabelle, die sich auf einen festen Versatz für die Suche stützt.

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

Aus irgendeinem Grund wird getsdies nicht implizit deklariert. Als ich das Include entfernte, musste ich gets(t+2)zu (gets(t+2),t)(oder ähnlich woanders, was genauso viel kostet) wechseln .


Erläuterung

Da die Wahrheitstabellen für die Operatoren viele überlappende Zeichen enthalten, möchten wir die Nachschlagetabellen so speichern, dass Überlappungen möglich sind. So habe ich sie gespeichert:

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)

Als nächstes wollen wir diesen Offsets Operatorsymbole zuordnen. Dazu speichern wir die Operatorsymbole in derselben Zeichenfolge mit einem festen Versatz zu den LUT-Daten (nämlich 16 Zeichen später, dh direkt nach den LUT-Daten). Der Suchvorgang lautet "Operator suchen in s, subtrahieren 16, addieren left*2+right(linker / rechter Operand). Für die Suche nach der leeren" Identitätsoperation "wird der Operator in diesem Fall aufgrund des Abrufs der Eingabe in das aufgelöst, was t[1]initialisiert wird. -in unseren Fall /. so verwenden wir /als Schlüssel - Lookup - Tabelle , um die Identitätsoperation darzustellen. Wenn wir den einstelligen verarbeiten ~Betrieb „ left“ (für die Lookup - Berechnung bereits erwähnte) ist immer das gleiche / . /geschieht eine kleiner zu sein als0ASCII-weise, dh wenn wir ASCII-Ziffern kompensieren, \wird dies dargestellt -1. Der Schrägstrich im Schlüsselbereich der Nachschlagetabelle (dh vorletztes Zeichen in s) ist so positioniert, dass dies ausgeglichen wird.

Als nächstes Eingabehandhabung. Die Eingabe hat eine dynamische Länge, aber es wäre einfacher, wenn wir unabhängig von der Eingabe bestimmte statische Namen für den linken Operanden, den Operator und den rechten Operanden haben. Wenn wir so tun, als könnten wir die Eingabe von rechts nach links lesen, würde dies grundsätzlich automatisch geschehen - der rechte Operand ist immer das Zeichen ganz rechts, der Operator (falls vorhanden) ist der zweit-rechts-Operand, der linke Operand (falls vorhanden) ) ist von rechts nach rechts. Um die Zeichenfolge so indizieren zu können, verwenden wir sie strchr, um den \0Terminator zu lokalisieren ( - 3um die Indizierung zu vereinfachen). Dies zeigt, warum t[0]und t[1]wird der linke Operand / Operator, wenn die Eingabe 1 oder 2 Zeichen umfasst.

Zusammengenommen wäre die Ausgabe putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), aber einige Umgestaltungen und ständige Faltungen bringen uns stattdessen umso kürzer putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).

FireFly
quelle
Können Sie erklären, wie das funktioniert?
Johannes Kuhn
Die Überlappung der Wahrheitstabelle war eine brillante Idee. Daran hätte ich selbst nie gedacht. :)
Asteri
Auch das Lesen von rechts nach links. Ich wusste, dass die Eingabe und Positionierung mit variabler Länge eine Herausforderung darstellen würde, und das ist eine großartige Möglichkeit, sie zu lösen. Wirklich exzellentes Out-of-the-Box-Denken. Möchten Sie in meinem Entwicklungsteam arbeiten? Haha
Asteri
4
Ich denke, mehr Antworten sollten Erklärungen wie diese haben. Hilft denen von uns, die noch viel lernen! (Und von denen, die noch so ziemlich lernen, bedeutet jeder)
Agweber
@agweber: Das ist gut zu hören, ich war ein bisschen besorgt über meine Erklärung. Und ja, wahrscheinlich befindet sich jeder hier in einer "noch lernenden" Phase. Nun, zumindest weiß ich, dass ich es bin.
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

Ich denke, die foreach-Zeile braucht eine Erklärung:

  • split $argv {} teilt die Eingabezeichenfolge (es ist eigentlich eine Liste, aber Code-Golf) in ihre Zeichen.
  • string map {{~ 0} 1 {~ 1} 0} ...nimmt einen String und ersetzt ~ 0durch 1und ~ 1mit0
  • lassign ... a Nimmt das erste Element der Liste und weist es der Variablen a zu, gibt den Rest zurück.
  • foreach {op b} ... {code}geht über die Liste und nimmt jedes Mal 2 Elemente: opundb
  • set a [$op $a $b]führt den Befehl in der Variablen aus opund speichert das Ergebnis ina
Johannes Kuhn
quelle
3

JavaScript - 107 105 Zeichen

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
quelle
Haha schön. Das ist praktisch. eval()Ich habe nicht einmal daran gedacht, wann ich das erfunden habe. Gib mir einfach ein bisschen, um nach Hause zu kommen und es zu testen.
Asteri
1
nand = &~und nor = |~?
Johannes Kuhn
@ Johannes: Es ist nicht wirklich &~und |~, aber NAND ist nur die Umkehrung von UND. Das Invertieren eines der Bits invertiert also auch das Ergebnis.
ProgramFOX
3

Befunge-98 - 104 101 98-6 72

... weil jede Aufgabe eine Esolang-Lösung benötigt .. Übersetzung meiner C-Implementierung, aber stattdessen die Verarbeitung von Zeichen nacheinander.

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

Unterhaltsame Tatsache: Ändern Sie das @in a,$und Sie erhalten stattdessen eine ausgefallene, nie endende REPL (wenn Sie dies tun, werden Sie jedoch feststellen, dass Identität tatsächlich "letzten Befehl mit lhs = 0 und rhs = Eingabe wiederholen" ist, was zufällig standardmäßig Identität ist ). Die REPL ist nicht mehr.

Ungolfed (frühere Version):

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 $

Bearbeiten: Inspiriert von der Lösung von @jpjacobs, verlasse ich mich jetzt auf die Position der Zeichen in der LUT, um Wahrheitstabellen darzustellen. ZB |ist auf Position 1110 2 = 14, weil dies der Wahrheitstabelle für entspricht |.

FireFly
quelle
Das ist verrückt. Ok, jede Lösung in befunge ist verrückt.
Johannes Kuhn
2

J - 65 67-6 = 61

Nicht mehr die b. Adverb. Ohne die Zuordnung der Funktion zu zählen: 67 Zeichen für die TF-Version, 63 für die Nicht-TF-Version:

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

LgcTF behandelt sowohl 0 und 1 als auch T und F.

Unterstützt die gesamte Syntax von J in Bezug auf Züge und Klammern und wird streng von rechts nach links ausgewertet (keine anderen Vorrangregeln).

Alle Zeichen, die nicht in der Operatorliste + Z enthalten sind, können nicht verwendet werden, andere verhalten sich wie in Standard J (einschließlich Variablen).

Verwendungszweck:

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

Nachtrag 263

Die Idee von Firefly wurde in Postscript übersetzt.

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

Eingerückt:

%!

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

Befunge-93, 86 Zeichen

Das Hashing des zweiten Symbols der Eingabe (das Finden einer Funktion, die sowohl kompakt war als auch Kollisionen vermeidet, war eine Arbeit) für jede Koordinate und das erste und dritte Symbol jedes Modulo 2 als die zwei niedrigstwertigen Bits der x-Koordinate Abrufen eines beliebigen Werts an der angegebenen Position. Eine bessere Hash-Funktion oder eine kompaktere Methode zum Speichern / Adressieren der Wahrheitstabellen sind nur zwei Möglichkeiten, die Länge zu reduzieren.

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







1001
0001
1101
1

0
0110



1110
1000


0111
MDS
quelle