def ALU74381(a: int, b: int, s1: int, s2: int, s3: int):
    a, b = control.encoder(a, b)
    if not s1 and not s2 and not s3:
        return [0] * max(len(a), len(b))
    if not s1 and not s2 and s3:
        return subtractor.substractor(b, a)
    if not s1 and s2 and not s3:
        return subtractor.substractor(a, b)
    if not s1 and s2 and s3:
        return adder.n_bit_adder(a, b)[0]
    if s1 and not s2 and not s3:
        result = [0] * len(a)
        for index in range(len(a)):
            result[index] = gate.XOR(a[index], b[index])
        return result
    if s1 and not s2 and s3:
        result = [0] * len(a)
        for index in range(len(a)):
            result[index] = gate.OR(a[index], b[index])
        return result
    if s1 and s2 and not s3:
        result = [0] * len(a)
        for index in range(len(a)):
            result[index] = gate.AND(a[index], b[index])
        return result
    if s1 and s2 and s3:
        return [1] * max(len(a), len(b))
def gate_checker():
    for x in [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1),
              (1, 1, 0), (1, 1, 1)]:
        y = gate.AND(*x)
        print("AND : " + str(x) + " -> " + str(y))
    for x in [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1),
              (1, 1, 0), (1, 1, 1)]:
        y = gate.NAND(*x)
        print("NAND : " + str(x) + " -> " + str(y))
    for x in [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1),
              (1, 1, 0), (1, 1, 1)]:
        y = gate.OR(*x)
        print("OR : " + str(x) + " -> " + str(y))
    for x in [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1),
              (1, 1, 0), (1, 1, 1)]:
        y = gate.XOR(*x)
        print("XOR : " + str(x) + " -> " + str(y))
import gate as g

print("############ AND gate ############")
print("1 1 -> %d" % g.AND(1, 1))
print("1 0 -> %d" % g.AND(1, 0))
print("0 1 -> %d" % g.AND(0, 1))
print("0 0 -> %d" % g.AND(0, 0))
print("############ NAND gate ############")
print("1 1 -> %d" % g.NAND(1, 1))
print("1 0 -> %d" % g.NAND(1, 0))
print("0 1 -> %d" % g.NAND(0, 1))
print("0 0 -> %d" % g.NAND(0, 0))
print("############ OR gate ############")
print("1 1 -> %d" % g.OR(1, 1))
print("1 0 -> %d" % g.OR(1, 0))
print("0 1 -> %d" % g.OR(0, 1))
print("0 0 -> %d" % g.OR(0, 0))
print("############ XOR gate ############")
print("1 1 -> %d" % g.XOR(1, 1))
print("1 0 -> %d" % g.XOR(1, 0))
print("0 1 -> %d" % g.XOR(0, 1))
print("0 0 -> %d" % g.XOR(0, 0))
def full_adder(x: int, y: int, carry_in: int):
    sumation = gate.XOR(x, y, carry_in)
    carry_out = gate.OR(gate.AND(x, y), gate.AND(x, carry_in),
                        gate.AND(y, carry_in))
    return sumation, carry_out
def half_adder(x: int, y: int):
    sumation = gate.XOR(x, y)
    carry_out = gate.AND(x, y)
    return sumation, carry_out