├── poster.png ├── README.md ├── simulation.py └── IBM.py /poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antontutoveanu/quantum-tic-tac-toe/HEAD/poster.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A 'quantum' version of tic tac toe that can run on IBM's quantum computer (or simulated on your local machine). 2 | 3 | Requires 9 qubits. 4 | 5 | Done as part of [Chris Ferrie](https://profiles.uts.edu.au/Christopher.Ferrie)'s [Introduction to Quantum Computing](https://handbook.uts.edu.au/subjects/41170.html) course at [UTS](https://www.uts.edu.au/). 6 | 7 | ![](./poster.png) 8 | 9 | To run simulated version: 10 | ```bash 11 | python3 simulated.py 12 | ``` 13 | To run on IBM's quantum computer: 14 | ```bash 15 | python3 IBM.py 16 | ``` 17 | 18 | Example output of a game: 19 | ``` 20 | 21 | ########################### 22 | ### Quantum Tic-Tac-Toe ### 23 | ########################### 24 | 25 | 26 | Start Menu: 27 | 28 | 1. Start Game 29 | 2. How to Play 30 | 3. Quit 31 | 32 | What would you like to do? 1 33 | 34 | | | 35 | -+-+- 36 | | | 37 | -+-+- 38 | | | 39 | 40 | It's your turn X. 41 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 42 | 1 43 | 44 | Which location? (1-9) 1 45 | ┌───┐ 46 | q_0: ┤ X ├ 47 | └───┘ 48 | q_1: ───── 49 | 50 | q_2: ───── 51 | 52 | q_3: ───── 53 | 54 | q_4: ───── 55 | 56 | q_5: ───── 57 | 58 | q_6: ───── 59 | 60 | q_7: ───── 61 | 62 | q_8: ───── 63 | 64 | c: 9/═════ 65 | 66 | 67 | X| | 68 | -+-+- 69 | | | 70 | -+-+- 71 | | | 72 | 73 | It's your turn O. 74 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 75 | 2 76 | 77 | Which location? (1-9) 78 | 2 79 | Which location? (1-9) 80 | 3 81 | ┌───┐ 82 | q_0: ┤ X ├───── 83 | ├───┤ 84 | q_1: ┤ H ├──■── 85 | ├───┤┌─┴─┐ 86 | q_2: ┤ X ├┤ X ├ 87 | └───┘└───┘ 88 | q_3: ────────── 89 | 90 | q_4: ────────── 91 | 92 | q_5: ────────── 93 | 94 | q_6: ────────── 95 | 96 | q_7: ────────── 97 | 98 | q_8: ────────── 99 | 100 | c: 9/══════════ 101 | 102 | 103 | X|O|O 104 | -+-+- 105 | | | 106 | -+-+- 107 | | | 108 | 109 | It's your turn X. 110 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 111 | 2 112 | 113 | Which location? (1-9) 114 | 4 115 | Which location? (1-9) 116 | 5 117 | ┌───┐ 118 | q_0: ┤ X ├───── 119 | ├───┤ 120 | q_1: ┤ H ├──■── 121 | ├───┤┌─┴─┐ 122 | q_2: ┤ X ├┤ X ├ 123 | ├───┤└───┘ 124 | q_3: ┤ H ├──■── 125 | ├───┤┌─┴─┐ 126 | q_4: ┤ X ├┤ X ├ 127 | └───┘└───┘ 128 | q_5: ────────── 129 | 130 | q_6: ────────── 131 | 132 | q_7: ────────── 133 | 134 | q_8: ────────── 135 | 136 | c: 9/══════════ 137 | 138 | 139 | X|O|O 140 | -+-+- 141 | X|X| 142 | -+-+- 143 | | | 144 | 145 | It's your turn O. 146 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 147 | 2 148 | 149 | Which location? (1-9) 150 | 6 151 | Which location? (1-9) 152 | 7 153 | ┌───┐ 154 | q_0: ┤ X ├───── 155 | ├───┤ 156 | q_1: ┤ H ├──■── 157 | ├───┤┌─┴─┐ 158 | q_2: ┤ X ├┤ X ├ 159 | ├───┤└───┘ 160 | q_3: ┤ H ├──■── 161 | ├───┤┌─┴─┐ 162 | q_4: ┤ X ├┤ X ├ 163 | ├───┤└───┘ 164 | q_5: ┤ H ├──■── 165 | ├───┤┌─┴─┐ 166 | q_6: ┤ X ├┤ X ├ 167 | └───┘└───┘ 168 | q_7: ────────── 169 | 170 | q_8: ────────── 171 | 172 | c: 9/══════════ 173 | 174 | 175 | X|O|O 176 | -+-+- 177 | X|X|O 178 | -+-+- 179 | O| | 180 | 181 | It's your turn X. 182 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 183 | 2 184 | 185 | Which location? (1-9) 186 | 8 187 | Which location? (1-9) 188 | 9 189 | ┌───┐ 190 | q_0: ┤ X ├───── 191 | ├───┤ 192 | q_1: ┤ H ├──■── 193 | ├───┤┌─┴─┐ 194 | q_2: ┤ X ├┤ X ├ 195 | ├───┤└───┘ 196 | q_3: ┤ H ├──■── 197 | ├───┤┌─┴─┐ 198 | q_4: ┤ X ├┤ X ├ 199 | ├───┤└───┘ 200 | q_5: ┤ H ├──■── 201 | ├───┤┌─┴─┐ 202 | q_6: ┤ X ├┤ X ├ 203 | ├───┤└───┘ 204 | q_7: ┤ H ├──■── 205 | ├───┤┌─┴─┐ 206 | q_8: ┤ X ├┤ X ├ 207 | └───┘└───┘ 208 | c: 9/══════════ 209 | 210 | 211 | X|O|O 212 | -+-+- 213 | X|X|O 214 | -+-+- 215 | O|X|X 216 | 217 | Trigger collapse. 218 | 219 | ┌───┐ ┌─┐ 220 | q_0: ┤ X ├─────┤M├──────────────────────── 221 | ├───┤ └╥┘┌─┐ 222 | q_1: ┤ H ├──■───╫─┤M├───────────────────── 223 | ├───┤┌─┴─┐ ║ └╥┘┌─┐ 224 | q_2: ┤ X ├┤ X ├─╫──╫─┤M├────────────────── 225 | ├───┤└───┘ ║ ║ └╥┘┌─┐ 226 | q_3: ┤ H ├──■───╫──╫──╫─┤M├─────────────── 227 | ├───┤┌─┴─┐ ║ ║ ║ └╥┘┌─┐ 228 | q_4: ┤ X ├┤ X ├─╫──╫──╫──╫─┤M├──────────── 229 | ├───┤└───┘ ║ ║ ║ ║ └╥┘┌─┐ 230 | q_5: ┤ H ├──■───╫──╫──╫──╫──╫─┤M├───────── 231 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ └╥┘┌─┐ 232 | q_6: ┤ X ├┤ X ├─╫──╫──╫──╫──╫──╫─┤M├────── 233 | ├───┤└───┘ ║ ║ ║ ║ ║ ║ └╥┘┌─┐ 234 | q_7: ┤ H ├──■───╫──╫──╫──╫──╫──╫──╫─┤M├─── 235 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ ║ ║ └╥┘┌─┐ 236 | q_8: ┤ X ├┤ X ├─╫──╫──╫──╫──╫──╫──╫──╫─┤M├ 237 | └───┘└───┘ ║ ║ ║ ║ ║ ║ ║ ║ └╥┘ 238 | c: 9/═══════════╩══╩══╩══╩══╩══╩══╩══╩══╩═ 239 | 0 1 2 3 4 5 6 7 8 240 | 241 | X|O| 242 | -+-+- 243 | X| |O 244 | -+-+- 245 | | |X 246 | 247 | It's your turn O. 248 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 249 | 1 250 | 251 | Which location? (1-9) 3 252 | ┌───┐ ┌─┐ ┌───┐ 253 | q_0: ┤ X ├─────┤M├─|0>─┤ X ├──────────────────────────────────────── 254 | ├───┤ └╥┘ ┌─┐ └───┘┌───┐ 255 | q_1: ┤ H ├──■───╫──┤M├──|0>─┤ X ├─────────────────────────────────── 256 | ├───┤┌─┴─┐ ║ └╥┘ ┌─┐ └───┘┌───┐ 257 | q_2: ┤ X ├┤ X ├─╫───╫───┤M├──|0>─┤ X ├────────────────────────────── 258 | ├───┤└───┘ ║ ║ └╥┘ ┌─┐ └───┘┌───┐ 259 | q_3: ┤ H ├──■───╫───╫────╫───┤M├──|0>─┤ X ├───────────────────────── 260 | ├───┤┌─┴─┐ ║ ║ ║ └╥┘ ┌─┐ └───┘ 261 | q_4: ┤ X ├┤ X ├─╫───╫────╫────╫───┤M├──|0>────────────────────────── 262 | ├───┤└───┘ ║ ║ ║ ║ └╥┘ ┌─┐ ┌───┐ 263 | q_5: ┤ H ├──■───╫───╫────╫────╫────╫───┤M├──|0>─┤ X ├─────────────── 264 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ └╥┘ ┌─┐ └───┘ 265 | q_6: ┤ X ├┤ X ├─╫───╫────╫────╫────╫────╫───┤M├──|0>──────────────── 266 | ├───┤└───┘ ║ ║ ║ ║ ║ ║ └╥┘ ┌─┐ 267 | q_7: ┤ H ├──■───╫───╫────╫────╫────╫────╫────╫───┤M├──|0>─────────── 268 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ ║ ║ └╥┘ ┌─┐ ┌───┐ 269 | q_8: ┤ X ├┤ X ├─╫───╫────╫────╫────╫────╫────╫────╫───┤M├──|0>─┤ X ├ 270 | └───┘└───┘ ║ ║ ║ ║ ║ ║ ║ ║ └╥┘ └───┘ 271 | c: 9/═══════════╩═══╩════╩════╩════╩════╩════╩════╩════╩════════════ 272 | 0 1 2 3 4 5 6 7 8 273 | 274 | X|O|O 275 | -+-+- 276 | X| |O 277 | -+-+- 278 | | |X 279 | 280 | It's your turn X. 281 | Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit? 282 | 1 283 | 284 | Which location? (1-9) 7 285 | ┌───┐ ┌─┐ ┌───┐ 286 | q_0: ┤ X ├─────┤M├─|0>─┤ X ├──────────────────────────────────────── 287 | ├───┤ └╥┘ ┌─┐ └───┘┌───┐ 288 | q_1: ┤ H ├──■───╫──┤M├──|0>─┤ X ├─────────────────────────────────── 289 | ├───┤┌─┴─┐ ║ └╥┘ ┌─┐ └───┘┌───┐ 290 | q_2: ┤ X ├┤ X ├─╫───╫───┤M├──|0>─┤ X ├────────────────────────────── 291 | ├───┤└───┘ ║ ║ └╥┘ ┌─┐ └───┘┌───┐ 292 | q_3: ┤ H ├──■───╫───╫────╫───┤M├──|0>─┤ X ├───────────────────────── 293 | ├───┤┌─┴─┐ ║ ║ ║ └╥┘ ┌─┐ └───┘ 294 | q_4: ┤ X ├┤ X ├─╫───╫────╫────╫───┤M├──|0>────────────────────────── 295 | ├───┤└───┘ ║ ║ ║ ║ └╥┘ ┌─┐ ┌───┐ 296 | q_5: ┤ H ├──■───╫───╫────╫────╫────╫───┤M├──|0>─┤ X ├─────────────── 297 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ └╥┘ ┌─┐ └───┘┌───┐ 298 | q_6: ┤ X ├┤ X ├─╫───╫────╫────╫────╫────╫───┤M├──|0>─┤ X ├────────── 299 | ├───┤└───┘ ║ ║ ║ ║ ║ ║ └╥┘ ┌─┐ └───┘ 300 | q_7: ┤ H ├──■───╫───╫────╫────╫────╫────╫────╫───┤M├──|0>─────────── 301 | ├───┤┌─┴─┐ ║ ║ ║ ║ ║ ║ ║ └╥┘ ┌─┐ ┌───┐ 302 | q_8: ┤ X ├┤ X ├─╫───╫────╫────╫────╫────╫────╫────╫───┤M├──|0>─┤ X ├ 303 | └───┘└───┘ ║ ║ ║ ║ ║ ║ ║ ║ └╥┘ └───┘ 304 | c: 9/═══════════╩═══╩════╩════╩════╩════╩════╩════╩════╩════════════ 305 | 0 1 2 3 4 5 6 7 8 306 | 307 | X|O|O 308 | -+-+- 309 | X| |O 310 | -+-+- 311 | X| |X 312 | 313 | Game Over. 314 | 315 | **** X won **** 316 | 317 | Play Again?(y/n) 318 | ``` 319 | 320 | ## Disclaimer 321 | 322 | The output from the quantum computer isn't always correct. 323 | 324 | Use the simulator for accuracy and the quantum computer for novelty. -------------------------------------------------------------------------------- /simulation.py: -------------------------------------------------------------------------------- 1 | from termcolor import colored, cprint 2 | import json 3 | from qiskit import * 4 | from qiskit.tools.monitor import job_monitor 5 | 6 | def resetBoard(): 7 | return {'1': [' ', 0] , '2': [' ', 0], '3': [' ', 0], 8 | '4': [' ', 0], '5': [' ', 0], '6': [' ', 0], 9 | '7': [' ', 0], '8': [' ', 0], '9': [' ', 0]} 10 | 11 | def printBoard(board): 12 | print() 13 | colour = 0 14 | for i in range (1,10): 15 | if board[str(i)][1] == 0: 16 | cprint(board[str(i)][0], end='') 17 | else: 18 | if (colour == 0 or colour == 1): 19 | cprint(board[str(i)][0], 'red', end='') 20 | colour = colour + 1 21 | elif (colour == 2 or colour == 3): 22 | cprint(board[str(i)][0], 'green', end='') 23 | colour = colour + 1 24 | elif (colour == 4 or colour == 5): 25 | cprint(board[str(i)][0], 'blue', end='') 26 | colour = colour + 1 27 | elif (colour == 6 or colour == 7): 28 | cprint(board[str(i)][0], 'yellow', end='') 29 | colour = colour + 1 30 | 31 | if i % 3 == 0: 32 | print() 33 | if i != 9: 34 | print('-+-+-') 35 | else: 36 | cprint('|', end='') 37 | 38 | def make_classic_move(theBoard, turn, count, circuit): 39 | 40 | valid_move = 0 41 | valid_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 42 | 43 | while (not valid_move): 44 | print() 45 | print("Which location? (1-9) ", end='') 46 | location = input() 47 | 48 | if location in valid_moves: 49 | 50 | if theBoard[location][0] == ' ': 51 | valid_move = 1 52 | # set the location's marker 53 | theBoard[location][0] = turn 54 | # increment counter (total markers on board) *when this = 9, collapse the board, also called measurement 55 | count += 1 56 | # set marker's state (classical or quantum) 57 | theBoard[location][1] = 0 # classical (not flashing on screen) 58 | 59 | # set qubit[location] to ON, 100% = 1 60 | # one pauli X gate 61 | circuit.x(int(location)-1) 62 | 63 | print(circuit.draw()) 64 | else: 65 | print() 66 | print("That place is already filled.") 67 | else: 68 | print("Please select a square from 1-9") 69 | 70 | return theBoard, turn, count, circuit 71 | 72 | def make_quantum_move(theBoard, count, circuit, turn): 73 | 74 | valid_move = False 75 | valid_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 76 | 77 | while (not valid_move): 78 | 79 | print() 80 | print("Which location? (1-9) ") 81 | location1 = input() 82 | print("Which location? (1-9) ") 83 | location2 = input() 84 | 85 | if theBoard[location1][0] == ' ' and theBoard[location2][0] == ' ' and location1 != location2: 86 | # set the location's marker 87 | theBoard[location1][0] = turn 88 | theBoard[location2][0] = turn 89 | # increment counter (total markers on board) *when this = 9, collapse the board, also called measurement 90 | count += 2 91 | # set marker's state (classical or quantum) 92 | theBoard[location1][1] = 1 # quantum (flashing on screen) 93 | theBoard[location2][1] = 1 # quantum (flashing on screen) 94 | 95 | 96 | # set qubit[location1], qubit[location2] to superposition/entangled 97 | 98 | # hadamard gates 99 | circuit.h(int(location1)-1) 100 | 101 | # x gate 102 | circuit.x(int(location2)-1) 103 | 104 | # cnot gate 105 | circuit.cx(int(location1)-1,int(location2)-1) 106 | 107 | print(circuit.draw()) 108 | valid_move = True 109 | else: 110 | print() 111 | print("You have selected an invalid position/s") 112 | 113 | 114 | return theBoard, count, circuit, turn 115 | 116 | def measure(circuit, theBoard, count): 117 | # trigger collapse 118 | printBoard(theBoard) 119 | print() 120 | print("Trigger collapse.") 121 | print() 122 | 123 | # Use Aer's qasm_simulator 124 | simulator = qiskit.Aer.get_backend('qasm_simulator') 125 | 126 | circuit.measure(0,0) 127 | circuit.measure(1,1) 128 | circuit.measure(2,2) 129 | circuit.measure(3,3) 130 | circuit.measure(4,4) 131 | circuit.measure(5,5) 132 | circuit.measure(6,6) 133 | circuit.measure(7,7) 134 | circuit.measure(8,8) 135 | 136 | print(circuit.draw()) 137 | 138 | # Execute the circuit on quantum simulator 139 | job = qiskit.execute(circuit, simulator, shots=1) 140 | 141 | # Grab results from the job 142 | result = job.result() 143 | 144 | out = json.dumps(result.get_counts()) #Converts the result.get_counts() into a string 145 | string = out[2:11] #Removes unnecessary data from string, leaving us with board 146 | 147 | # update board 148 | for i in range(9): 149 | if string[i] == '1': 150 | # cement value in the board 151 | theBoard[str(9-i)][1] = 0 152 | else: 153 | # make square empty 154 | theBoard[str(9-i)][1] = 0 155 | theBoard[str(9-i)][0] = ' ' 156 | 157 | # update count (total number of markers on the board) 158 | count = 0 159 | for i in range(9): 160 | theBoard[str(i+1)][1] = 0 161 | if theBoard[str(i+1)][0] != ' ': 162 | count += 1 163 | 164 | # reset qubits 165 | circuit.reset(0) 166 | circuit.reset(1) 167 | circuit.reset(2) 168 | circuit.reset(3) 169 | circuit.reset(4) 170 | circuit.reset(5) 171 | circuit.reset(6) 172 | circuit.reset(7) 173 | circuit.reset(8) 174 | 175 | for i in range(9): 176 | if string[8-i] == '1': 177 | # add pauli x gate 178 | circuit.x(i) 179 | 180 | return circuit, string, theBoard, count 181 | 182 | def check_win(theBoard, turn): 183 | if theBoard['7'][0] == theBoard['8'][0] == theBoard['9'][0] != ' ': # across the top 184 | if theBoard['7'][1] == theBoard['8'][1] == theBoard['9'][1] == 0: # only cemented markers 185 | printBoard(theBoard) 186 | print("\nGame Over.\n") 187 | print(" **** ", end='') 188 | print(theBoard['8'][0], end='') 189 | print(" won ****") 190 | print() 191 | return True 192 | 193 | elif theBoard['4'][0] == theBoard['5'][0] == theBoard['6'][0] != ' ': # across the middle 194 | if theBoard['4'][1] == theBoard['5'][1] == theBoard['6'][1] == 0: # only cemented markers 195 | printBoard(theBoard) 196 | print("\nGame Over.\n") 197 | print(" **** ", end='') 198 | print(theBoard['5'][0], end='') 199 | print(" won ****") 200 | print() 201 | return True 202 | 203 | elif theBoard['1'][0] == theBoard['2'][0] == theBoard['3'][0] != ' ': # across the bottom 204 | if theBoard['1'][1] == theBoard['2'][1] == theBoard['3'][1] == 0: # only cemented markers 205 | printBoard(theBoard) 206 | print("\nGame Over.\n") 207 | print(" **** ", end='') 208 | print(theBoard['2'][0], end='') 209 | print(" won ****") 210 | print() 211 | return True 212 | 213 | elif theBoard['1'][0] == theBoard['4'][0] == theBoard['7'][0] != ' ': # down the left side 214 | if theBoard['1'][1] == theBoard['4'][1] == theBoard['7'][1] == 0: # only cemented markers 215 | printBoard(theBoard) 216 | print("\nGame Over.\n") 217 | print(" **** ", end='') 218 | print(theBoard['4'][0], end='') 219 | print(" won ****") 220 | print() 221 | return True 222 | 223 | elif theBoard['2'][0] == theBoard['5'][0] == theBoard['8'][0] != ' ': # down the middle 224 | if theBoard['2'][1] == theBoard['5'][1] == theBoard['8'][1] == 0: # only cemented markers 225 | printBoard(theBoard) 226 | print("\nGame Over.\n") 227 | print(" **** ", end='') 228 | print(theBoard['5'][0], end='') 229 | print(" won ****") 230 | print() 231 | return True 232 | 233 | elif theBoard['3'][0] == theBoard['6'][0] == theBoard['9'][0] != ' ': # down the right side 234 | if theBoard['3'][1] == theBoard['6'][1] == theBoard['9'][1] == 0: # only cemented markers 235 | printBoard(theBoard) 236 | print("\nGame Over.\n") 237 | print(" **** ", end='') 238 | print(theBoard['6'][0], end='') 239 | print(" won ****") 240 | print() 241 | return True 242 | 243 | elif theBoard['7'][0] == theBoard['5'][0] == theBoard['3'][0] != ' ': # diagonal 244 | if theBoard['7'][1] == theBoard['5'][1] == theBoard['3'][1] == 0: # only cemented markers 245 | printBoard(theBoard) 246 | print("\nGame Over.\n") 247 | print(" **** ", end='') 248 | print(theBoard['5'][0], end='') 249 | print(" won ****") 250 | print() 251 | return True 252 | 253 | elif theBoard['1'][0] == theBoard['5'][0] == theBoard['9'][0] != ' ': # diagonal 254 | if theBoard['1'][1] == theBoard['5'][1] == theBoard['9'][1] == 0: # only cemented markers 255 | printBoard(theBoard) 256 | print("\nGame Over.\n") 257 | print(" **** ", end='') 258 | print(theBoard['5'][0], end='') 259 | print(" won ****") 260 | print() 261 | return True 262 | 263 | #Implementation of Two Player Tic-Tac-Toe game in Python. 264 | # start game function 265 | # Now we'll write the main function which has all the gameplay functionality. 266 | 267 | 268 | def game(): 269 | 270 | turn = 'X' 271 | count = 0 272 | win = False 273 | x_collapse = 1 274 | y_collapse = 1 275 | 276 | # initialise quantum circuit with 9 qubits (all on OFF = 0) 277 | circuit = qiskit.QuantumCircuit(9, 9) 278 | 279 | while (not win): 280 | 281 | # ============================= ROUND START ============================ 282 | global theBoard 283 | printBoard(theBoard) 284 | 285 | print() 286 | print("It's your turn " + turn + ". Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit?") 287 | 288 | move = input() 289 | 290 | # ============================= CLASSIC MOVE =========================== 291 | 292 | if int(move) == 1: 293 | theBoard, turn, count, circuit = make_classic_move(theBoard, turn, count, circuit) 294 | madeMove = True 295 | 296 | # ============================= QUANTUM MOVE =========================== 297 | 298 | elif int(move) == 2 and count > 8: 299 | # cant do a quantum move if there's only 1 empty square left 300 | print() 301 | print("There aren't enough empty spaces for that!") 302 | 303 | elif int(move) == 2 and count < 8: 304 | theBoard, count, circuit, turn = make_quantum_move(theBoard, count, circuit, turn) 305 | madeMove = True 306 | 307 | # ============================= COLLAPSE/MEASURE ======================= 308 | 309 | elif int(move) == 3: 310 | 311 | if (turn == 'X' and x_collapse== 1 ): 312 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 313 | x_collapse = 0 314 | elif (turn == 'O' and y_collapse == 1): 315 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 316 | y_collapse = 0 317 | else: 318 | print("You have already used your collapse this game!") 319 | 320 | # ============================= QUIT =================================== 321 | 322 | elif int(move) == 4: 323 | break 324 | 325 | # ============================= CHECK FOR WIN ========================== 326 | 327 | # Now we will check if player X or O has won,for every move 328 | if count >= 5: 329 | win = check_win(theBoard, turn) 330 | if (win): 331 | break 332 | 333 | 334 | 335 | # If neither X nor O wins and the board is full, we'll declare the result as 'tie'. 336 | if count == 9: 337 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 338 | win = check_win(theBoard, turn) 339 | if count == 9: 340 | print("\nGame Over.\n") 341 | print("It's a Tie !") 342 | print() 343 | win = True 344 | 345 | 346 | 347 | # Now we have to change the player after every move. 348 | if (madeMove): 349 | madeMove = False 350 | if turn =='X': 351 | turn = 'O' 352 | else: 353 | turn = 'X' 354 | 355 | 356 | # Now we will ask if player wants to restart the game or not. 357 | restart = input("Play Again?(y/n) ") 358 | if restart == "y" or restart == "Y": 359 | 360 | theBoard = resetBoard() 361 | game() 362 | 363 | def start_menu(): 364 | start_menu = """ 365 | Start Menu: 366 | 367 | 1. Start Game 368 | 2. How to Play 369 | 3. Quit 370 | """ 371 | 372 | print(""" 373 | ########################### 374 | ### Quantum Tic-Tac-Toe ### 375 | ########################### 376 | """) 377 | print(start_menu) 378 | choice = 0 379 | while (choice != '1'): 380 | print("What would you like to do? ", end='') 381 | choice = input() 382 | 383 | if (choice == '2'): 384 | How_To = """ 385 | In Quantum Tic-Tac-Toe, each square starts empty and your goal is to create a line of three of your naughts/crosses. 386 | Playing a classical move will result in setting a square permanently as your piece. 387 | Playing a quantum move will create a superposition between two squares of your choosing. You may only complete a quantum move in two empty squares. 388 | The board will collapse when the board is full. At collapse, each superposition is viewed and only 1 piece of the superposition will remain. 389 | *Powerup* Each player can decide to collapse the board prematurely, they may do this once per round each. 390 | """ 391 | print(How_To) 392 | 393 | if (choice == '3'): 394 | print("Goodbye") 395 | break 396 | 397 | return choice 398 | 399 | #Reset the board at start 400 | theBoard = resetBoard() 401 | 402 | #Set no moves made yet 403 | if (start_menu() == '1'): 404 | madeMove = False 405 | game() -------------------------------------------------------------------------------- /IBM.py: -------------------------------------------------------------------------------- 1 | from termcolor import colored, cprint 2 | import json 3 | from qiskit import * 4 | from qiskit.tools.monitor import job_monitor 5 | 6 | TOKEN = "404713877cdee77e48a874066538a3cecab6e044ddbc06b7f25d4b2178a3b3c25151add0d8135bd8fed43867888555109239891a38555adeaef7f0342994b4fe" 7 | IBMQ.save_account(TOKEN) 8 | 9 | def resetBoard(): 10 | return {'1': [' ', 0] , '2': [' ', 0], '3': [' ', 0], 11 | '4': [' ', 0], '5': [' ', 0], '6': [' ', 0], 12 | '7': [' ', 0], '8': [' ', 0], '9': [' ', 0]} 13 | 14 | def printBoard(board): 15 | print() 16 | colour = 0 17 | for i in range (1,10): 18 | if board[str(i)][1] == 0: 19 | cprint(board[str(i)][0], end='') 20 | else: 21 | if (colour == 0 or colour == 1): 22 | cprint(board[str(i)][0], 'red', end='') 23 | colour = colour + 1 24 | elif (colour == 2 or colour == 3): 25 | cprint(board[str(i)][0], 'green', end='') 26 | colour = colour + 1 27 | elif (colour == 4 or colour == 5): 28 | cprint(board[str(i)][0], 'blue', end='') 29 | colour = colour + 1 30 | elif (colour == 6 or colour == 7): 31 | cprint(board[str(i)][0], 'yellow', end='') 32 | colour = colour + 1 33 | 34 | if i % 3 == 0: 35 | print() 36 | if i != 9: 37 | print('-+-+-') 38 | else: 39 | cprint('|', end='') 40 | 41 | def make_classic_move(theBoard, turn, count, circuit): 42 | 43 | valid_move = 0 44 | valid_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 45 | 46 | while (not valid_move): 47 | print() 48 | print("Which location? (1-9) ", end='') 49 | location = input() 50 | 51 | if location in valid_moves: 52 | 53 | if theBoard[location][0] == ' ': 54 | valid_move = 1 55 | # set the location's marker 56 | theBoard[location][0] = turn 57 | # increment counter (total markers on board) *when this = 9, collapse the board, also called measurement 58 | count += 1 59 | # set marker's state (classical or quantum) 60 | theBoard[location][1] = 0 # classical (not flashing on screen) 61 | 62 | # set qubit[location] to ON, 100% = 1 63 | # one pauli X gate 64 | circuit.x(int(location)-1) 65 | 66 | print(circuit.draw()) 67 | else: 68 | print() 69 | print("That place is already filled.") 70 | else: 71 | print("Please select a square from 1-9") 72 | 73 | return theBoard, turn, count, circuit 74 | 75 | def make_quantum_move(theBoard, count, circuit, turn): 76 | 77 | valid_move = False 78 | valid_moves = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 79 | 80 | while (not valid_move): 81 | 82 | print() 83 | print("Which location? (1-9) ") 84 | location1 = input() 85 | print("Which location? (1-9) ") 86 | location2 = input() 87 | 88 | if theBoard[location1][0] == ' ' and theBoard[location2][0] == ' ' and location1 != location2: 89 | # set the location's marker 90 | theBoard[location1][0] = turn 91 | theBoard[location2][0] = turn 92 | # increment counter (total markers on board) *when this = 9, collapse the board, also called measurement 93 | count += 2 94 | # set marker's state (classical or quantum) 95 | theBoard[location1][1] = 1 # quantum (flashing on screen) 96 | theBoard[location2][1] = 1 # quantum (flashing on screen) 97 | 98 | 99 | # set qubit[location1], qubit[location2] to superposition/entangled 100 | 101 | # hadamard gates 102 | circuit.h(int(location1)-1) 103 | 104 | # x gate 105 | circuit.x(int(location2)-1) 106 | 107 | # cnot gate 108 | circuit.cx(int(location1)-1,int(location2)-1) 109 | 110 | print(circuit.draw()) 111 | valid_move = True 112 | else: 113 | print() 114 | print("You have selected an invalid position/s") 115 | 116 | 117 | return theBoard, count, circuit, turn 118 | 119 | def measure(circuit, theBoard, count): 120 | # trigger collapse 121 | printBoard(theBoard) 122 | print() 123 | print("Trigger collapse.") 124 | print() 125 | 126 | # Use Aer's qasm_simulator 127 | # simulator = qiskit.Aer.get_backend('qasm_simulator') 128 | 129 | 130 | IBMQ.load_account() 131 | provider = IBMQ.get_provider(hub = 'ibm-q') 132 | qcomp = provider.get_backend('ibmq_16_melbourne') 133 | 134 | circuit.measure(0,0) 135 | circuit.measure(1,1) 136 | circuit.measure(2,2) 137 | circuit.measure(3,3) 138 | circuit.measure(4,4) 139 | circuit.measure(5,5) 140 | circuit.measure(6,6) 141 | circuit.measure(7,7) 142 | circuit.measure(8,8) 143 | 144 | print(circuit.draw()) 145 | 146 | # Execute the circuit on real quantum computer 147 | job = qiskit.execute(circuit, backend=qcomp, shots=1) 148 | 149 | job_monitor(job) 150 | 151 | # Grab results from the job 152 | result = job.result() 153 | 154 | out = json.dumps(result.get_counts()) #Converts the result.get_counts() into a string 155 | string = out[2:11] #Removes unnecessary data from string, leaving us with board 156 | 157 | # update board 158 | for i in range(9): 159 | if string[i] == '1': 160 | # cement value in the board 161 | theBoard[str(9-i)][1] = 0 162 | else: 163 | # make square empty 164 | theBoard[str(9-i)][1] = 0 165 | theBoard[str(9-i)][0] = ' ' 166 | 167 | # update count (total number of markers on the board) 168 | count = 0 169 | for i in range(9): 170 | theBoard[str(i+1)][1] = 0 171 | if theBoard[str(i+1)][0] != ' ': 172 | count += 1 173 | 174 | # reset qubits 175 | circuit.reset(0) 176 | circuit.reset(1) 177 | circuit.reset(2) 178 | circuit.reset(3) 179 | circuit.reset(4) 180 | circuit.reset(5) 181 | circuit.reset(6) 182 | circuit.reset(7) 183 | circuit.reset(8) 184 | 185 | for i in range(9): 186 | if string[8-i] == '1': 187 | # add pauli x gate 188 | circuit.x(i) 189 | 190 | return circuit, string, theBoard, count 191 | 192 | def check_win(theBoard, turn): 193 | if theBoard['7'][0] == theBoard['8'][0] == theBoard['9'][0] != ' ': # across the top 194 | if theBoard['7'][1] == theBoard['8'][1] == theBoard['9'][1] == 0: # only cemented markers 195 | printBoard(theBoard) 196 | print("\nGame Over.\n") 197 | print(" **** ", end='') 198 | print(theBoard['8'][0], end='') 199 | print(" won ****") 200 | print() 201 | return True 202 | 203 | elif theBoard['4'][0] == theBoard['5'][0] == theBoard['6'][0] != ' ': # across the middle 204 | if theBoard['4'][1] == theBoard['5'][1] == theBoard['6'][1] == 0: # only cemented markers 205 | printBoard(theBoard) 206 | print("\nGame Over.\n") 207 | print(" **** ", end='') 208 | print(theBoard['5'][0], end='') 209 | print(" won ****") 210 | print() 211 | return True 212 | 213 | elif theBoard['1'][0] == theBoard['2'][0] == theBoard['3'][0] != ' ': # across the bottom 214 | if theBoard['1'][1] == theBoard['2'][1] == theBoard['3'][1] == 0: # only cemented markers 215 | printBoard(theBoard) 216 | print("\nGame Over.\n") 217 | print(" **** ", end='') 218 | print(theBoard['2'][0], end='') 219 | print(" won ****") 220 | print() 221 | return True 222 | 223 | elif theBoard['1'][0] == theBoard['4'][0] == theBoard['7'][0] != ' ': # down the left side 224 | if theBoard['1'][1] == theBoard['4'][1] == theBoard['7'][1] == 0: # only cemented markers 225 | printBoard(theBoard) 226 | print("\nGame Over.\n") 227 | print(" **** ", end='') 228 | print(theBoard['4'][0], end='') 229 | print(" won ****") 230 | print() 231 | return True 232 | 233 | elif theBoard['2'][0] == theBoard['5'][0] == theBoard['8'][0] != ' ': # down the middle 234 | if theBoard['2'][1] == theBoard['5'][1] == theBoard['8'][1] == 0: # only cemented markers 235 | printBoard(theBoard) 236 | print("\nGame Over.\n") 237 | print(" **** ", end='') 238 | print(theBoard['5'][0], end='') 239 | print(" won ****") 240 | print() 241 | return True 242 | 243 | elif theBoard['3'][0] == theBoard['6'][0] == theBoard['9'][0] != ' ': # down the right side 244 | if theBoard['3'][1] == theBoard['6'][1] == theBoard['9'][1] == 0: # only cemented markers 245 | printBoard(theBoard) 246 | print("\nGame Over.\n") 247 | print(" **** ", end='') 248 | print(theBoard['6'][0], end='') 249 | print(" won ****") 250 | print() 251 | return True 252 | 253 | elif theBoard['7'][0] == theBoard['5'][0] == theBoard['3'][0] != ' ': # diagonal 254 | if theBoard['7'][1] == theBoard['5'][1] == theBoard['3'][1] == 0: # only cemented markers 255 | printBoard(theBoard) 256 | print("\nGame Over.\n") 257 | print(" **** ", end='') 258 | print(theBoard['5'][0], end='') 259 | print(" won ****") 260 | print() 261 | return True 262 | 263 | elif theBoard['1'][0] == theBoard['5'][0] == theBoard['9'][0] != ' ': # diagonal 264 | if theBoard['1'][1] == theBoard['5'][1] == theBoard['9'][1] == 0: # only cemented markers 265 | printBoard(theBoard) 266 | print("\nGame Over.\n") 267 | print(" **** ", end='') 268 | print(theBoard['5'][0], end='') 269 | print(" won ****") 270 | print() 271 | return True 272 | 273 | #Implementation of Two Player Tic-Tac-Toe game in Python. 274 | # start game function 275 | # Now we'll write the main function which has all the gameplay functionality. 276 | 277 | 278 | def game(): 279 | 280 | turn = 'X' 281 | count = 0 282 | win = False 283 | x_collapse = 1 284 | y_collapse = 1 285 | 286 | # initialise quantum circuit with 9 qubits (all on OFF = 0) 287 | circuit = qiskit.QuantumCircuit(9, 9) 288 | 289 | while (not win): 290 | 291 | # ============================= ROUND START ============================ 292 | global theBoard 293 | printBoard(theBoard) 294 | 295 | print() 296 | print("It's your turn " + turn + ". Do you want to make a (1) classical move, (2) quantum move, (3) collapse?, or (4) quit?") 297 | 298 | move = input() 299 | 300 | # ============================= CLASSIC MOVE =========================== 301 | 302 | if int(move) == 1: 303 | theBoard, turn, count, circuit = make_classic_move(theBoard, turn, count, circuit) 304 | madeMove = True 305 | 306 | # ============================= QUANTUM MOVE =========================== 307 | 308 | elif int(move) == 2 and count > 8: 309 | # cant do a quantum move if there's only 1 empty square left 310 | print() 311 | print("There aren't enough empty spaces for that!") 312 | 313 | elif int(move) == 2 and count < 8: 314 | theBoard, count, circuit, turn = make_quantum_move(theBoard, count, circuit, turn) 315 | madeMove = True 316 | 317 | # ============================= COLLAPSE/MEASURE ======================= 318 | 319 | elif int(move) == 3: 320 | 321 | if (turn == 'X' and x_collapse== 1 ): 322 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 323 | x_collapse = 0 324 | elif (turn == 'O' and y_collapse == 1): 325 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 326 | y_collapse = 0 327 | else: 328 | print("You have already used your collapse this game!") 329 | 330 | # ============================= QUIT =================================== 331 | 332 | elif int(move) == 4: 333 | break 334 | 335 | # ============================= CHECK FOR WIN ========================== 336 | 337 | # Now we will check if player X or O has won,for every move 338 | if count >= 5: 339 | win = check_win(theBoard, turn) 340 | if (win): 341 | break 342 | 343 | 344 | 345 | # If neither X nor O wins and the board is full, we'll declare the result as 'tie'. 346 | if count == 9: 347 | circuit, string, theBoard, count = measure(circuit, theBoard, count) 348 | win = check_win(theBoard, turn) 349 | if count == 9: 350 | print("\nGame Over.\n") 351 | print("It's a Tie !") 352 | print() 353 | win = True 354 | 355 | 356 | 357 | # Now we have to change the player after every move. 358 | if (madeMove): 359 | madeMove = False 360 | if turn =='X': 361 | turn = 'O' 362 | else: 363 | turn = 'X' 364 | 365 | 366 | # Now we will ask if player wants to restart the game or not. 367 | restart = input("Play Again?(y/n) ") 368 | if restart == "y" or restart == "Y": 369 | 370 | theBoard = resetBoard() 371 | game() 372 | 373 | def start_menu(): 374 | start_menu = """ 375 | Start Menu: 376 | 377 | 1. Start Game 378 | 2. How to Play 379 | 3. Quit 380 | """ 381 | 382 | print(""" 383 | ########################### 384 | ### Quantum Tic-Tac-Toe ### 385 | ########################### 386 | """) 387 | print(start_menu) 388 | choice = 0 389 | while (choice != '1'): 390 | print("What would you like to do? ", end='') 391 | choice = input() 392 | 393 | if (choice == '2'): 394 | How_To = """ 395 | In Quantum Tic-Tac-Toe, each square starts empty and your goal is to create a line of three of your naughts/crosses. 396 | Playing a classical move will result in setting a square permanently as your piece. 397 | Playing a quantum move will create a superposition between two squares of your choosing. You may only complete a quantum move in two empty squares. 398 | The board will collapse when the board is full. At collapse, each superposition is viewed and only 1 piece of the superposition will remain. 399 | *Powerup* Each player can decide to collapse the board prematurely, they may do this once per round each. 400 | """ 401 | print(How_To) 402 | 403 | if (choice == '3'): 404 | print("Goodbye") 405 | break 406 | 407 | return choice 408 | 409 | #Reset the board at start 410 | theBoard = resetBoard() 411 | 412 | #Set no moves made yet 413 | if (start_menu() == '1'): 414 | madeMove = False 415 | game() --------------------------------------------------------------------------------