Evaluating Logic Gates

Logic gates are functions which perform basic logic operations. In this problem, we will account for the following 6 logic gates: AND, OR, XOR, NAND, NOR, and XNOR. Each of these takes two boolean inputs $$\ a \$$ and $$\ b \$$, and outputs a boolean. Below are the truth tables which show the output of each gate given two inputs.

Given two boolean inputs $$\ a \$$ and $$\ b \$$, return/output a list of the names of all gates which would return a Truthy value. The order doesn't matter, but the names must be in the exact format as given in the 2nd sentence of the above paragraph (not the ones in the diagram). You are also allowed to output them exclusively in lowercase, if desired.

Clarifications

• You may also output a delimiter-separated string
• I will allow leading/trailing spaces

Test Cases

Input

0 0
0 1
1 0
1 1


Output

[NOR, NAND, XNOR]
[OR, NAND, XOR]
[OR, NAND, XOR]
[OR, AND, XNOR]


This is , so the shortest code in bytes wins!

• Can output be a string with a space between elements, such as or and xnor? Apr 27, 2020 at 2:42
• @Cloudy7 Yes, that's allowed. Apr 27, 2020 at 2:50
• Can output have leading/trailing spaces? Apr 27, 2020 at 6:23
• @Bubbler Sure thing. Apr 27, 2020 at 6:28

Python 3, 53 50 49 bytes

Thanks @JonathanAllan for saving 1 byte!

lambda a,b:"NOR N"[a|b:5-a*b]+"AND X"+"NOR"[a^b:]


Try it online!

• I really like how you use the bitwise operations themselves for indexing. Apr 27, 2020 at 3:32
• Unfortunately it loses the use of & but lambda a,b:"NOR N"[a|b:5-a*b]+"AND X"+"NOR"[a^b:] is 49 bytes TIO. Apr 28, 2020 at 18:12
• @JonathanAllan multiplication is pretty much the same as &, so I'll take that. Thanks! Apr 28, 2020 at 23:11

J, 46 bytes

;:@'AND NAND OR NOR XOR XNOR'#~*,*:,+.,+:,~:,=


Try it online!

-5 bytes thanks to Bubbler

We execute a train *,*:,+.,+:,~:,= corresponding to the gates on the arguments, which will produce a single boolean mask of the results.

We then apply that mask as a filter #~ on the list of words, which is in the same order.

Note: Since the returned strings of are of unequal length, J requires them to be boxed.

• You don't need parens there for an obvious reason. But then, you can go for filtering Ns at 42 bytes. Apr 27, 2020 at 4:19
• Well it's shorter without Evoke Gerund... (Basically replace all backticks with , and remove the trailing 3 bytes) Apr 27, 2020 at 4:25
• Thanks Bubbler! I've taken 2 of the 3 suggestions. As for the 42 byte solution, it's clever and different enough that you can feel free to post yourself. It's similar to the python solution, and this is rare case where I think I prefer the cleanness of this single mask solution to the cleverness of the string manipulations (even though it's slightly less golfy). Apr 27, 2020 at 4:29

Ruby, 49 bytes

->a,b{"#{?N[a|b]}OR #{?N[a&b]}AND X#{?N[a^b]}OR"}


Try it online!

Interpolates 'N' into the output string conditionally for each gate.

Alternatively, a direct port of @Surculose Sputum's excellent Python answer (be sure to upvote it!) is also 49 bytes:

->a,b{"NOR "[a|b,4]+"NAND X"[a&b,6]+"NOR"[a^b,3]}


Try it online!

Python 2.7, 117111102 98 bytes

-6 bytes thanks to @math junkie!
-13 bytes thanks to @Surculose Sputum!

Try it online!

Probably could be made shorter with lambda but I don't know how to use it:

a,b=input()
s="or nand xor"
if a==b:s=s.replace("o","no")
if a&b:s=s.replace("na","a")[1:]
print s


EDIT: Yep. This program uses string manipulation to solve the problem, which I thought was simpler, but now I'm not so sure.

