# Checking the version of PYTHON; we only support 3 at the moment
import sys
if sys.version_info < (3,0):
    raise Exception('Please use Python version 3 or greater.')
    
# useful additional packages 
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import time
from pprint import pprint

# importing the QISKit
from qiskit import QuantumCircuit, QuantumProgram 
#import Qconfig   
# import basic plot tools
from qiskit.tools.visualization import plot_histogram

QPS_SPECS = {
    'circuits': [{
        'name': 'W_states',
        'quantum_registers': [{
            'name':'q',
            'size':5
        }],
        'classical_registers': [{
            'name':'c',
            'size':5
        }]}],
}

"Choice of the backend"
# The flag_qx2 must be "True" for using the ibmqx2. 
# "True" is also better when using the simulator
#backend = 'ibmqx2' # not advisable if other pending jobs!
#backend = 'ibmqx4' # not advisable if other pending jobs!
backend = 'local_qasm_simulator' #OK

#backend = 'ibmqx_hpc_qasm_simulator' #OK  
flag_qx2 = True
if backend == 'ibmqx4':
        flag_qx2 = False
        
print("Your choice for the backend is: ", backend, "flag_qx2 is: ", flag_qx2)

# Here, two useful routine
# Define a F_gate
def F_gate(circ,q,i,j,n,k) :
    theta = np.arccos(np.sqrt(1/(n-k+1)))
    circ.ry(-theta,q[j])       
    circ.cz(q[i],q[j])
    circ.ry(theta,q[j])
    circ.barrier(q[i])
# Define the cxrv gate which uses reverse CNOT instead of CNOT
def  cxrv(circ,q,i,j) :
    circ.h(q[i])
    circ.h(q[j])
    circ.cx(q[j],q[i])
    circ.h(q[i])
    circ.h(q[j])
    circ.barrier(q[i],q[j])

# 3-qubit W state

Q_program = QuantumProgram(specs=QPS_SPECS)
#Q_program.set_api(Qconfig.APItoken, Qconfig.config['url'])  
W_states = Q_program.get_circuit('W_states') 
q = Q_program.get_quantum_register('q') 
c = Q_program.get_classical_register('c')
        
W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
F_gate(W_states,q,1,0,3,2) # Applying F23

if flag_qx2 : # option ibmqx2 
    W_states.cx(q[1],q[2]) # cNOT 21
    W_states.cx(q[0],q[1]) # cNOT 32
    
else :        # option ibmqx4  
    cxrv(W_states,q,1,2)
    cxrv(W_states,q,0,1)
    
# Coin tossing
W_states.h(q[3]) 
W_states.h(q[4])

for i in range(5) :
    W_states.measure(q[i] , c[i]) 
    
circuits = ['W_states']

"Dotted alphabet"
top_bottom = "███████████████"
blank = "█             █"
chosen = []
chosen = chosen + ["███████████████"]
chosen = chosen + ["███████████  ██"]
chosen = chosen + ["██████████  ███"]
chosen = chosen + ["█████████  ████"]
chosen = chosen + ["████████  █████"]
chosen = chosen + ["█  ████  ██████"]
chosen = chosen + ["██  ██  ███████"]
chosen = chosen + ["███    ████████"]
chosen = chosen + ["████  █████████"]
chosen = chosen + ["███████████████"]

here_left = []
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███        ████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_center = []
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["█████      ████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["█████      ████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_right = []
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███       █████"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███       █████"]
here_right = here_right + ["███   ██   ████"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]

goa=["█             █","█   (     )   █","█    (   )    █","█  / O   O \  █","█     )|(     █","█      @      █","█      =      █","█      Y      █","█             █"]
car=["█             █","█   _______   █","█  /       \  █","█ ° _______ ° █","█  /       \  █","█ (O) ### (O) █","█  =+=====+=  █","█  ||     ||  █","█             █"]

"(RE)INITIATES STATISTICS"
nb_randomnb = 0
nb_left =  0
nb_center =  0
nb_right =  0
nb_switches = 0
nb_stays = 0
nb_won_switching = 0
nb_won_sticking = 0
nb_games = 0
n_won = 0

