quantum-chess

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

commit 6f1f30c1603195682a818f6db175ccaed1710ef3
parent 42c583fe1aa499b595ab812ebf3dd99395553e61
Author: Cody Lewis <luxdotsugi@gmail.com>
Date:   Mon,  3 Sep 2018 09:20:52 +1000

Full migrated to a web app

Diffstat:
AProcfile | 1+
MREADME.md | 1-
Rsrc/WebApp/Board.py -> WebApp/Board.py | 0
Rsrc/WebApp/Functions.py -> WebApp/Functions.py | 0
Rsrc/WebApp/Main.py -> WebApp/Main.py | 0
Rsrc/WebApp/Piece.py -> WebApp/Piece.py | 0
Rsrc/WebApp/__init__.py -> WebApp/__init__.py | 0
Rsrc/WebApp/static/css/style.css -> WebApp/static/css/style.css | 0
Rsrc/WebApp/static/images/background.png -> WebApp/static/images/background.png | 0
Rsrc/WebApp/static/scripts/chess.js -> WebApp/static/scripts/chess.js | 0
Rsrc/WebApp/templates/base.html -> WebApp/templates/base.html | 0
Rsrc/WebApp/templates/error.html -> WebApp/templates/error.html | 0
Rsrc/WebApp/templates/index.html -> WebApp/templates/index.html | 0
Arequirements.txt | 4++++
Dsrc/cmd/bishop.py | 20--------------------
Dsrc/cmd/board.py | 271-------------------------------------------------------------------------------
Dsrc/cmd/functions.py | 60------------------------------------------------------------
Dsrc/cmd/king.py | 19-------------------
Dsrc/cmd/knight.py | 34----------------------------------
Dsrc/cmd/pawn.py | 44--------------------------------------------
Dsrc/cmd/piece.py | 42------------------------------------------
Dsrc/cmd/play.py | 39---------------------------------------
Dsrc/cmd/queen.py | 20--------------------
Dsrc/cmd/rook.py | 20--------------------
Awsgi.py | 3+++
25 files changed, 8 insertions(+), 570 deletions(-)

diff --git a/Procfile b/Procfile @@ -0,0 +1 @@ +web: gunicorn wsgi --log-file - diff --git a/README.md b/README.md @@ -1,6 +1,5 @@ # QuantumChess Quantum Chess by Cody Lewis -Last Modified: 12-APR-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 diff --git a/src/WebApp/Board.py b/WebApp/Board.py diff --git a/src/WebApp/Functions.py b/WebApp/Functions.py diff --git a/src/WebApp/Main.py b/WebApp/Main.py diff --git a/src/WebApp/Piece.py b/WebApp/Piece.py diff --git a/src/WebApp/__init__.py b/WebApp/__init__.py diff --git a/src/WebApp/static/css/style.css b/WebApp/static/css/style.css diff --git a/src/WebApp/static/images/background.png b/WebApp/static/images/background.png Binary files differ. diff --git a/src/WebApp/static/scripts/chess.js b/WebApp/static/scripts/chess.js diff --git a/src/WebApp/templates/base.html b/WebApp/templates/base.html diff --git a/src/WebApp/templates/error.html b/WebApp/templates/error.html diff --git a/src/WebApp/templates/index.html b/WebApp/templates/index.html diff --git a/requirements.txt b/requirements.txt @@ -0,0 +1,4 @@ +flask +qiskit +bleach +gunicorn diff --git a/src/cmd/bishop.py b/src/cmd/bishop.py @@ -1,20 +0,0 @@ -# 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/src/cmd/board.py b/src/cmd/board.py @@ -1,271 +0,0 @@ -# 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/src/cmd/functions.py b/src/cmd/functions.py @@ -1,60 +0,0 @@ -# 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 -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]) - - 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 = 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/src/cmd/king.py b/src/cmd/king.py @@ -1,19 +0,0 @@ -# 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/src/cmd/knight.py b/src/cmd/knight.py @@ -1,34 +0,0 @@ -# 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/src/cmd/pawn.py b/src/cmd/pawn.py @@ -1,44 +0,0 @@ -# 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/src/cmd/piece.py b/src/cmd/piece.py @@ -1,42 +0,0 @@ -# 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/src/cmd/play.py b/src/cmd/play.py @@ -1,39 +0,0 @@ -# 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/src/cmd/queen.py b/src/cmd/queen.py @@ -1,20 +0,0 @@ -# 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/src/cmd/rook.py b/src/cmd/rook.py @@ -1,20 +0,0 @@ -# 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 diff --git a/wsgi.py b/wsgi.py @@ -0,0 +1,3 @@ +from WebApp import RAS_APP as application # move statics to ./ before deployment +if __name__ == "__main__": + application.run()