quantum-chess

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

commit 2cd12146bc392382bf9ba4b3674e4235e75e71ab
parent 24c60df5d92316806393195ca04a128c43f4d804
Author: Cody Lewis <luxdotsugi@gmail.com>
Date:   Mon,  6 Aug 2018 10:32:46 +1000

The web app now has a starting board

Diffstat:
Asrc/WebApp/Board.py | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WebApp/Functions.py | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/WebApp/Main.py | 10+++++++---
Asrc/WebApp/Piece.py | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/WebApp/__pycache__/Board.cpython-36.pyc | 0
Asrc/WebApp/__pycache__/Functions.cpython-36.pyc | 0
Msrc/WebApp/__pycache__/Main.cpython-36.pyc | 0
Asrc/WebApp/__pycache__/Piece.cpython-36.pyc | 0
Msrc/WebApp/static/css/style.css | 26++++++++++++++++++++++++++
Msrc/WebApp/templates/base.html | 2++
Msrc/WebApp/templates/index.html | 46+++++++++++++++++++++++++++++++++++++++++++---
11 files changed, 554 insertions(+), 6 deletions(-)

diff --git a/src/WebApp/Board.py b/src/WebApp/Board.py @@ -0,0 +1,260 @@ +import re # regex +import Piece +from Functions import Direction +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): # essentially a factory method + if(j == 1 or j == 8): + self.playBoard[index] = Piece.Rook(0, True, colour, j) + elif(j == 2 or j == 7): + self.playBoard[index] = Piece.Knight(0, True, colour, j) + elif(j == 3 or j == 6): + self.playBoard[index] = Piece.Bishop(0, True, colour, j) + elif(j == 4): + self.playBoard[index] = Piece.Queen(0, True, colour, j) + else: + self.playBoard[index] = Piece.King(0, True, colour, j) + elif(i == 98 or i == 96 + self.rows): + self.playBoard[index] = Piece.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): + i = chr(ord(i[0:1])-1) + str(int(i[1:])) + elif(move == Direction.DOWN): + i = chr(ord(i[0:1])+1) + str(int(i[1:])) + elif(move == Direction.RIGHT): + i = i[0:1] + str(int(i[1:])-1) + elif(move == Direction.LEFT): + i = i[0:1] + str(int(i[1:])+1) + elif(move == Direction.UPRIGHT): + i = chr(ord(i[0:1])-1) + str(int(i[1:])-1) + elif(move == Direction.DOWNRIGHT): + i = chr(ord(i[0:1])+1) + str(int(i[1:])-1) + elif(move == Direction.DOWNLEFT): + 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 Pieces 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/WebApp/Functions.py b/src/WebApp/Functions.py @@ -0,0 +1,55 @@ +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/WebApp/Main.py b/src/WebApp/Main.py @@ -1,4 +1,5 @@ -from qiskit import QuantumProgram +# import Board +# from qiskit import QuantumProgram from flask import ( Blueprint, render_template, url_for, redirect, current_app, g, session, request, flash ) @@ -10,4 +11,7 @@ def index(): @bp.route("/home") def home(): - return render_template("index.html")- \ No newline at end of file + return render_template("index.html") + +# def create_board(): +# return Board.Board()+ \ No newline at end of file diff --git a/src/WebApp/Piece.py b/src/WebApp/Piece.py @@ -0,0 +1,161 @@ +import Functions +from Functions import Direction +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) + 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) + +class Pawn(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'P ' + str(idT) + 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 + else: + direction = Direction.DOWN + 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 + dir2 = Direction.UPRIGHT + else: + dir1 = Direction.DOWNLEFT + dir2 = Direction.DOWNRIGHT + if(len(moveArr) == 1 and (moveArr[0] == dir1 or moveArr[0] == dir2)): + return True + else: + return False + +class Bishop(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'B ' + str(idT) + Piece.__init__(self, superposNum, frstSuperPos, col, idT) + + def canMove(self,movement): + moveArr = Functions.splitMovement(movement) + direction = moveArr[0] + if direction in [Direction.UPLEFT, Direction.UPRIGHT, Direction.DOWNLEFT, Direction.DOWNRIGHT]: + for i in range(1, len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False + +class King(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'Ki' + str(idT) + 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, Direction.UP, Direction.RIGHT, Direction.LEFT, Direction.DOWNRIGHT, Direction.DOWNLEFT, Direction.UPRIGHT, Direction.UPLEFT]: + return True + return False + +class Knight(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'Kn' + str(idT) + 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): + if(moveArr[1] == Direction.UPLEFT or moveArr[1] == Direction.UPRIGHT): + return True + elif(moveArr[0] == Direction.DOWN): + if(moveArr[1] == Direction.DOWNLEFT or moveArr[1] == Direction.DOWNRIGHT): + return True + elif(moveArr[0] == Direction.LEFT): + if(moveArr[1] == Direction.UPLEFT or moveArr[1] == Direction.DOWNLEFT): + return True + elif(moveArr[0] == Direction.RIGHT): + if(moveArr[1] == Direction.UPRIGHT or moveArr[1] == Direction.DOWNRIGHT): + return True + else: + return False + +class Queen(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'Q ' + str(idT) + Piece.__init__(self, superposNum, frstSuperPos, col, idT) + + def canMove(self, movement): + moveArr = Functions.splitMovement(movement) + direction = moveArr[0] + if direction in [Direction.DOWN, Direction.UP, Direction.RIGHT, Direction.LEFT, Direction.DOWNRIGHT, Direction.DOWNLEFT, Direction.UPRIGHT, Direction.UPLEFT]: + for i in range(1, len(moveArr)): + if(direction != moveArr[i]): + return False + return True + return False + +class Rook(Piece): + def __init__(self, superposNum, frstSuperPos, col, idT): + idT = 'R ' + str(idT) + Piece.__init__(self, superposNum, frstSuperPos, col, idT) + + def canMove(self, movement): + moveArr = Functions.splitMovement(movement) + direction = moveArr[0] + if direction in [Direction.UP, Direction.DOWN, Direction.LEFT, Direction.RIGHT]: + for i in range(1, len(moveArr)): + if direction != moveArr[i]: + return False + return True + return False diff --git a/src/WebApp/__pycache__/Board.cpython-36.pyc b/src/WebApp/__pycache__/Board.cpython-36.pyc Binary files differ. diff --git a/src/WebApp/__pycache__/Functions.cpython-36.pyc b/src/WebApp/__pycache__/Functions.cpython-36.pyc Binary files differ. diff --git a/src/WebApp/__pycache__/Main.cpython-36.pyc b/src/WebApp/__pycache__/Main.cpython-36.pyc Binary files differ. diff --git a/src/WebApp/__pycache__/Piece.cpython-36.pyc b/src/WebApp/__pycache__/Piece.cpython-36.pyc Binary files differ. diff --git a/src/WebApp/static/css/style.css b/src/WebApp/static/css/style.css @@ -2,3 +2,29 @@ background: linear-gradient(rgb(0, 72, 0), rgb(28, 100, 28), rgb(56, 128, 56), rgb(84, 156, 84), rgb(255, 255, 255)); background-repeat: no-repeat; } + +div.square { + height: 50px; + border: 1px solid black; + text-align: center; +} + +div.square:hover { + background-color: rgb(146, 255, 255) !important; +} + +div.move-space { + background-color: rgb(252, 118, 118) !important; +} + +.piece { + font-size: 150%; +} + +.pc-black { + color: red; +} + +.pc-white { + color: blue; +} diff --git a/src/WebApp/templates/base.html b/src/WebApp/templates/base.html @@ -21,6 +21,8 @@ <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script> <!-- Latest compiled JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script> + <!-- Font awesome --> + <script defer src="https://use.fontawesome.com/releases/v5.2.0/js/all.js" integrity="sha384-4oV5EgaV02iISL2ban6c/RmotsABqE4yZxZLcYMAdG7FAPsyHYAPpywE9PJo+Khy" crossorigin="anonymous"></script> {% block scripts %}{% endblock %} </head> <body class="bg-img"> diff --git a/src/WebApp/templates/index.html b/src/WebApp/templates/index.html @@ -8,10 +8,50 @@ {% block contents %} <div class="container-fluid bg-light"> + <br /> <div class="container"> - <!-- <h1 class="display-1">Quantum Chess</h1> --> - <!-- <canvas class="col-12" id="qccanvas"></canvas> --> - <div id="board" class="col-12"></div> + <div class="container" id="board"> + {% for i in range(0, 8) %} + <div class="row"> + <div class="col-sm-2"></div> + {% for j in range(0, 8) %} + <div class="col-1 + {% if ((j % 2) == (i % 2)) %} + bg-dark + {% else %} + bg-light + {% endif %} + square" id="{{ "ABCDEFGH"[i] }}{{ j + 1 }}"> + {% if i in [0, 1, 6, 7] %} + <span class="piece text-center fa + {% if i in [0, 7] %} + {% if j in [0, 7] %} + fa-chess-rook + {% elif j in [1, 6] %} + fa-chess-knight + {% elif j in [2, 5] %} + fa-chess-bishop + {% elif j == 3 %} + fa-chess-queen + {% else %} + fa-chess-king + {% endif %} + {% else %} + fa-chess-pawn + {% endif %} + {% if i in [0, 1] %} + pc-black + {% else %} + pc-white + {% endif %} + "></span> + {% endif %} + </div> + {% endfor %} + <div class="col-sm-2"></div> + </div> + {% endfor %} + </div> </div> </div> {% endblock %} \ No newline at end of file