"HERE START THE GAME"
"Hiding the car and the two goats behind the three doors"
Label = ["left", "central", "right"]
shots = 1
repeat = "Y"
while repeat == "Y":
    nb_of_cars = 4
    while nb_of_cars != 1:
        result = Q_program.execute(circuits, backend=backend, shots=shots, max_credits=5, wait=5, timeout=600)
        c5str = str(result.get_counts('W_states'))
        nb_of_cars = int(c5str[4]) + int(c5str[5]) + int(c5str[6])

        #this is for checking results from the real computer:
        if nb_of_cars == 0:
            print("They managed to hide three goats and no car behind the doors! Restarting the hiding process...")
        if nb_of_cars >= 2: 
            print("They managed to hide", nb_of_cars, "cars behind the doors! Restarting the hiding process...")

    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(here_left[i]," ",here_center[i]," ",here_right[i])
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")        
    door = input("Game master: Your choice? letter l: left door, c: central door, r: right door + enter\n").upper()
    
    picl = here_left
    picc = here_center
    picr = here_right
    if (door == "L"):
        Doorchosen = 1
        nb_left =  nb_left + 1
        picl = chosen
    else:
        if (door == "C"):
            Doorchosen = 2
            nb_center =  nb_center + 1
            picc=chosen
        else:
            Doorchosen = 3
            nb_right = nb_right + 1
            picr = chosen
            
            
    print('Game master:   Your choice was the',Label[Doorchosen-1], "door")

    "AN OPPORTUNITY TO CHANGE YOUR MIND"

    c5str = str(result.get_counts('W_states'))

    randomnb = (int(c5str[2]) + int(c5str[3])) %2  

    if c5str[4] == "1":    #car behind left door 
        Doorwinning = 1        
        if Doorchosen == 1:
            Dooropen = 2 + randomnb
            Doorswitch = 3 - randomnb            
        if Doorchosen == 2:
            Dooropen = 3
            Doorswitch = 1
        if Doorchosen == 3:
            Dooropen = 2
            Doorswitch = 1    

    if c5str[5] == "1":     #car behind central door 
        Doorwinning = 2
        if Doorchosen == 2:
            Dooropen = 1 + 2*randomnb 
            Doorswitch = 3 - 2*randomnb 
        if Doorchosen == 1:
            Dooropen = 3            
            Doorswitch = 2
        if Doorchosen == 3:
            Dooropen = 1            
            Doorswitch = 2

    if c5str[6] == "1":     #car behind right door 
        Doorwinning = 3
        if Doorchosen == 3:
            Dooropen = randomnb + 1
            Doorswitch = 2 - randomnb
        if Doorchosen == 1:
            Dooropen = 2         
            Doorswitch = 3
        if Doorchosen == 2:
            Dooropen = 1            
            Doorswitch = 3
            
    if Dooropen == 1:
        picl = goa
    if Dooropen == 2:   
        picc = goa
    if Dooropen == 3:   
        picr = goa        
    
    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(picl[i]," ",picc[i]," ",picr[i])        
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")
    print('I opened the', Label[Dooropen-1], 'door and you see a goat')
    print('You get now an opportunity to change your choice!')
    print("Do you want to switch for the ",Label[Doorswitch-1], " door?")
    I_switch = input("    Answer by (y/n) + enter\n").upper()

    if (I_switch == "Y"):
        Doorfinal = Doorswitch
    else:
        Doorfinal = Doorchosen

    "FINAL ANNOUNCE"
    if Doorfinal == Doorwinning:
        if Doorfinal == 1:
            picl = car
        if Doorfinal == 2:   
            picc = car
        if Doorfinal == 3:   
            picr = car 
        endmessage = 'won the car! Congratulations!'
    else:
        if Doorfinal == 1:
            picl = goa
        if Doorfinal == 2:   
            picc = goa
        if Doorfinal == 3:   
            picr = goa
        endmessage = 'won a goat! Sorry!'
    
    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(picl[i]," ",picc[i]," ",picr[i])        
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")
    print('Game master: You opened the',Label[Doorfinal-1],'door and', endmessage)
   
    "STATISTICS"
    nb_games = nb_games + 1
    nb_randomnb = nb_randomnb + randomnb
    
    if Doorfinal == Doorswitch:
        nb_switches = nb_switches +1
        if c5str[Doorfinal+3] == "1":
            nb_won_switching = nb_won_switching + 1
    else:
        nb_stays = nb_stays+1
        if c5str[Doorfinal+3] == "1":
            nb_won_sticking = nb_won_sticking + 1
    n_won = nb_won_switching + nb_won_sticking
    print()    
    print("YOUR STATS")    
    print("nb of games: ", nb_games,"     total nb won:", n_won, "     first choice:  left",nb_left," center", nb_center,"right", nb_right)
    print("nb sticking: ",nb_stays," nb won when sticking: ",nb_won_sticking,"nb switching:",nb_switches," nb won when switching:",nb_won_switching)    
    repeat = input("Another game?   Answer by (y/n) + enter\n").upper()
print("Game over")

%run "../version.ipynb"