• Surculose Sputum's answer is compatible with Python 2 and is much shorter than yours. Apr 27, 2020 at 3:16
• You can save some bytes by moving the body of each if statement to the same line as the if Apr 27, 2020 at 3:33
• @HighlyRadioactive I posted my answer within a minute of Surculose, so when I was writing this Surculose had not answered yet. Apr 27, 2020 at 16:26
• There are a couple of saves here: s can be initialized as a default argument, saving 1 byte. Getting rid of i, and replacing i!=1 and i==2 directly with a==b and a&b saves another 8 bytes. Try it online! Apr 27, 2020 at 16:38
• @SurculoseSputum Odd. Don't know how that one slipped by. Also, that footer thing is neat. Apr 27, 2020 at 16:43

J, 39 37 bytes

[:;(_5<\'NAND NOR XNOR')}.~&.>*,+.,~:


Try it online!

-2 bytes thanks to @Jonah.

A solution that pretty much works like Surculose Sputum's Python 3 answer.

How it works

NB. The three segments in the new version
_5<\'NAND NOR XNOR'
'NAND NOR XNOR'  NB. a length-13 string
_5<\                 NB. enclose non-overlapping length-5 chunks
(which works because the three N's to filter appear at indexes 0, 5, 10)

NB. Previous version
[:;('NAND ';'NOR X';'NOR')}.~&.>*,+.,~:  NB. Input: two bits as left/right args
*,+.,~:  NB. evaluate AND, OR, XOR
('NAND ';'NOR X';'NOR')               NB. corresponding three segments
&.>  NB. pair up both sides unboxed and
}.~     NB.   drop the first char from left if right is 1
[:;  NB. Remove boxing and concatenate into a single vector

• 37 bytes Apr 28, 2020 at 2:25
• @Jonah Nice. I knew that the N's are at nice positions, but somehow I missed that one. Apr 28, 2020 at 2:40

05AB1E, 28 bytes

.•UNœ5Z’dµ•#εI…PàONè.Vi'nõ.;


Try it online!

• Nice approach with the indexing and .V. :) Equal-bytes alternative for the first part using the dictionary: ’n€ƒxš¯š¯’4ôεI…POà Apr 28, 2020 at 7:31

JavaScript (ES6), 55 bytes

a=>b=>'1OR 3AND X5OR'.replace(/\d/g,n=>n>>a+b&1?'N':'')


Try it online!

How?

For each gate type, we use the sum of $$\a\$$ and $$\b\$$ to right-shift a bit mask. We test the least significant bit of the result to find out if we must return the complementary form of the gate.

   a  | 1 | 0 | 1 | 0 |
b  | 1 | 1 | 0 | 0 |
------+---+-------+---+---------
a+b | 2 |   1   | 0 | decimal
------+---+-------+---+---------
NOR | 0 |   0   | 1 |    1
NAND | 0 |   1   | 1 |    3
XNOR | 1 |   0   | 1 |    5


JavaScript (ES6), 55 bytes

Using a template literal is just as long.

a=>b=>['N'[a|b]]+OR ${['N'[a&b]]}AND X${['N'[a^b]]}OR


Try it online!

C (gcc), 65 60 58 bytes

f(a,b){printf("NOR %s X%s"+(a|b),"NAND"+a*b,"NOR"+(a^b));}


Try it online!

• The " X" part can go in the format string to make it more idiomatic C. This direct port is kind of obfuscated for no reason because Python was using string concat, not a separate format string. I don't see any savings, though, unless any of those operators or logical versions of them like a&&b have higher precedence than +. &"NOR"[a|b] might be legal but it's not clearer and is break-even on byte count. Apr 28, 2020 at 12:19
• @PeterCordes Interesting. Your bit about moving the " X" part into the format string gave me the idea of moving the whole first argument into the format sting for -5 bytes - thanks! :-) Apr 28, 2020 at 13:13
• @PeterCordes && doesn't have higher precedence than + but * does for -2 bytes! :D Apr 28, 2020 at 13:27
• Cool, glad there's some C-specific golfing to do here to make this answer more interesting. :) Apr 28, 2020 at 13:44

