# Dependencies and initial configuration

%pylab inline
from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
from qiskit import execute, Aer
from qiskit.tools.visualization import plot_histogram
from ipywidgets import interact
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

from qiskit.circuit.library.standard_gates import HGate, IGate, XGate


def MoveA1(move_A1): global moveA1; moveA1=move_A1;
def MoveB1(move_B1): global moveB1; moveB1=move_B1;
def MoveA2(move_A2): global moveA2; moveA2=move_A2;
    
def who_wins(counts):
    if len(counts)==1 :
        print('The winner is', 'A' if ("0" in counts) else 'B')
        if ("0" in counts):
            img = mpimg.imread('card.jpg')
        else:
            img = mpimg.imread('card_reverse.jpg')
        imgplot = plt.imshow(img)
        plt.axis('off')
        plt.show()
    else:
        count0=counts["0"]
        count1=counts["1"]
        print('The coin is in superposition of |0⟩ and |1⟩')
        print('A wins with probability',  "%.1f%%" % (100.*count0/(count0+count1)))
        print('B wins with probability',  "%.1f%%" % (100.*count1/(count0+count1)))
    return()

def build_circuit():
    q = QuantumRegister(1, name="coin") # create a quantum register with one qubit
    c = ClassicalRegister(1) 
    qc = QuantumCircuit(q, c) # creates the quantum circuit

    h = HGate(label='MAGIC')
    i = IGate(label='Do Nothing')
    x = XGate(label='Flip')
    
    # 1. move of A
    if   moveA1 == 0 : qc.append(i, [0]) #qc.i(q[0])
    elif moveA1 == 1 : qc.append(x, [0]) #qc.x(q[0]) 
    elif moveA1 == 2 : qc.append(h, [0]) #.h(q[0]) 

    # 1. move of B 
    if   moveB1 == 0 : qc.append(i, [0])
    elif moveB1 == 1 : qc.append(x, [0])     

    # 2. move of A
    if   moveA2 == 0 : qc.append(i, [0])
    elif moveA2 == 1 : qc.append(x, [0]) 
    elif moveA2 == 2 : qc.append(h, [0]) 
        
    qc.measure(q, c) # Measure the qubits
    return qc


interact(MoveA1, move_A1={'Not Flip':0,'Flip':1});

interact(MoveB1, move_B1={'Not Flip':0,'Flip':1});

interact(MoveA2, move_A2={'Not Flip':0,'Flip':1});

# The Quantum Circuit
qc = build_circuit()
qc.draw('mpl')

# execute the quantum circiut (coin moves) and identify the winner
backend = Aer.get_backend('qasm_simulator') # define the backend
job = execute(qc, backend, shots=200) # run the job simulation
result = job.result() # grab the result
counts = result.get_counts(qc) # results for the number of runs

#print(counts); # print the results of the runs
who_wins(counts); # celebrate the winner

interact(MoveB1, move_B1={'Not Flip':0,'Flip':1});

# Quantum Computer uses Superposition! (2 is a "Hadamard Gate")
MoveA1(2)
MoveA2(2)

qc = build_circuit()
qc.draw('mpl')

# execute the quantum circiut (coin moves) and identify the winner
backend = Aer.get_backend('qasm_simulator') # define the backend
job = execute(qc, backend, shots=200) # run the job simulation
result = job.result() # grab the result
counts = result.get_counts(qc) # results for the number of runs

print(counts); # print the results of the runs
who_wins(counts); # celebrate the winner
plot_histogram(counts) # Visualise the results

from qiskit.providers.aer.noise import NoiseModel, thermal_relaxation_error
noise_model = NoiseModel()
T1 = 0.001
T2 = 0.002
error = 0.001
thermal_error = thermal_relaxation_error(T1, T2, error)
noise_model.add_quantum_error(thermal_error, "MAGIC", [0])

job = execute(qc, backend, shots=200, noise_model=noise_model) # run the job simulation

result = job.result() # grab the result
counts = result.get_counts(qc) # results for the number of runs

print(counts); # print the results of the runs
who_wins(counts); # celebrate the winner
plot_histogram(counts) # Visualise the results

