@quantum_jim/QuantumProgrammingTutorial
Python3

No description

Files
  • main.py
  • Engine.py
  • Levels.py
  • License
main.py
#  Created by James Wootton
#  Copyright © 2018 University of Basel. All rights reserved.

#import replit
import math
import subprocess
import copy

from Engine import *
from Levels import *

  
# clear screen and put title
ClearScreen ()
print("")
print("")
print("              ██╗  ██╗███████╗██╗     ██╗      ██████╗       ")              
print("              ██║  ██║██╔════╝██║     ██║     ██╔═══██╗    ")                
print("              ███████║█████╗  ██║     ██║     ██║   ██║     ")               
print("              ██╔══██║██╔══╝  ██║     ██║     ██║   ██║     ")               
print("              ██║  ██║███████╗███████╗███████╗╚██████╔╝      ")              
print("              ╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝           ")          
print("                                                                   ") 
print("    ██████╗ ██╗   ██╗ █████╗ ███╗   ██╗████████╗██╗   ██╗███╗   ███╗")
print("   ██╔═══██╗██║   ██║██╔══██╗████╗  ██║╚══██╔══╝██║   ██║████╗ ████║")
print("   ██║   ██║██║   ██║███████║██╔██╗ ██║   ██║   ██║   ██║██╔████╔██║")
print("   ██║▄▄ ██║██║   ██║██╔══██║██║╚██╗██║   ██║   ██║   ██║██║╚██╔╝██║")
print("   ╚██████╔╝╚██████╔╝██║  ██║██║ ╚████║   ██║   ╚██████╔╝██║ ╚═╝ ██║")
print("    ╚══▀▀═╝  ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═══╝   ╚═╝    ╚═════╝ ╚═╝     ╚═╝")
print("\n")
print("\n")
print("             A GAMIFIED TUTORIAL FOR QUANTUM PROGRAMMING")
print("                               ")
print("       For more resources, and the least glitchy verson, visit:")
print("           github.com/decodoku/Quantum_Programming_Tutorial")
print("             To give feedback, please do this short survey:")
print("            www.surveygizmo.com/s3/4213712/helloquantum-cl")
print("\n")
print("\n")
print("\n")
print("\n")
print("\n")
print("\n")
input("> Press Enter to continue...\n")
print("  Choose which mode you want to play from the following list")
print("")
print("  1 - Story Mode\n      A gamified tutorial for programming quantum computers.\n")
print("  2 - Sandbox\n      A chance to do what you want with two qubits.\n")
print("  3 - Image Superposer\n      Write a quantum program to create superpositions of images.\n")
choosing = True
while choosing:
  mode = input("> Input a number to select a mode...\n")
  if mode in ["1","2","3","4"]:
    choosing = False
  else:
    input("> That's not a valid mode. Press Enter to try again...\n")

if mode=="1":
  state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelStory()
  choosing = True
  while choosing:
    level = input("\n> Select a level (from 1 to "+str(level_num)+")...\n")
    if level.isdigit():
      level = int(level)
      if level in range(1,level_num+1):
        level = int(level)-1
        choosing = False
      else:
        input("> That level does not exist. Press Enter to try again...\n")
    else:
      level = 0
      choosing = False
      input("> That was not a valid level, so we'll start from the beginning...\n")
elif mode=="2":
  state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelSandbox()
  level = 0
elif mode=="3":

  allowed_filenames = ["0000","0001","0010","0011", "0100","0101","0110","0111", "1000","1001","1010","1011", "1100","1101","1110","1111"]

  input("\n> This mode relates to a Jupyter notebook, which you'll find at github.com/decodoku/Quantum_Programming_Tutorial/tree/master/image-superposer...\n")
  input("\n> There you'll find 16 images, all with a bit string as their filename...\n")
  choosing = True
  while choosing :
    string1 = input("\n> Choose one of these images by typing the filename below...\n")
    if string1 in allowed_filenames:
      choosing = False
    else:
      input("> That was not a valid filename. Press Enter to try again...\n")
  choosing = True
  while choosing :
    string2 = input("\n> Choose another image typing the filename below...\n")
    if string2 in allowed_filenames and string2!=string1:
      choosing = False
    else:
      input("> That was not a valid filename. Press Enter to try again...\n")
  input("\n> You'll now write a QISKit program to superpose these two images...\n")
  input("\n> This can then be run on a real machine using the Jupyter notebook...\n")

  state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelSuperposer(string1,string2)
  level = 0

elif mode=="4":

  state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelRandom()
  level = 0

else:
  print("> Oops! You shouldn't have been allowed to pick this mode. Restart the program and try again...")