brainfuck, 234 bytes

>-[-[-<]>>+<]>-[<<++>+>-]<<+<<<-[+>++[++<]>]>-->>[>>>>[-]<<<<[>>+>>+<<<<-]<]<<,<,[>+<-]>[>+>+>>+<<<<-]>>>>--[>.<[-]]>>.>.>+++.>.[<]<<[>>+<<-]>+>[<[-]>[-]]<[->+<]>[>.<[-]]>+.+++.<<<<[>>>+<<<-]>>>>>>>>.<<<<++++++.<-[>>>.<<<[-]]>>>+.+++.


Try it online!

Takes input as two bytes (0 or 1) on stdin, outputs space-separated to stdout without trailing whitespace.

The TIO link has the 11 test case because I couldn't figure out how to type the null character into a web browser, but if you delete the second input character it will do the same thing as the 10 test-case, and if you delete both it will be the same as the 00 test-case.

Here's my annotated version (the two input bytes are b and a, their sum is c):

-[-[-<]>>+<]>- *32* from https://esolangs dot org/wiki/Brainfuck_constants#32
[<<++>+>-]      64 32 *0*
<<+<<<            *0* 0 0 65 32
-[+>++[++<]>]>-- *78* 65 32 from https://esolangs dot org/wiki/Brainfuck_constants#78

>>

[>>>>[-]<<<<[>>+>>+<<<<-]<] 0 *0* 0 0 78 65 78 65 32

<<
,<,          *b* a     0 0 0 0 78 65 78 65 32
[>+<-]>      0 *b plus a=c* 0 0 0 0 78 65 78 65 32
[>+>+>>+<<<<-]>>>> 0 0 c c 0 *c* 78 65 78 65 32

--                      0 0 c c 0 *c minus 2* 78 65 78 65 32
[>.<[-]]>>.>.>+++.>.    0 0 c c 0 0   78 65 78 *68* 32    (N)AND space  print N if c != 2
[<]<<[>>+<<-]>>         0 0 c 0 0 *c* 78 65 78 68 32
<+>[<[-]>[-]]<[->+<]>   0 0 c 0 0 *!c* 78 65 78 68 32
[>.<[-]]>+.+++.         0 0 c 0 0 0  *82* 65 78 68 32     (N)OR         print N if c == 0
< <<<[>>>+<<<-]>>>      0 0 0 0 0 *c* 82 65 78 68 32
>>>>>.<<<<++++++.<      0 0 0 0 0 *c* 88 65 78 68 32      space X
-[>>>.<<<[-]]           0 0 0 0 0 *0* 88 65 78 68 32      (N)           print N if c != 1
>>>+.+++.               0 0 0 0 0 0   88 65 *82* 68 32


tr 01 N\\0<<<"$[$1|$2]OR$[$1&$2]AND X$[$1^$2]OR"  Try it online! This is a full program. Input is passed as arguments, and the output is written to stdout. Retina 0.8.2, 37 bytes 00 N2N 11 ODN \d+ OND D AND X O|$
OR


Try it online!

Input is as a single 2-digit string (one of 00, 01, 10, or 11). Performs a series of replacements to arrive at the required output.

Explanation

AND X is a string common to all 4 outputs, so we encode the string as D.

OR appears in a bunch of places so we encode that as O.

