Prosty kalkulator bramki logicznej

9

Twoim zadaniem, jeśli zdecydujesz się to zaakceptować, jest zbudowanie prostego narzędzia do oceny prawdy dla następujących operatorów logicznych:

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

Tabele prawdy są w następującej kolejności:

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

Dane wejściowe będą miały postać prostego ciągu 0, 1 i symbolu. Możesz zaakceptować dane wejściowe jako parametr lub odczytać je od użytkownika na standardowym wejściu. Oto kilka przykładowych par wejścia / wyjścia:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

Operator jednoargumentowy (negacja) zawsze pojawi się przed wartością logiczną, podczas gdy operatory binarne zawsze pojawią się między dwiema wartościami logicznymi. Możesz założyć, że wszystkie dane wejściowe będą prawidłowe. Ciągi są zwykłymi ciągami ASCII.

Jeśli wolisz, możesz użyć T i F zamiast 1 i 0. -6 do liczby postaci, jeśli obsługujesz oba.

To jest : wygrywa najkrótszy kod w dowolnym języku!

asteri
źródło
3
Uważam, że ^nazwa symbolu powinna oznaczać karetkę .
FireFly,
3
@FireFly Haha, masz rację. Za blisko lunchu! Dzięki.
asteri

Odpowiedzi:

6

APL (45–6 = 39)

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

Obsługuje Ti Fjako dane wejściowe, ale zawsze będzie generować 0lub 1.

Wyjaśnienie:

  • Z←⍞: przeczytaj wiersz i zapisz go Z
  • L←'TF&|^vx>'⍳Z: pobierz indeks 'TF&|^vx>'dla każdego znaku Z, podając, 9jeśli znak nie jest w 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: znajdź odpowiedni znak w '10∧∨⍲⍱≠≤*'. (Tak więc stają się postacie, których nie było na pierwszej liście *).
  • ↓⍉Z⍪⍉⍪: zrób to w matrycę, umieść na nim oryginał ( Z) i podziel go na listę ciągów, gdzie pierwszy znak to oryginał, a drugi znak to tłumaczenie, jeśli istnieje.
  • (1+9≠L)⌷¨: dla każdego z tych ciągów uzyskaj pierwszy znak, jeśli nie było tłumaczenia (jeśli L=9w tym miejscu) i drugi znak, jeśli był.
  • Przykład: gdyby dane wejściowe były T|0, do tej pory mielibyśmy 1∨0odpowiednie wyrażenie APL
  • : eval

Uwaga: ~i =już postępuj właściwie, aby nie musiały być niczym zastępowane.

marinus
źródło
Bardzo dobrze! To podejście przekłada się na APL i ewaluację, prawda? Zastanawiałem się nad podejściem opartym na gerund w J, ale nie wiem, jak sprytnie rozdzielić operandy. : \
FireFly,
Po co manipulować macierzą, skoro można po prostu dodać reguły tłumaczenia dla znaków bez zmian, takich jak ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Wynik 33-6 = 27)
TwiNight
8

C - 165 127

To było zabawne! Prosta tabela wyszukiwania, oparta na stałym przesunięciu wyszukiwania.

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

Z jakiegoś powodu getsnie zostaje niejawnie zadeklarowane, więc kiedy usunąłem dołączenie, musiałem zmienić gets(t+2)na (gets(t+2),t)(lub podobnie gdzie indziej, kosztując tyle samo).


Wyjaśnienie

Po pierwsze, ponieważ tabele prawdy dla operatorów mają wiele nakładających się znaków, chcemy przechowywać tabele wyszukiwania w taki sposób, aby umożliwić nakładanie się. Oto jak postanowiłem je przechowywać:

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)

Następnie chcemy zmapować symbole operatora na te przesunięcia. Robimy to, przechowując symbole operatora w tym samym ciągu z ustalonym przesunięciem od danych LUT (a mianowicie 16 znaków później, tj. Bezpośrednio po danych LUT). Proces wyszukiwania polega na „znajdowaniu operatora w s, odejmowaniu 16, dodawaniu left*2+right(operand w lewo / w prawo). Aby wyszukać pustą„ operację tożsamości ”, ze względu na sposób pobierania danych wejściowych operator w tym przypadku podejmie operację na cokolwiek, co t[1]zostało zainicjowane - -w naszym przypadku /. Tak więc używamy /jako klucza tabeli odnośników do reprezentowania operacji tożsamości. Kiedy przetwarzamy jednoargumentową ~operację left„(dla wspomnianego wcześniej obliczenia wyszukiwania) jest zawsze taka sama / . /zdarza się, że jest o jeden mniejsza niż0ASCII-mądry, czyli kiedy kompensujemy cyfry ASCII \będą reprezentować -1. Ukośnik w obszarze klucza tabeli odnośników (czyli od drugiego do ostatniego znaku w s) jest ustawiony, aby to zrekompensować.

Dalej, obsługa danych wejściowych. Dane wejściowe mają długość dynamiczną, ale byłoby łatwiej, gdybyśmy mieli określone nazwy statyczne dla lewego operandu, operatora i prawego operandu, niezależnie od danych wejściowych. Gdybyśmy udawali, że potrafimy odczytać dane wejściowe od prawej do lewej, to w zasadzie dzieje się to automagicznie - prawy operand jest zawsze znakiem z prawej strony, operator (jeśli jest obecny) jest drugim z prawej, operand z lewej strony (jeśli jest obecny) ) jest od prawej do trzeciej. Aby móc zaindeksować taki ciąg, używamy go strchrdo zlokalizowania \0terminatora (w - 3celu uproszczenia indeksowania). To pokazuje dlaczego t[0]i t[1]staje się odpowiednio lewym operandem / operatorem, gdy dane wejściowe mają 1 lub 2 znaki.