while (level<level_num) :
    
  # specifications for this level
  state = state_list[level]
  allowed_gates = allowed_gates_list[level]
  required_gates = copy.deepcopy(allowed_gates)
  qubits_used = qubits_used_list[level]
  success_condition = success_condition_list[level]

  bloch = False # always start a level with Bloch off
  active_qubit = -1 # and no active qubit
  program = [] # and an empty program

  # every puzzle is thought of as one involving two qubits, even if only one of those qubits is involved
  # qubits_used should therefore always be a list of two qubits, the first is the one displayed on the top, and the second is the one on the bottom

  if allowed_gates[qubits_used[0]]=={} : # if no gates are allowed for the qubit on top, we know to only show the qubit on the side
      shown_qubit = 1
  elif allowed_gates[qubits_used[1]]=={} : # and vice versa
      shown_qubit = 0
  else :
      shown_qubit = 2
      
  if mode=="4": # for mode 4, this is overwritten and we show both
    shown_qubit = 2
    
    

  success = False
  restart = False
    
  ClearScreen ()
  print("\nLevel "+str(level+1)+"\n")
  for line in intro[level] :
    input("> " + line + "...")

  while success==False and restart==False :

    # ask player to choose an operation
    combined_gates = []
    for qubit in [qubits_used[0],qubits_used[1],"both"]:
      for gate in allowed_gates[qubit].keys() :
        if allowed_gates[qubit][gate]==0 or required_gates[qubit][gate]>0:
          if gate not in combined_gates:
            combined_gates.append(gate)
    
    gate = ""
    while gate=="":
 
      message = "> Choose one of the allowed operations from the list above by typing its name below\n> Or type restart to start this puzzle over..."
      given_input = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates )

      if given_input in combined_gates or given_input=='restart' :
        gate = given_input

    # ask player for a qubit to act on (if there is a choice)...
    qubit = ""
    if gate in ["cz","unbloch","restart"]: # for gates that act symmetrically the choice is irrelevant, and so set by default to both
      qubit = "both"
    elif shown_qubit==0 : # if only the top qubit is shown, that's what the gate acts on
      qubit = qubits_used[0]
    elif shown_qubit==1 : # if only the side qubit is shown, that's what the gate acts on
      qubit = qubits_used[1]
    elif gate not in allowed_gates[qubits_used[0]].keys(): # if the gate isn't an allowed one for the top qubit, it acts on the side
      qubit = qubits_used[1]
    elif gate not in allowed_gates[qubits_used[1]].keys(): # and vice-versa
      qubit = qubits_used[0]
    else :
      while qubit not in [qubits_used[0],qubits_used[1]]:
        message = "> Choose a qubit to act on:\n> Type in "+qubits_used[0]+" or "+qubits_used[1]+"..."
        qubit = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates )


    # if it is a gate, apply it
    if gate in ["x","z","h","q","qdg","cz","cx"] :
      # the apply gate function adresses qubits as 0 and 1, so we convert back to this before applying
      if qubit==qubits_used[0] :
        qubit_pos = "0"
      elif qubit==qubits_used[1] :
        qubit_pos = "1"
      else :
        qubit_pos = "both"
      # now apply
      state = ApplyGate( state, gate, qubit_pos )
      # then we write the qiskit commands
      if gate=="cz" :
        program.append("program.cz( qubit["+qubits_used[0]+"], qubit["+qubits_used[1]+"] )")
      elif gate=="cx" :
        if qubit==qubits_used[0] :
          program.append("program.cx( qubit["+qubits_used[1]+"], qubit["+qubits_used[0]+"] )")
        else :
          program.append("program.cx( qubit["+qubits_used[0]+"], qubit["+qubits_used[1]+"] )")
      else :
        program.append("program."+gate+"( qubit["+qubit+"] )")

    # if it is a visualization command, apply it
    elif gate=="bloch" :
      bloch = True
      if qubit==qubits_used[0] :
        active_qubit = 0
      elif qubit==qubits_used[1] :
        active_qubit = 1
      elif gate=="unbloch" :
        bloch = false
        active_qubit = -1
    elif gate=="restart" :
      restart = True
    else :
      print("Error: Something's not quite right")


    # log the number of these gates if it is important
    if gate!="restart" :
      if allowed_gates[qubit][gate] > 0 :
        required_gates[qubit][gate] -= 1
        if required_gates[qubit][gate] < 0 :
          input("> You have used this gate too many times, so the level will restart...\n")
          restart = True

        
    # see if success conditions are met
    success = True
    # the final state has to be right
    for box, expect in success_condition.items() :
      success =  success and state[box]==expect
    # and the number of ops has to be right
    for qubit in required_gates.keys() :
      for gate in required_gates[qubit].keys() :
        if (required_gates[qubit][gate] > 0) :
          success = False

    
  if restart==False :
    
    message = "> Target achieved.\n> Press Enter to continue..."
    given_input = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates )
        
    # print the outro
    for line in outro[level] :
      input("> " + line + "...")
        
    # interate the level
    level += 1


if mode==1 :
  input("> That's all the levels we have for now. Restart the program, or continue your QISKit journey at QISKit.org\n")
elif mode==2 :
  input("> How are you seeing this?!?!?!?!?!?!?!\n")
elif mode==3 :
  input("> Now you have your QISKit program. You just need to run the notebook for your image.\n")




  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
Python 3.6.1 (default, Dec 2015, 13:05:11) [GCC 4.8.2] on linux