Then, we can replace each pair of digits with a string of Ns, Os and Ds. (The 00 -> N2N and the \d+ -> OND are golfs arising from 10 and 01 yielding the same output and sharing some overlap with the output for 00.

Finally, we just replace the Os and Ds with the expanded string mentioned above and we get the required list!

• Wow, that's some serious golfing, the best I could do was 40 bytes...
– Neil
Apr 27, 2020 at 12:07

Pyth, 37 bytes

AQ%"%sOR X%sOR %sAND"*R\N!M[|GHxGH&GH


Try it online!

Takes a list of two values as input, outputs in the form AND OR XNOR

Explanation

AQ                                     # Q is the input. Set G:=Q[0], H:=Q[1]
%                                    # Format a string (printf-style)
"%sOR X%sOR %sAND"                  # Format string
*R\N!M[|GHxGH&GH  # replacement values as a list:
[           # [                        ]
|GH        #  G or H
xGH     #          G xor H
&GH  #                   G and H
!M            # map each to its negation
*R\N              # map each x to "N"*x


(Ab)uses the fact that in Python and thus Pyth, True == 1 and False == 0 and thus "N"*True == "N" and "N"*False == "".

• Cool solution, but you can get it down to 31 bytes by porting @Surculose Sputum's answer: Try it online! Apr 27, 2020 at 16:15
• 29 bytes: Try it online! Apr 27, 2020 at 16:16

Jelly, 23 bytes

S11,:Sµ“×®ṫ.¡Ḍẹhɗ»x€⁸¦0


A monadic Link accepting a list of two integers (in [0,1]) which yields a list of characters - the gate names separated by spaces.

Try it online! Or see the test-suite.

How?

Observe that there are three outputs, aligning with the sums and that the sum $$\1\$$ and sum $$\2\$$ outputs are the sum $$\0\$$ one missing certain characters. When one-indexed the sum $$\1\$$ needs characters 1 and 11 removed while the sum $$\2\$$ one needs characters 1 and 5 removed. Furthermore $$\\lfloor \frac{11}{2} \rfloor = 5\$$.

S11,:Sµ“×®ṫ.¡Ḍẹhɗ»x€⁸¦0 - Link: list of integers, B  e.g [0,0]            [1,1]            [1,0] (or [0,1])
S                       - sum (B)                        0                2                1
11                     - literal eleven                 11               11               11
,                    - pair                           [11,0]           [11,2]           [11,1]
S                  - sum (B)                        0                2                1
:                   - integer division               [inf,nan]        [5,1]            [11,1]
“×®ṫ.¡Ḍẹhɗ»      - compressed string              "NOR NAND XNOR"  "NOR NAND XNOR"  "NOR NAND XNOR"
€ ¦  - sparse application...
⁸   - ...to indices: chain's left argument
x   0 - ...action: repeat zero times   "NOR NAND XNOR"  "OR AND XNOR"    "OR NAND XOR"


APL (Dyalog Unicode), 30 bytes

∊'NAND ' 'NOR X' 'NOR'↓⍨¨∧,∨,≠


Try it online!

A port of my own J answer.

How it works

∊'NAND ' 'NOR X' 'NOR'↓⍨¨∧,∨,≠
∧,∨,≠  ⍝ AND, OR, XOR
'NAND ' 'NOR X' 'NOR'↓⍨¨       ⍝ Drop an N from the string segments at ones
∊                               ⍝ Flatten


05AB1E, 42 bytes

.•Vs’9ìï´¸•.•B»Î5γ'¸•DŠ‚s.•B»¯4qld•‚«IðмCè


Try it online!

Makes a list: ["nor nand xnor", "or nand xor", "or nand xor", "or and xnor"]; the input is read as a binary number and that corresponds to the position in the list. This could probably be reduced heavily as I see the other 05ab1e answer just uses "nand nor xnor" as its string.

Common Lisp, 154 bytes

Not a short answer, but relies on BOOLE, which is a function that is practically never used:

(lambda(a b)(loop for(n o)in((and,boole-and)(nand,boole-nand)(or,boole-ior)(nor,boole-nor)(xor,boole-xor)(xnor,boole-eqv))if(/=(boole o a b)0)collect n))


(loop
for (name op) in ((and  ,boole-and)
(nand ,boole-nand)
(or   ,boole-ior)
(nor  ,boole-nor)
(xor  ,boole-xor)
(xnor ,boole-eqv))
unless (= (boole op a b) 0)
collect name)


All couples (name op) in the list are made of name, a symbol used for the output, and op, a constant integer value that represents a particular boolean operation. The boole functions knows how to perform the operation based on such value. Note that xnor is the equivalence operation, namely boole-eqv.

The loop builds a list of names such that the associated operation yields a non-zero result.

Indeed, if you do:

(boole boole-nand 1 1)


The result is -2, a.k.a. -10 in binary; this is because those operations assume an infinite two's complement representation (https://comp.lang.lisp.narkive.com/OXYD1hNK/two-s-complement-representation-and-common-lisp)

x86-16 machine code, IBM PC DOS, 57 52 bytes

Binary:

00000000: a182 0025 0101 8bd8 ba2f 0152 0ac4 7401  ...%...../.R..t.
00000010: 42b4 09cd 21ba 2801 84df 7401 42cd 215a  B...!.(...t.B.!Z
00000020: 32df 7401 42cd 21c3 4e41 4e44 2058 244e  2.t.B.!.NAND X$N 00000030: 4f52 2024 OR$


Listing:

A1 0082     MOV  AX, [0082H]        ; load command line chars into AH/AL
25 0101     AND  AX, 0101H          ; ASCII convert
8B D8       MOV  BX, AX             ; save input to BX for later
BA 012F     MOV  DX, OFFSET NOR     ; DX = string 'NOR'
52          PUSH DX                 ; save 'NOR' for later
0A C4       OR   AL, AH             ; OR or NOR?
74 01       JZ   OUT_NOR            ; is OR?
42          INC  DX                 ; increment string pointer to skip 'N'
OUT_NOR:
B4 09       MOV  AH, 9              ; DOS write string function
CD 21       INT  21H                ; write to STDOUT
BA 0128     MOV  DX, OFFSET NAND    ; DX = string 'NAND X'
84 DF       TEST BL, BH             ; AND or NAND?
74 01       JZ   OUT_NAND           ; is AND?
42          INC  DX                 ; increment string pointer to skip 'N'
OUT_NAND:
CD 21       INT  21H                ; write string to STDOUT
5A          POP  DX                 ; Restore DX = 'NOR'
32 DF       XOR  BL, BH             ; XOR or XNOR?
74 01       JZ   OUT_XOR            ; is OR?
42          INC  DX                 ; increment string pointer to skip 'N'
OUT_XOR:
CD 21       INT  21H                ; write string to STDOUT

NAND    DB  'NAND X$' NOR DB 'NOR$'


A standalone PC DOS executable. Input via command line, output string to STDOUT.

I/O:

OIL, 81 bytes

5
1
5
NAND OR XOR
10
NAND NOR XNOR
1
9
20
10
AND OR XNOR
6
14
17
4
10
3
4
5
3
4
3


As usual with golfed OIL code, we use cells as both data and code. All the strings also serve as references to the cell #0 (which will later contain the second input), and we use cell #6 (the one containing a 1) as both a reference to cell #1, as well as the value 1.

Aceto, 67 bytes

pdAANpn
"Ln>"D"L
RON'  Ov
"p   Vu
p^p"pX
N''XRO
irHL "<
riMdpN'


Try it online!

I'm using quick storage for one of the inputs, the stack for the other. It's mostly conditionally escaped movement to avoid printing N, but I also used the reverse-and-jump-to-the-end trick for a few saved bytes.

Io, 65 bytes

Port of Surculose Sputum's Python answer.

method(a,b,"NOR "slice(a|b).."NAND X"slice(a&b).."NOR"slice(a^b))


Try it online!

Charcoal, 160 bytes

×N¬ΣθOR ×N‹Σθ²AND X×N↔⊖ΣθOR


Try it online! Link is to verbose version of code. Takes input as an array or string of two bits. Explanation: Just interpolates the Ns as appropriate based on the count of 1 bits (zero for the first N, less than 2 for the second, and absolute difference from 1 for the third).

a?b=[h(a||b)"OR""NOR",h(a&&b)"AND""NAND",h(a/=b)"XOR""XNOR"];h x a b|x=a|9>0=b
`