Podsumowując, wynik byłby putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), ale zamiast tego pewne refaktoryzowanie i ciągłe składanie powoduje, że jesteśmy krótsi putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).

Robaczek świętojański
źródło
Czy możesz wyjaśnić, jak to działa?
Johannes Kuhn
Nakładanie się tabeli prawdy było genialnym pomysłem. Nigdy bym o tym nie pomyślał. :)
asteri
Również czytanie od prawej do lewej. Wiedziałem, że wejście o zmiennej długości i pozycjonowanie będą stanowić wyzwanie, i jest to świetny sposób na jego rozwiązanie. Naprawdę doskonałe myślenie po wyjęciu z pudełka. Chcesz przyjść pracować w moim zespole programistycznym? Haha
asteri
4
Myślę, że więcej odpowiedzi powinno zawierać takie wyjaśnienia. Pomaga tym z nas, którzy wciąż dużo się uczą! (A ci, którzy wciąż uczą się prawie wszyscy dochodowe)
agweber
@agweber: Dobrze to słyszeć, trochę martwiłem się o moje wyjaśnienia. I tak, prawdopodobnie wszyscy tutaj są w fazie „uczenia się”. Cóż, przynajmniej wiem, że tak.
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

Nie golfowany:

# 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

Myślę, że linia foreach wymaga wyjaśnienia:

  • split $argv {} dzieli ciąg wejściowy (tak naprawdę jest to lista, ale kod golfowy) na jego znaki.
  • string map {{~ 0} 1 {~ 1} 0} ...pobiera ciąg i zastępuje ~ 0się 1i ~ 1ze0
  • lassign ... a pobiera pierwszy element listy i przypisuje go do zmiennej a, zwraca resztę.
  • foreach {op b} ... {code}przegląda listę i za każdym razem przyjmuje 2 elementy: opib
  • set a [$op $a $b]wykonuje polecenie w zmiennej op, przechowuje wynik wa
Johannes Kuhn
źródło
3

JavaScript - 107 105 znaków

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
źródło
Haha, miło. To się przydaje. Nawet nie pomyślałem, eval()kiedy to wymyśliłem. Daj mi trochę, aby wrócić do domu i przetestować.
asteri
1
nand = &~i nor = |~?
Johannes Kuhn
@Johannes: To naprawdę nie jest &~a |~, ale NAND jest po prostu odwrotnością AND. Zatem odwrócenie jednego z bitów również odwraca wynik.
ProgramFOX,
3

Befunge-98 - 104 101 98-6 72

... ponieważ każde zadanie wymaga rozwiązania esolang .. tłumaczenia mojej implementacji C, ale zamiast tego przetwarzania znaków pojedynczo.

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

Ciekawostka: Zmień @się a,$i masz ochotę niekończące rEPL zamiast (choć, jeśli zrobisz to można zauważyć, że tożsamość jest rzeczywiście „powtórz ostatnie polecenie z LHS i RHS = 0 = wejście”, który okazuje się domyślnie z tożsamością ). REPL już nie ma.

Ungolfed (wcześniejsza wersja):

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 $

Edycja: zainspirowany rozwiązaniem @jpjacobs, teraz polegam na pozycji znaków w LUT do reprezentowania tabel prawdy. Np. |Znajduje się na pozycji 1110 2 = 14, ponieważ odpowiada to tabeli prawdy dla |.

Robaczek świętojański
źródło
To jest szalone. Ok, każde rozwiązanie w befunge jest szalone.
Johannes Kuhn
2

J - 65 67–6 = 61

Nigdy więcej b. Przysłówek. Bez policzenia przypisania funkcji: 67 znaków dla wersji TF, 63 dla wersji innej niż TF:

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

LgcTF obsługuje zarówno 0 i 1, a także T i F.

Obsługuje całą składnię J pod względem ciągów, nawiasów i ocenia ściśle od prawej do lewej (brak innych reguł pierwszeństwa).

Nie można używać wszystkich znaków, których nie ma na liście operatorów + Z, inne będą działać jak w standardowym J (łącznie ze zmiennymi).

Stosowanie:

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
źródło
1

Postscriptum 263

Pomysł Firefly przetłumaczony na 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

Zębaty:

%!

{
    (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
źródło
1

Befunge-93, 86 znaków

Działa poprzez haszowanie drugiego symbolu wejścia (znalezienie funkcji, która była zarówno zwarta, jak i uniknięcie kolizji było trochę pracy) dla każdej współrzędnej, i przyjmowanie pierwszego i trzeciego symbolu każdego modulo 2 jako dwóch najmniej znaczących bitów współrzędnej x, a następnie pobieranie dowolnej wartości z podanej pozycji. Lepsza funkcja skrótu lub bardziej kompaktowa metoda przechowywania / adresowania tabel prawdy to tylko dwa możliwe sposoby skrócenia długości.

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







1001
0001
1101
1

0
0110



1110
1000


0111
MDS
źródło