Un semplice calcolatore di gate logici


9

La tua missione, se scegli di accettarlo, è quella di costruire un semplice valutatore della verità per i seguenti operatori logici:

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

Le tabelle di verità sono nel seguente ordine:

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

L'input verrà come una semplice stringa di 0, 1 e il simbolo. Puoi accettare l'input come parametro o leggerlo dall'utente su stdin. Ecco alcune coppie di input / output di esempio:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

L'operatore unario (negazione) apparirà sempre prima del valore booleano, mentre gli operatori binari appariranno sempre tra i due valori booleani. Puoi presumere che tutti gli input saranno validi. Le stringhe sono stringhe ASCII regolari.

Se preferisci, puoi usare T e F piuttosto che 1 e 0. -6 per il conteggio dei personaggi se supporti entrambi.

Questo è : vince il codice più corto in qualsiasi lingua!


3
Credo che ^il nome del simbolo dovrebbe significare la cura .
FireFly

3
@FireFly Haha, hai ragione. Troppo vicino a pranzo! Grazie.
asteri,

Risposte:


6

APL (45-6 = 39)

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

Supporta Te Fcome input ma verrà sempre emesso 0o 1.

Spiegazione:

  • Z←⍞: leggi una riga e memorizzala in Z
  • L←'TF&|^vx>'⍳Z: ottieni l'indice 'TF&|^vx>'per ogni personaggio Z, dando 9se il personaggio non è dentro 'TF&|^vx>'.
  • '10∧∨⍲⍱≠≤*'[... ]: trova il carattere corrispondente in '10∧∨⍲⍱≠≤*'. (Così diventano i personaggi che non erano nella prima lista *).
  • ↓⍉Z⍪⍉⍪: trasformalo in una matrice, mettici Zsopra l'originale ( ) e dividilo in un elenco di stringhe, dove il primo carattere è l'originale e il secondo carattere è la sua traduzione, se presente.
  • (1+9≠L)⌷¨: per ciascuna di queste stringhe, ottieni il primo carattere se non c'era traduzione (se L=9in quel posto) e il secondo carattere se c'era.
  • Esempio: se l'input fosse stato T|0, avremmo 1∨0ormai qual è l'espressione APL corrispondente
  • : eval

Nota: ~e =già fanno la cosa giusta in modo che non debbano essere sostituiti da nulla.


Molto bella! Questo è un approccio di traduzione in APL ed eval, giusto? Stavo meditando su un approccio basato sui gerundi in J, ma non so come suddividere abilmente gli operandi. : \
FireFly

Perché manipolare le matrici quando puoi semplicemente aggiungere regole di traduzione per i caratteri senza cambiamento come ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Punteggio 33-6 = 27)
TwiNight,

8

C - 165 127

È stato divertente! Tabella di ricerca semplice basata su un offset fisso per la ricerca.

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

Per qualche ragione getsnon viene implicitamente dichiarato, così quando ho rimosso il includere ho dovuto cambiare gets(t+2)a (gets(t+2),t)(o in modo simile altrove, che costano tanto).


Spiegazione

Prima di tutto, poiché le tabelle di verità per gli operatori hanno molti caratteri sovrapposti, desideriamo memorizzare le tabelle di ricerca in modo da consentire la sovrapposizione. Ecco come ho scelto di memorizzarli:

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)

Successivamente, vogliamo mappare i simboli dell'operatore su questi offset. Lo facciamo memorizzando i simboli dell'operatore nella stessa stringa con un offset fisso rispetto ai dati LUT (ovvero, 16 caratteri più tardi, cioè direttamente dopo i dati LUT). Il processo di ricerca è "trova operatore s, sottrai 16, aggiungi left*2+right(operando sinistro / destro). Per la ricerca dell'operazione" identità "vuota, a causa del modo in cui viene recuperato l'input, l'operatore in questo caso risolverà tutto ciò che t[1]è inizializzato a- nel nostro caso /, quindi, utilizziamo /come chiave della tabella di ricerca per rappresentare l'operazione di identità. Quando elaboriamo l' ~operazione unaria " left" (per il calcolo di ricerca menzionato in precedenza) è sempre la stessa / . /sembra essere uno in meno di0ASCII-saggio, che significa quando compensiamo le cifre ASCII \rappresenterà -1. La barra nell'area chiave della tabella di ricerca (penultimo carattere s, ovvero) è posizionata per compensare ciò.

