quantum-chess

git clone git://git.codymlewis.com/quantum-chess.git
Log | Files | Refs | LICENSE

commit 4fae94676c64856b86dfbe92e3f01fb9ca5a0e11
parent 7a5f174ff168fd766bf14594b004a2633542589d
Author: Cody Lewis <luxdotsugi@gmail.com>
Date:   Sun,  1 Apr 2018 16:31:00 +1000

Added majority of the program to git

Diffstat:
MREADME.md | 12+++++++++++-
Abishop.py | 20++++++++++++++++++++
Aboard.py | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afunctions.py | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aking.py | 18++++++++++++++++++
Aknight.py | 33+++++++++++++++++++++++++++++++++
Apawn.py | 42++++++++++++++++++++++++++++++++++++++++++
Apiece.py | 37+++++++++++++++++++++++++++++++++++++
Aqueen.py | 20++++++++++++++++++++
Arook.py | 20++++++++++++++++++++
10 files changed, 460 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -1,2 +1,12 @@ # QuantumChess -A python Quantum Chess program using ibm's Qiskit +Quantum Chess by Cody Lewis +Last Modified: 26-FEB-2018 + +This is a python implementation of quantum chess using IBM's Qiskit for the +case of piece superposition. That is, to calculate the probability of the +entire pieces death. Sadly, the game runs for too long to have entanglement +of the qubits. + +Requirements: +- Python 3.6+ +- Qiskit diff --git a/bishop.py b/bishop.py @@ -0,0 +1,20 @@ +# bishop.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +class Bishop(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'B ' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + direction = moveArr[0] + if(direction == 'f' or direction == 'q' or direction == 'h' or direction == 'g'): + for i in range(1,len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False diff --git a/board.py b/board.py @@ -0,0 +1,203 @@ +# board.py - QuantumChess +# Author: Cody Lewis +# Date: 26-FEB-2018 +# Mod.: 03-MAR-2018 +# Description: +# The board for the Quantum Chess +# the board is indexed with a birds eye view with the white pieces on the bottom +import pawn +import rook +import bishop +import knight +import queen +import king +class Board: + def __init__(self): + self.playBoard = dict() + self.rows = 8 + self.columns = 8 + for i in range(97,98+self.rows): # letters for columns, with 'a' at the top and 'i' at the bottom + if(i == 97 or i == 98): + colour = 'B' + elif(i == 96+self.rows or i == 97+self.rows): + colour = 'W' + for j in range(1,self.columns+1): # numbers for rows, with 1 at the left and 8 at the right + index = str(chr(i)) + str(j) + if(i == 97 or i==97+self.rows): + if(j == 1 or j == 8): + self.playBoard[index] = rook.Rook(0,True,colour,j) + elif(j == 2 or j == 7): + self.playBoard[index] = knight.Knight(0,True,colour,j) + elif(j == 3 or j == 6): + self.playBoard[index] = bishop.Bishop(0,True,colour,j) + elif(j == 4): + self.playBoard[index] = queen.Queen(0,True,colour,j) + else: + self.playBoard[index] = king.King(0,True,colour,j) + elif(i == 98 or i==96+self.rows): + self.playBoard[index] = pawn.Pawn(0,True,colour,j) + else: + self.playBoard[index] = '0' + + def play(self,start,end,colour): # TODO: stop pieces from teleporting through eachother, modify the entanglement, add the superposition move + # check if inputs are valid + if(end != start and self.checkPoint(start) and self.checkPoint(end)): + if(self.playBoard[start] != '0'): + # check if colour matches + if(colour == self.playBoard[start].getId()[0:1]): + # evaluate the path travelled + dy = ord(start[0:1]) - ord(end[0:1]) # +ve: up, -ve: down + dx = int(start[1:]) - int(end[1:]) # +ve: right, -ve: left + movement = self.pathToString(dx,dy) + # output path as string into piece + if(self.playBoard[end] == '0'): + if(self.playBoard[start].canMove(movement)): + self.playBoard[end] = self.playBoard[start] + self.playBoard[start] = '0' + return True + else: + return False + # check for attack + else: # ends at another piece + if(self.playBoard[start].getId()[0:1] != self.playBoard[end].getId()[0:1]): # canMove function is contained in attack + # then do the attack + kill,supKill = self.playBoard[start].attack(self.playBoard[end],movement) + if(kill): # maybe modify attack return values + self.playBoard[end] = self.playBoard[start] + self.playBoard[start] = '0' + if(supKill): + self.findAndDestroyAllId(end) + return True + return False + else: + return False + return False + + def checkPoint(self,p): + charNum = ord(p[0:1]) + if(charNum > 96 and charNum < 98+self.rows): + num = int(p[1:]) + if(num > 0 and num < 9): + return True + return False + + def pathToString(self,dx,dy): + string = '' + if(dx > 0): # goes right + if(dy > 0): # goes up + if(dx == 2 and dy == 1): # L move + string = 'rq' + elif(dx == 1 and dy == 2): + string = 'uq' + elif(dx > dy): + diff = dx - dy + for i in range(dy): + string = string + 'q' + for i in range(diff): + string = string + 'r' + elif(dx < dy): + diff = dy - dx + for i in range(dx): + string = string + 'q' + for i in range(diff): + string = string + 'u' + else: + for i in range(dx): + string = string + 'q' + elif(dy == 0): + for i in range(dx): + string = string + 'r' + else: # goes down + if(dx == 2 and dy == -1): + string = 'rg' + elif(dx == 1 and dy == -2): + string = 'dg' + elif(dx > abs(dy)): + diff = dx - abs(dy) # dy is -ve + for i in range(abs(dy)): + string = string + 'g' + for i in range(diff): + string = string + 'r' + elif(dx < abs(dy)): + diff = abs(dy) - dx + for i in range(dx): + string = string + 'g' + for i in range(diff): + string = string + 'd' + else: + for i in range(dx): + string = string + 'g' + elif(dx == 0): + if(dy > 0): # up + for i in range(dy): + string = string + 'u' + else: # down (no change is an invalid input) + for i in range(abs(dy)): + string = string + 'd' + else: # goes left + if(dy > 0): # goes up + if(dx == -2 and dy == 1): # L move + string = 'lf' + elif(dx == -1 and dy == 2): + string = 'uf' + elif(abs(dx) > dy): + diff = abs(dx) - dy + for i in range(dy): + string = string + 'f' + for i in range(diff): + string = string + 'l' + elif(abs(dx) < dy): + diff = dy - abs(dx) + for i in range(abs(dx)): + string = string + 'f' + for i in range(diff): + string = string + 'u' + else: + for i in range(abs(dx)): + string = string + 'f' + elif(dy == 0): + for i in range(abs(dx)): + string = string + 'l' + else: # goes down + if(dx == -2 and dy == -1): + string = 'lh' + elif(dx == -1 and dy == -2): + string = 'dh' + elif(abs(dx) > abs(dy)): + diff = abs(dx) - abs(dy) # dy is -ve + for i in range(abs(dy)): + string = string + 'h' + for i in range(diff): + string = string + 'l' + elif(abs(dx) < abs(dy)): + diff = abs(dy) - abs(dx) + for i in range(abs(dx)): + string = string + 'h' + for i in range(diff): + string = string + 'd' + else: + for i in range(abs(dx)): + string = string + 'h' + return string + def findAndDestroyAllId(self,index): + # search board for all matching pieces and destroy them + return '' + + def toString(self): + string = '' + for i in range(97,99+self.rows): + if(i < 98+self.rows): + string = string + chr(i) + string = string + ' ' + for j in range(1,self.columns+1): + index = str(chr(i)) + str(j) + if(i == 98+self.rows): + string = string + ' ' + str(j) + elif(self.playBoard[index] == '0'): + string = string + '| ' + else: + idTag = self.playBoard[index].getId()[:3] + string = string + '|' + idTag + if(i < 98+self.rows): + string = string + '|\n' + return string diff --git a/functions.py b/functions.py @@ -0,0 +1,56 @@ +# functions.py - QuantumChess +# Author: Cody Lewis +# Date: 23-FEB-2018 +# Mod.: 25-FEB-2018 +# Description: +# defines misc. functions for the Quantum Chess program +def evalQubit(qrNo): + from qiskit import QuantumProgram + qp = QuantumProgram() + try: + qr = qp.create_quantum_register("qr",qrNo) + cr = qp.create_classical_register("cr",qrNo) + qc = qp.create_circuit("superposition", [qr], [cr]) + + isPiece = '' + for i in range(qrNo): + qc.h(qr[i]) + isPiece = isPiece + '1' + qc.measure(qr, cr) + result = qp.execute(["superposition"], backend="local_qasm_simulator", shots=1024) + counts = result.get_counts("superposition") + return isPiece == getGreatestCount(qrNo,counts) + except QISKITError as ex: + print("There was an error in the circuit! Error = {}".format(ex)) + except RegisterSizeError as ex: + print("Error in the number of registers! Error = {}".format(ex)) + +def getGreatestCount(qrNo,counts): + # increment throught dict, find greatest value, return index + greatestCount = '' + gc = 0 + perms = pow(2,qrNo) + for i in range(0,perms): + index = bin(i)[2:] + if(len(index) < qrNo): + while(len(index) < qrNo): + index = '0' + index + if(counts[index] > gc): + greatestCount = index + gc = counts[index] + return greatestCount + +def pow(n,i): + if(i == 0 or i == 1): + return n + else: + return n*pow(n,i-1) + +def splitMovement(movement): + # split the string movement into individual characters and store them in the returned array + # movement key: f = up dia left, u = up, q = up dia right, r = right, l = left, h = down dia left, d = down, g = down dia right + # Note: The move movement directions are from a birds eye view with the white pieces on the bottom + moveArr = [] + for i in range(len(movement)): + moveArr.append(movement[i:i+1]) + return moveArr diff --git a/king.py b/king.py @@ -0,0 +1,18 @@ +# king.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +class King(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'Ki' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + direction = moveArr[0] + if(len(moveArr) == 1): + if(direction == 'd' or direction == 'u' or direction == 'r' or direction == 'l' or direction == 'f' or direction == 'q' or direction == 'h' or direction == 'g'): + return True + return False diff --git a/knight.py b/knight.py @@ -0,0 +1,33 @@ +# knight.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +class Knight(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'Kn' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + if(len(moveArr) == 2): # need the L movement + if(self.__isL(moveArr)): + return True + return False + + def __isL(self,moveArr): + if(moveArr[0] == 'u'): + if(moveArr[1] == 'f' or moveArr[1] == 'q'): + return True + elif(moveArr[0] == 'd'): + if(moveArr[1] == 'h' or moveArr[1] == 'g'): + return True + elif(moveArr[0] == 'l'): + if(moveArr[1] == 'q' or moveArr[1] == 'g'): + return True + elif(moveArr[0] == 'r'): + if(moveArr[1] == 'f' or moveArr[1] == 'h'): + return True + else: + return False diff --git a/pawn.py b/pawn.py @@ -0,0 +1,42 @@ +# pawn.py - QuantumChess +# Author: Cody Lewis +# Date: 23-FEB-2018 +# Mod.: 23-FEB-2018 +import piece +import functions +class Pawn(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'P ' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + self.firstMove = True + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + if(self.firstMove): + moveNum = 2 + self.firstMove = False + else: + moveNum = 1 + if(len(moveArr) <= moveNum): + if(self.colour == 'W'): + direction = 'u' + else: + direction = 'd' + for i in range(len(moveArr)): + if(not moveArr[i] == direction): + return False + return True + return False + + def canAttack(self,movement): + moveArr = functions.splitMovement(movement) + if(self.colour == 'W'): + dir1 = 'f' + dir2 = 'q' + else: + dir1 = 'h' + dir2 = 'g' + if(len(moveArr) == 1 and (moveArr[0] == dir1 or moveArr[0] == dir2)): + return True + else: + return False diff --git a/piece.py b/piece.py @@ -0,0 +1,37 @@ +# piece.py - QuantumChess +# Author: Cody Lewis +# Date: 21-FEB-2018 +# Mod.: 28-FEB-2018 +# Description: Defines the super class of a piece in Quantum Chess +import functions +class Piece: + def __init__(self,superposNum,frstSuperPos,col,idT): + self.superposNo = superposNum + self.firstSuperPos = frstSuperPos + self.colour = col + self.idTag = self.colour + idT + + def getId(self): + return self.idTag + + def superpostion(self): + if(self.firstSuperPos): + self.__init__(1,False,self.colour,self.idTag) + + def attack(self,enemy,movement): + if(self.canAttack(movement)): + return enemy.die() + else: + return False + + def canAttack(self,movement): + return self.canMove(movement) + + def die(self): + if(self.superposNo > 0): + return True,self.observe() + return True,False + + def observe(self): + # check the Qubit stored in this piece + return functions.evalQubit(self.superposNo) diff --git a/queen.py b/queen.py @@ -0,0 +1,20 @@ +# queen.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +class Queen(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'Q ' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + direction = moveArr[0] + if(direction == 'd' or direction == 'u' or direction == 'r' or direction == 'l' or direction == 'f' or direction == 'q' or direction == 'h' or direction == 'g'): + for i in range(1,len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False diff --git a/rook.py b/rook.py @@ -0,0 +1,20 @@ +# rook.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +class Rook(piece.Piece): + def __init__(self,superposNum,frstSuperPos,col,idT): + idT = 'R ' + str(idT) + piece.Piece.__init__(self,superposNum,frstSuperPos,col,idT) + + def canMove(self,movement): + moveArr = functions.splitMovement(movement) + direction = moveArr[0] + if(direction == 'u' or direction == 'r' or direction == 'l' or direction == 'd'): + for i in range(1,len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False