quantum-chess

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

commit 309c0859592e3e9b306dd4dedf47cdb425ec0ce9
parent 296c10eb0ae9ea31b6087c930052098e50c3337e
Author: Cody Lewis <luxdotsugi@gmail.com>
Date:   Mon, 10 Dec 2018 09:51:01 +1100

Updated qiskit, and re-added cmd mode

Diffstat:
MWebApp/Functions.py | 18+++++++++++-------
Acmd/bishop.py | 20++++++++++++++++++++
Acmd/board.py | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acmd/functions.py | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acmd/king.py | 19+++++++++++++++++++
Acmd/knight.py | 34++++++++++++++++++++++++++++++++++
Acmd/pawn.py | 44++++++++++++++++++++++++++++++++++++++++++++
Acmd/piece.py | 42++++++++++++++++++++++++++++++++++++++++++
Acmd/play.py | 39+++++++++++++++++++++++++++++++++++++++
Acmd/queen.py | 20++++++++++++++++++++
Acmd/rook.py | 20++++++++++++++++++++
11 files changed, 579 insertions(+), 7 deletions(-)

diff --git a/WebApp/Functions.py b/WebApp/Functions.py @@ -1,19 +1,23 @@ +# functions.py - QuantumChess +# Author: Cody Lewis +# Date: 23-FEB-2018 +# Description: +# defines misc. functions for the Quantum Chess program from enum import Enum -from qiskit import QuantumProgram +from qiskit import * def evalQubit(qrNo): # check if the most occurring qubit is all ones - qp = QuantumProgram() try: - qr = qp.create_quantum_register("qr", qrNo) - cr = qp.create_classical_register("cr", qrNo) - qc = qp.create_circuit("superposition", [qr], [cr]) + qr = QuantumRegister(qrNo) + cr = ClassicalRegister(qrNo) + qc = QuantumCircuit(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") + result = execute(qc, Aer.get_backend("local_qasm_simulator")).result() + counts = result.get_counts(qc) return isPiece == getGreatestCount(qrNo, counts) except QISKITError as ex: print("There was an error in the circuit! Error = {}".format(ex)) diff --git a/cmd/bishop.py b/cmd/bishop.py @@ -0,0 +1,20 @@ +# bishop.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +import piece +import functions +from functions import Direction +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 in [Direction.UPLEFT.value, Direction.UPRIGHT.value, Direction.DOWNLEFT.value, Direction.DOWNRIGHT.value]: + for i in range(1, len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False diff --git a/cmd/board.py b/cmd/board.py @@ -0,0 +1,271 @@ +# board.py - QuantumChess +# Author: Cody Lewis +# Date: 26-FEB-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 re # regex +import pawn # the various pieces +import rook +import bishop +import knight +import queen +import king +from functions import Direction +class Board: + def __init__(self): + self.playBoard = dict() + self.rows = 7 + 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): # essentially a factory method + 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 addMovement(self, i, move): # add an atomic movement unit to the index + if(move == Direction.UP.value): + i = chr(ord(i[0:1])-1) + str(int(i[1:])) + elif(move == Direction.DOWN.value): + i = chr(ord(i[0:1])+1) + str(int(i[1:])) + elif(move == Direction.RIGHT.value): + i = i[0:1] + str(int(i[1:])-1) + elif(move == Direction.LEFT.value): + i = i[0:1] + str(int(i[1:])+1) + elif(move == Direction.UPRIGHT.value): + i = chr(ord(i[0:1])-1) + str(int(i[1:])-1) + elif(move == Direction.DOWNRIGHT.value): + i = chr(ord(i[0:1])+1) + str(int(i[1:])-1) + elif(move == Direction.DOWNLEFT.value): + i = chr(ord(i[0:1])+1) + str(int(i[1:])+1) + else: + i = chr(ord(i[0:1])-1) + str(int(i[1:])+1) + return i + + def play(self, start, end, colour, sp): + # 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) + i = start + i = self.addMovement(i, movement[0:1]) + # if((self.playBoard[start].getId()[1:3] != "Kn" and (movement[0:1] in ['u', 'd', 'l', 'r'])) and i != end and self.playBoard[i] != '0'): # make sure nothing is in the way + # return False + if(len(movement) > 1): + for j in range(1, len(movement)): + i = self.addMovement(i, movement[j : j + 1]) + if(i != end and self.playBoard[i] != '0'): # check whether there are pieces in the way + return False + # output path as string into piece + if(self.playBoard[end] == '0'): + if(self.playBoard[start].canMove(movement)): + if(sp): + self.playBoard[start].superposition() + self.playBoard[end] = self.playBoard[start] + else: + self.playBoard[end] = self.playBoard[start] + self.playBoard[start] = '0' + return True + else: + return False + # check for attack + else: # ends at another piece + if(sp): + return False + 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): + if(supKill): + self.findAndDestroyParent(end) + self.playBoard[end] = self.playBoard[start] + self.playBoard[start] = '0' + return True + return False + else: + return False + return False + + def checkPoint(self, p): # check whether a point is on the board + 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 findAndDestroyParent(self, point): + # search board for all matching pieces and destroy them + ident = self.playBoard[point].getId() # identifier + num = int(ident[len(ident) - 1 : len(ident)]) + parent = ident[0 : len(ident) - 1] + '.' + for i in range(97, 98 + self.rows): + for j in range(1, self.columns + 1): + index = chr(i) + str(j) + if(self.playBoard[index] != '0'): + if(index != point and re.match(parent, self.playBoard[index].getId())): + otherId = self.playBoard[index].getId() + otherNum = int(otherId[len(otherId) - 1 : len(otherId)]) + if(otherNum >= num): + self.playBoard[index] = '0' + + def win(self): # find if one of the players have no kings left + blackWin = True + bkPat = 'BKi.*' + whiteWin = True + wkPat = 'WKi.*' + for i in range(97, 98 + self.rows): + for j in range(1, self.columns + 1): + index = chr(i) + str(j) + if(self.playBoard[index] != '0'): + currId = self.playBoard[index].getId() + if(re.match(bkPat, currId)): + whiteWin = False + elif(re.match(wkPat, currId)): + blackWin = False + if(whiteWin): + return 'W' + elif(blackWin): + return 'B' + else: + return '0' + + def toString(self): + string = '' + for i in range(97, 99 + self.rows): # iterate through the letter part of the index + 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): # put a pipe at the end of the line + string = string + '|\n' + return string diff --git a/cmd/functions.py b/cmd/functions.py @@ -0,0 +1,59 @@ +# functions.py - QuantumChess +# Author: Cody Lewis +# Date: 23-FEB-2018 +# Description: +# defines misc. functions for the Quantum Chess program +from enum import Enum +from qiskit import * +def evalQubit(qrNo): # check if the most occurring qubit is all ones + try: + qr = QuantumRegister(qrNo) + cr = ClassicalRegister(qrNo) + qc = QuantumCircuit(qr, cr) + + isPiece = '' + for i in range(qrNo): + qc.h(qr[i]) + isPiece = isPiece + '1' + qc.measure(qr, cr) + result = execute(qc, Aer.get_backend("local_qasm_simulator")).result() + counts = result.get_counts(qc) + 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 = 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 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 + +class Direction(Enum): + UPLEFT = "f" + UP = "u" + UPRIGHT = "q" + RIGHT = "r" + LEFT = "l" + DOWN = "d" + DOWNLEFT = "h" + DOWNRIGHT = "g" diff --git a/cmd/king.py b/cmd/king.py @@ -0,0 +1,19 @@ +# king.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +from functions import Direction +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 in [Direction.DOWN.value, Direction.UP.value, Direction.RIGHT.value, Direction.LEFT.value, Direction.DOWNRIGHT.value, Direction.DOWNLEFT.value, Direction.UPRIGHT.value, Direction.UPLEFT.value]: + return True + return False diff --git a/cmd/knight.py b/cmd/knight.py @@ -0,0 +1,34 @@ +# knight.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +# Mod.: 24-FEB-2018 +import piece +import functions +from functions import Direction +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] == Direction.UP.value: + if moveArr[1] == Direction.UPLEFT.value or moveArr[1] == Direction.UPRIGHT.value: + return True + elif moveArr[0] == Direction.DOWN.value: + if moveArr[1] == Direction.DOWNLEFT.value or moveArr[1] == Direction.DOWNRIGHT.value: + return True + elif moveArr[0] == Direction.LEFT.value: + if moveArr[1] == Direction.UPLEFT.value or moveArr[1] == Direction.DOWNLEFT.value: + return True + elif moveArr[0] == Direction.RIGHT.value: + if moveArr[1] == Direction.UPRIGHT.value or moveArr[1] == Direction.DOWNRIGHT.value: + return True + else: + return False diff --git a/cmd/pawn.py b/cmd/pawn.py @@ -0,0 +1,44 @@ +# pawn.py - QuantumChess +# Author: Cody Lewis +# Date: 23-FEB-2018 +# Mod.: 23-FEB-2018 +import piece +import functions +from functions import Direction +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 = Direction.UP.value + else: + direction = Direction.DOWN.value + print(direction) + 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 = Direction.UPLEFT.value + dir2 = Direction.UPRIGHT.value + else: + dir1 = Direction.DOWNLEFT.value + dir2 = Direction.DOWNRIGHT.value + if(len(moveArr) == 1 and (moveArr[0] == dir1 or moveArr[0] == dir2)): + return True + else: + return False diff --git a/cmd/piece.py b/cmd/piece.py @@ -0,0 +1,42 @@ +# piece.py - QuantumChess +# Author: Cody Lewis +# Date: 21-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 getSuperPosNum(self): + return self.superposNo + + def superposition(self): + self.superposNo += 1 + self.idTag = self.idTag + str(self.superposNo) + print(self.idTag) + if self.firstSuperPos: + self.firstSuperPos = False + + def attack(self, enemy, movement): + if self.canAttack(movement): + return enemy.die() + else: + return False, 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/cmd/play.py b/cmd/play.py @@ -0,0 +1,39 @@ +# Author: Cody Lewis +# Date: 12-APR-2018 +# Description: The main game flow of the quantum chess game +import re +import board +if __name__ == "__main__": + b = board.Board() + i = 0 + col = 'B' + pattern = '[Yy]e?s?' + sp = False + while(True): + winVal = b.win() + if(winVal == 'W'): + print("White wins!") + break + elif(winVal == 'B'): + print("Black wins!") + break + print(b.toString()) + i += 1 + if(col == 'W'): + col = 'B' + print("Blacks turn") + else: + col = 'W' + print("Whites turn") + while(True): + superPos = str(input("Do you want to super-position (y/n)? ")) + if(re.match(pattern, superPos)): + print('Super-position mode on') + sp = True + start = str(input("Choose your starting piece: ")) + end = str(input("Choose your end place: ")) + if(b.play(start, end, col, sp)): + sp = False + break + else: + print("Your move was invalid, try again") diff --git a/cmd/queen.py b/cmd/queen.py @@ -0,0 +1,20 @@ +# queen.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +import piece +import functions +from functions import Direction +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 in [Direction.DOWN.value, Direction.UP.value, Direction.RIGHT.value, Direction.LEFT.value, Direction.DOWNRIGHT.value, Direction.DOWNLEFT.value, Direction.UPRIGHT.value, Direction.UPLEFT.value]: + for i in range(1, len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False diff --git a/cmd/rook.py b/cmd/rook.py @@ -0,0 +1,20 @@ +# rook.py - QuantumChess +# Author: Cody Lewis +# Date: 24-FEB-2018 +import piece +import functions +from functions import Direction +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 in [Direction.UP.value, Direction.DOWN.value, Direction.LEFT.value, Direction.RIGHT.value]: + for i in range(1, len(moveArr)): + if direction != moveArr[i]: + return False + return True + return False