Successivamente, gestione dell'input. L'input ha una lunghezza dinamica, ma sarebbe più semplice se avessimo nomi statici specifici per l'operando di sinistra, l'operatore e l'operando di destra, indipendentemente dall'input. Se fingiamo di poter leggere l'input da destra a sinistra, ciò avverrebbe sostanzialmente in modo automatico: l'operando di destra è sempre il carattere più a destra, l'operatore (se presente) è l'estremo da secondo a destra, l'operando di sinistra (se presente ) è dalla terza alla destra. Per poter indicizzare la stringa in questo modo, usiamo strchrper individuare il \0terminatore ( - 3per semplificare l'indicizzazione). Questo mostra perché t[0]e t[1]diventa rispettivamente l'operando / operatore di sinistra quando l'input è di 1 o 2 caratteri.

Mettendolo insieme, l'output sarebbe putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]), ma un po 'di refactoring e una piegatura costante ci rendono invece più brevi putchar(strchr(s,u[1])[u[0]*2+u[2]-159]).


Potresti spiegare come funziona?
Johannes Kuhn,

La sovrapposizione della tabella della verità era un'idea geniale. Non ci avrei mai pensato. :)
asteri,

Anche la lettura da destra a sinistra. Sapevo che l'input e il posizionamento a lunghezza variabile rappresentavano una sfida, ed è un ottimo modo per risolverlo. Pensiero pronto davvero eccellente. Vuoi venire a lavorare sul mio team di sviluppo? Haha
asteri,

4
Penso che più risposte dovrebbero avere spiegazioni come questa. Aiuta quelli di noi che stanno ancora imparando molto! (E per coloro che stanno ancora imparando praticamente significano tutti)
agweber

@agweber: è bello sentirlo, ero un po 'preoccupato per la mia spiegazione. E sì, probabilmente tutti qui sono in una fase di "apprendimento" .. beh, almeno so di esserlo.
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

Penso che la linea foreach abbia bisogno di qualche spiegazione:

  • split $argv {} divide la stringa di input (in realtà è un elenco, ma code-golf) nei suoi caratteri.
  • string map {{~ 0} 1 {~ 1} 0} ...prende una stringa e sostituisce ~ 0con 1e ~ 1con0
  • lassign ... a prende il primo elemento dell'elenco e lo assegna alla variabile a, restituisce il resto.
  • foreach {op b} ... {code}cammina sulla lista e prende 2 elementi ogni volta: opeb
  • set a [$op $a $b]esegue il comando nella variabile op, memorizza il risultato ina

3

JavaScript - 107 105 caratteri

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

Ahah carino. È utile. Non ho nemmeno pensato a eval()quando l'ho inventato. Dammi solo un po 'per tornare a casa e provarlo.
asteri,

1
nand = &~e né = |~?
Johannes Kuhn,

@Johannes: non è proprio &~e |~, ma NAND è solo l'inverso di AND. Quindi, l'inversione di uno dei bit inverte anche il risultato.
Programma FOX

3

Befunge-98 - 104 101 98-6 72

... perché ogni attività ha bisogno di una soluzione esolang .. traduzione della mia implementazione in C, ma invece di elaborare i caratteri uno alla volta.

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

Curiosità: cambia in @to a,$e ottieni invece una fantasia infinita di REPL (anche se, se lo fai, noterai che l'identità è in realtà "ripeti l'ultimo comando con lhs = 0 e rhs = input", che succede di default all'identità ). Il REPL non esiste più.

Ungolfed (versione precedente):

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 $

Modifica: ispirato alla soluzione di @jpjacobs, ora mi affido alla posizione dei personaggi nella LUT per rappresentare le tabelle di verità. Ad esempio, |è nella posizione 1110 2 = 14 perché questo corrisponde alla tabella della verità per |.


Questo è pazzo. Ok, ogni soluzione in befunge è pazza.
Johannes Kuhn,

2

J - 65 67-6 = 61

Non più il b. Avverbio. Senza contare l'assegnazione della funzione: 67 caratteri per la versione TF, 63 per la versione non TF:

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

LgcTF gestisce sia 0 e 1 sia T e F.

Supporta tutta la sintassi di J in termini di treni, parentesi e valuta rigorosamente da destra a sinistra (nessuna altra regola di precedenza).

Tutti i caratteri non presenti nell'elenco degli operatori + Z non possono essere utilizzati, altri agiranno come nello standard J (comprese le variabili).

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

1

Postscript 263

L'idea di Firefly tradotta in 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

rientrato:

%!

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

Funziona eseguendo l'hashing del secondo simbolo dell'input (trovare una funzione che era allo stesso tempo compatta ed evitare le collisioni era un po 'di lavoro) per ogni coordinata, e prendendo il primo e il terzo simbolo ogni modulo 2 come i due bit meno significativi della coordinata x, quindi recuperare qualunque valore si trovi nella posizione indicata. Una migliore funzione hash o un metodo più compatto di memorizzazione / indirizzamento delle tabelle di verità sono solo due possibili modi in cui si potrebbe ridurre la lunghezza.

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







1001
0001
1101
1

0
0110



1110
1000


0111
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.