Skip to content

Instantly share code, notes, and snippets.

@quantumjim
Created June 23, 2020 19:20
Show Gist options
  • Save quantumjim/f2fd5c727d608d032351e8ea3b4669fc to your computer and use it in GitHub Desktop.
Save quantumjim/f2fd5c727d608d032351e8ea3b4669fc to your computer and use it in GitHub Desktop.
Quantum Game Demo
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Making a Quantum Game"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Import standard Qiskit stuff"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"# Importing standard Qiskit libraries and configuring account\n",
"from qiskit import QuantumCircuit, execute, Aer, IBMQ\n",
"from qiskit.compiler import transpile, assemble\n",
"from qiskit.tools.jupyter import *\n",
"from qiskit.visualization import *\n",
"# Loading your IBM Q account(s)\n",
"provider = IBMQ.load_account()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And numpy."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's a simple element that could be part of a game: damage for an enemy that takes 3 hits to defeat."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"damage = 0\n",
"\n",
"def attack(damage):\n",
" \n",
" damage = min( damage + 1/3 , 1)\n",
" \n",
" return damage"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We could instead use a quantum circuit to store the damage value, and a quantum gate to implement the attack."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"damage_qc = QuantumCircuit(1,1)\n",
"\n",
"def attack(damage_qc):\n",
" \n",
" damage_qc.rx(np.pi/3,0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to run the circuit to get information out."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"meas = QuantumCircuit(1,1)\n",
"meas.measure(0,0)\n",
"\n",
"qc = damage_qc+meas\n",
" \n",
"counts = execute(qc, Aer.get_backend('qasm_simulator'), shots=1000).result().get_counts()\n",
"\n",
"print(counts)\n",
"qc.draw()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's put this in a function."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_damage(damage_qc):\n",
" \n",
" meas = QuantumCircuit(1,1)\n",
" meas.measure(0,0)\n",
"\n",
" qc = damage_qc+meas\n",
"\n",
" counts = execute(qc, Aer.get_backend('qasm_simulator'), shots=1000).result().get_counts()\n",
" \n",
" damage = 0\n",
" if '1' in counts:\n",
" damage = counts['1']/1000\n",
" \n",
" return damage"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"damage = get_damage(damage_qc)\n",
"print(damage)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This used just a single qubit. Let's do some fancier things, but still with a single qubit. We'll use our knowledge of the [Bloch sphere](https://javafxpert.github.io/grok-bloch/).\n",
"\n",
"We'll use [this](https://github.com/quantumjim/jupyter-widget-game-engine/blob/master/jupyter_widget_game.ipynb) very simple game engine that runs in Jupyter notebooks. You can download with the following."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!git clone https://github.com/quantumjim/jupyter-widget-game-engine/\n",
"!mv jupyter-widget-game-engine/jupyter_widget_engine.py jupyter_widget_engine.py\n",
"!mv jupyter-widget-game-engine/jupyter_widget_game.ipynb jupyter_widget_game.ipynb\n",
"!rm -r jupyter-widget-game-engine"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then import the game engine."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from jupyter_widget_engine import jupyter_widget_engine"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This gives us an LxL screen of pixels and a controller."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"L = 8\n",
"\n",
"def start(engine):\n",
" pass\n",
"\n",
"def next_frame(engine):\n",
" pass \n",
" \n",
"engine = jupyter_widget_engine(start,next_frame,L=L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's make a simple walking simulator, where you just walk around and explore a 2D map."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_terrain(x,y):\n",
" return 'grass'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def start(engine):\n",
" \n",
" engine.get_terrain = get_terrain\n",
" \n",
" engine.next_frame(engine)\n",
"\n",
"def next_frame(engine):\n",
"\n",
" for x in range(L):\n",
" for y in range(L):\n",
" if engine.get_terrain(x,y)=='grass':\n",
" engine.screen[x,y].button_style = 'success'\n",
" \n",
"engine = jupyter_widget_engine(start,next_frame,L=L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since grass is a bit boring, we'll use a single qubit to generate the map using the method explained [here](https://github.com/qiskit-community/MicroQiskit/blob/master/versions/MicroPython/tutorials/Terrain-Generator.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_terrain(x,y):\n",
"\n",
" qc = QuantumCircuit(1,1) # make a circuit\n",
" \n",
" # perform rotations, whose angles depend on x and y\n",
" qc.rx( (np.pi/16)*(x+y) ,0)\n",
" # calculate probability for outcome 1\n",
" qc.measure(0,0)\n",
" counts = execute(qc, Aer.get_backend('qasm_simulator'), shots=1000).result().get_counts()\n",
" if '1' in counts:\n",
" p = counts['1']/1000\n",
" else:\n",
" p = 0\n",
" \n",
" # return terrain depending on this probability\n",
" # the chosen values here are fairly arbitrarily\n",
" if p<0.3:\n",
" terrain = 'sea'\n",
" elif p<0.7:\n",
" terrain = 'sand'\n",
" else:\n",
" terrain = 'grass'\n",
" \n",
" return terrain"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This produces either grass, sand or sea. The game engine needs to be updated accordingly."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def start(engine):\n",
" \n",
" engine.get_terrain = get_terrain\n",
" \n",
" engine.next_frame(engine)\n",
"\n",
"def next_frame(engine):\n",
"\n",
" for x in range(L):\n",
" for y in range(L):\n",
" terrain = engine.get_terrain(x,y)\n",
" if terrain=='grass':\n",
" engine.screen[x,y].button_style = 'success'\n",
" elif terrain=='sea':\n",
" engine.screen[x,y].button_style = 'info'\n",
" else:\n",
" engine.screen[x,y].button_style = 'warning'\n",
" \n",
"engine = jupyter_widget_engine(start,next_frame,L=L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A nice beach, though very straight. By experimenting with different single qubit circuits, we can come up with better terrain.\n",
"\n",
"But let's start on the non-quantum part: walking around!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def start(engine):\n",
" \n",
" engine.get_terrain = get_terrain\n",
" \n",
" engine.p_x = 4\n",
" engine.p_y = 4\n",
" \n",
" engine.next_frame(engine)\n",
"\n",
"def next_frame(engine):\n",
" \n",
" if engine.controller['up'].value:\n",
" engine.p_y -= 1\n",
" if engine.controller['down'].value:\n",
" engine.p_y += 1\n",
" if engine.controller['left'].value:\n",
" engine.p_x -= 1\n",
" if engine.controller['right'].value:\n",
" engine.p_x += 1\n",
" \n",
" s_x = np.floor(engine.p_x/L)\n",
" s_y = np.floor(engine.p_y/L)\n",
"\n",
" for x in range(L):\n",
" for y in range(L):\n",
" terrain = engine.get_terrain(L*s_x+x,L*s_y+y)\n",
" if terrain=='grass':\n",
" engine.screen[x,y].button_style = 'success'\n",
" elif terrain=='sea':\n",
" engine.screen[x,y].button_style = 'info'\n",
" else:\n",
" engine.screen[x,y].button_style = 'warning'\n",
" \n",
" engine.screen[engine.p_x%L,engine.p_y%L].button_style = 'danger'\n",
" \n",
"engine = jupyter_widget_engine(start,next_frame,L=L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Improvements that could be made:\n",
"* Improve terrain generation.\n",
"* Only calculate terrain when screen changes.\n",
"* Make player interact with map (no walking on water).\n",
"* Make an actual game!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment