Example #1
0
def resign(cursor, params, connhandler):
    gameid, sessionid = params
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {"(SELECT Id, Name FROM Users) AS BlackUser":"******", "(SELECT Id, Name FROM Users) AS WhiteUser":"******", "GameStatuses":"GameStatuses.Id=Games.Status"}, "Games.Id, Position, White, Black, WhiteUser.Name, BlackUser.Name, GameStatuses.Description")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ['Id', 'Position', 'White', 'Black', 'WhiteName', 'BlackName', 'PrevStatus'])
    #prevent resignation in completed game
    if gamedata["PrevStatus"] != "In Progress":
        return b"FAILURE\r\nGame is over\r\n\r\n"
    blackid = gamedata['Black']
    if len(gamedata) == 0:
        return b"FAILURE\r\nNo such game or you are not part of it\r\n\r\n"
    #if opposing player only has lone king, change resign to draw by autoaccept
    position = gamedata['Position']
    isblackplayer = blackid==uid
    textstatus = 'White win' if isblackplayer else 'Black win'
    isWinnerNonKing = (lambda x: (x!='K' and x.isupper())) if isblackplayer else (lambda x: (x!='k' and x.islower()))
    winningPieceGen = (i for i in position[:64] if isWinnerNonKing(i))
    try:
        next(winningPieceGen)
        textsubstatus = "Resign"
    except StopIteration:
        textstatus = "Draw"
        textsubstatus = "Autoaccept"
    statuscursor = dblogic.selectCommon(cursor, "GameStatuses INNER JOIN GameSubstatuses ON GameStatuses.Id=GameSubstatuses.Superstatus", {"GameStatuses.Description":textstatus, "GameSubstatuses.Description":textsubstatus}, "GameStatuses.Id, GameSubstatuses.Id")
    statusdata = dblogic.unwrapCursor(statuscursor, False, ["StatusId", "SubstatusId"])
    statusid, substatusid = statusdata["StatusId"], statusdata["SubstatusId"]
    dblogic.updateCommon(cursor, "Games", {"Status":statusid, "Substatus": substatusid}, gameid)
    oppname = gamedata['WhiteName'] if isblackplayer else gamedata['BlackName']
    serverlogic.notifyuser(oppname, bytewrap("NOTIFY\r\nSTATUSCHANGE\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gameid, textstatus, textsubstatus)))
    return bytewrap("SUCCESS\r\n%s\r\n%s\r\n\r\n"%(textstatus, textsubstatus))
Example #2
0
def promote(cursor, params, connhandler):
    gameid, promoteType, sessionid = params
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {"(SELECT Id, Name FROM Users) AS BlackUser":"******", "(SELECT Id, Name FROM Users) AS WhiteUser":"******"}, "Position, White, Black, WhiteUser.Name, BlackUser.Name")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ["Position", "WhiteId", "BlackId", "WhiteName", "BlackName"])
    position = gamedata['Position']
    turn = position[69]
    if (turn == 'W') != (gamedata['WhiteId'] == uid):
        return b"FAILURE\r\nOut of turn play\r\n\r\n"
    promotesquare = chesslogic.promoteSquare(position)
    if promotesquare == None:
        print(gamedata)
        return b"FAILURE\r\nNo pending promotion\r\n\r\n"
    newposition = chesslogic.promote(position, promotesquare, promoteType)
    gamestatus = chesslogic.terminalStatus(newposition, gamedata['WhiteId'], gamedata['BlackId'], None, None, False, gameid, cursor)
    status, substatus = chesslogic.unwrapStatus(gamestatus, turn=='W')
    dblogic.updateCommon(cursor, "Games", {"Position": newposition}, gameid)
    movecountcursor = dblogic.selectCommon(cursor, "Moves", {"Game": gameid, "Player": uid}, "Id, Sequence, SqFrom, SqTo, Piece, Captured", suffix=" ORDER BY Sequence DESC LIMIT 1")
    movedata = dblogic.unwrapCursor(movecountcursor, False, ["Id","Sequence","Initial","Final","Piece","Captured"])
    moveid = movedata["Id"]
    dblogic.insert(cursor, "Promotions", {"Move": moveid,
                                          "Piece": promoteType.__getattribute__('upper' if turn=='W' else 'lower')(),
                                          "PosBefore": position,
                                          "PosAfter": newposition})
    newannotation = chesslogic.annotateMove(position, newposition, movedata['Initial'], movedata['Final'], movedata['Piece'], movedata['Captured'], promoteType)
    dblogic.updateCommon(cursor, "Moves", {"Annotated":newannotation}, moveid)
    oppname = gamedata['BlackName'] if turn == 'W' else gamedata['WhiteName']
    serverlogic.notifyuser(oppname, bytewrap("NOTIFY\r\nENEMYPROMOTE\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gameid, newannotation, movedata["Sequence"], newposition, status, substatus)))
    return bytewrap("SUCCESS\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gameid, newannotation, movedata["Sequence"], newposition, status, substatus))
Example #3
0
def respond(cursor, params, connhandler):
    challengeid = params[0]
    responsetype = params[1]
    if len(params) >= 4:
        sessionid = params[3]
        colorselection = params[2]
    else:
        sessionid = params[2]
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    rescursor = dblogic.selectCommon(cursor, "Challenges INNER JOIN ColorSelections ON Challenges.ColorSelection=ColorSelections.Id INNER JOIN (SELECT Id, Name FROM Users) AS ChallengerUser ON Challenges.Challenger=ChallengerUser.Id INNER JOIN (SELECT Id, Name FROM Users) AS ChallengeeUser ON Challenges.Challengee=ChallengeeUser.Id", {"Challenges.Id":challengeid}, "Challenger, Challengee, ColorSelections.Name, ChallengerUser.Name, ChallengeeUser.Name")
    challengedata = dblogic.unwrapCursor(rescursor, False)
    if responsetype == "ACCEPT":
        if uname != challengedata[4]:
           return bytewrap("Failure\r\nNot your challenge to accept.\r\n\r\n")
        if challengedata[2] == "White":
            blackindex = 1
        elif challengedata[2] == "Black":
            blackindex = 0
        elif challengedata[2] == "Random":
            blackindex = random.randrange(2)
        elif challengedata[2] == "Opponent":
            if colorselection == "WHITE":
                blackindex = 0
            elif colorselection == "BLACK":
                blackindex = 1
            elif colorselection == "RANDOM":
                blackindex = random.randrange(2)
                
        whiteid, blackid = challengedata[1-blackindex], challengedata[blackindex]
        whitename, blackname = (challengedata[challengedata.index(i)+3] for i in (whiteid, blackid))
        cursor.execute("DELETE FROM Challenges WHERE Id=?", (challengeid,))
        cursor.connection.commit()
        rescursor = dblogic.selectCommon(cursor, "GameSubstatuses", {"Description": "In Progress"}, "Id, Superstatus")
        substatus = dblogic.unwrapCursor(rescursor, False)
        gamecursor = dblogic.insert(cursor, "Games", {"White": whiteid, "Black": blackid, "Status": substatus[1], "Substatus": substatus[0], "Position": STARTPOSITION})
        serverlogic.notifyuser(challengedata[3], bytewrap("NOTIFY\r\nACCEPTCHALLENGE\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(challengeid, gamecursor.lastrowid, whitename, blackname)))
        return bytewrap("SUCCESS\r\nACCEPT\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(challengeid, gamecursor.lastrowid, whitename, blackname))
    elif responsetype == "REJECT":
        if uname != challengedata[4]:
           return bytewrap("Failure\r\nNot your challenge to reject.\r\n\r\n")
        cursor.execute("DELETE FROM Challenges WHERE Id=?", (challengeid,))
        cursor.connection.commit()
        serverlogic.notifyuser(challengedata[3], bytewrap("NOTIFY\r\nREJECTCHALLENGE\r\n%s\r\n\r\n"%(challengeid)))
        return bytewrap("SUCCESS\r\nREJECT\r\n%s\r\n\r\n"%challengeid)
    elif responsetype == "RESCIND":
        if uname != challengedata[3]:
           return bytewrap("Failure\r\nNot your challenge to rescind.\r\n\r\n")
        cursor.execute("DELETE FROM Challenges WHERE Id=?", (challengeid,))
        cursor.connection.commit()
        serverlogic.notifyuser(challengedata[4], bytewrap("NOTIFY\r\nRESCINDCHALLENGE\r\n%s\r\n\r\n"%(challengeid)))
        return bytewrap("SUCCESS\r\nRESCIND\r\n%s\r\n\r\n"%challengeid)
Example #4
0
def checkDrawClaim(cursor, gameid, is3x, newposition=None):
    print("Is3x: %s"%is3x)
    movecursor = dblogic.selectCommon(cursor, "Moves", {"Moves.Game": gameid}, "PosAfter, SqFrom, SqTo, Piece, Captured", " ORDER BY Moves.Id DESC")
    positions = dblogic.unwrapCursor(movecursor, True, ["Position","From","To","Mover","Captured"])
    if len(positions)==0:
        return False
    if newposition==None:
        newposition = positions[0]
    else:
        positions.insert(0, newposition)
    if is3x:
        reps = 0
        for i in positions:
            print(i["Position"])
            if i["Position"] == newposition["Position"]:
                print("Increment")
                reps += 1
            if reps >= 3:
                return True
        if reps == 2 and newposition["Position"] == "RNBQKBNRPPPPPPPP--------------------------------pppppppprnbqkbnr++++-W":
            return True
    else:
        moves = 0
        for i in reversed(positions):
            mover = i["Mover"]
            captured = i["Captured"]
            if isEnemy(mover, captured):
                moves = 0
            isSwap = isAlly(mover, captured)
            isPawn = (mover.lower()=='p')
            isPawnSwap = isSwap and captured.lower()=='p'
            hasPawn = False
            if isPawn:
                hasPawn = True
                xi,yi = squareNameToXY(i["From"])
                xf,yf = squareNameToXY(i["To"])
            elif isPawnSwap:
                hasPawn = True
                xi,yi = squareNameToXY(i["To"]) #inverted because the pawn's motion is opposite the real motion
                xf,yf = squareNameToXY(i["From"])
            if hasPawn:
                if yf in [1,8]:
                    moves = 0
                else:
                    moves -= 10*(yf-yi)
                    if yf<yi:
                        moves += 1
            else:
                moves += 1
            moves = constrain(moves, 0, 100)
        if moves >= 100:
            return True
    return False
Example #5
0
def newchallenge(cursor, params, connhandler):
    uname = serverlogic.getunamefromsession(params[2], connhandler, True)
    oppname = params[0]
    if (uname == oppname):
        return b'FAILURE\r\nCannot challenge yourself\r\n\r\n'
    colorselection = params[1].title()
    oppcursor = dblogic.selectCommon(cursor, "Users", {"Name":oppname})
    oppdata = oppcursor.fetchall()
    if len(oppdata) == 0:
        return bytewrap("FAILURE\r\nNo such user %s"%oppname)
    oppid = oppdata[0][0]
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname})
    userdata = usercursor.fetchall()
    uid = userdata[0][0]
    colorcursor = dblogic.selectCommon(cursor, "ColorSelections", {"Name":colorselection})
    colordata = colorcursor.fetchall()
    colorid = colordata[0][0]
    challengecursor = dblogic.insert(cursor, "Challenges", {"Challenger":uid, "Challengee":oppid, "ColorSelection":colorid})
    challengeid = challengecursor.lastrowid
    serverlogic.notifyuser(oppname, bytewrap("NOTIFY\r\nNEWCHALLENGE\r\n%s\r\n%s\r\n%s\r\n\r\n"%(uname, challengeid, colorselection)))
    return bytewrap("SUCCESS\r\n%s\r\n\r\n"%challengeid)
Example #6
0
def showmovehistory(cursor, params, connhandler):
    gameid, sessionid = params
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {}, "Id, White, Black")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ['Id', 'White', 'Black'])
    blackid = gamedata['Black']
    if len(gamedata) == 0:
        return b"FAILURE\r\nNo such game or you are not part of it\r\n\r\n"
    movescursor = dblogic.selectCommon(cursor, "Moves LEFT OUTER JOIN Promotions ON Promotions.Move=Moves.Id", {"Moves.Game": gameid}, 'Moves.Id, Moves.SqFrom, Moves.SqTo, Moves.Captured, Moves.Piece, Moves.Sequence, Moves.PosBefore, Moves.PosAfter, Promotions.Piece, Moves.Player=%s AS Color, Moves.Annotated'%blackid, " ORDER BY Moves.Sequence, Color")
    movesdata = dblogic.unwrapCursor(movescursor, True, ['Id', 'From','To','Captured','Piece','Sequence','PosBefore','PosAfter','PromotedTo','Color','Annotation'])
    for i in movesdata:
        if not i['Annotation']:
            i['Annotation'] = chesslogic.annotateMove(i['PosBefore'],i['PosAfter'],i['From'],i['To'],i['Piece'],i['Captured'],i['PromotedTo'])
            dblogic.updateCommon(cursor, "Moves", {"Annotated": i["Annotation"]}, i["Id"])
    movestring = ' '.join([i['Annotation'] for i in movesdata])
    if movestring=='':
        return bytewrap("SUCCESS\r\n%s\r\n\r\n"%(gameid))
    return bytewrap("SUCCESS\r\n%s\r\n%s\r\n\r\n"%(gameid, movestring))
Example #7
0
def retrievedata(includemetadata, conn=None):
    if conn == None:
        conn = connect()
    tables = list(datastrings) + (list(metadatastrings)
                                  if includemetadata else [])
    data = {}
    cursor = conn.cursor()
    for i in tables:
        cols = dblogic.getColsFromTable(cursor, i)
        rowscursor = dblogic.selectCommon(cursor, i, {})
        alldata = dblogic.unwrapCursor(rowscursor, True, cols)
        data[i] = alldata
    return data
Example #8
0
def getgamestate(cursor, params, connhandler):
    gameid, sessionid = params
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {"(SELECT Id, Name FROM Users) AS BlackUser":"******", "(SELECT Id, Name FROM Users) AS WhiteUser":"******"}, "Position, White, Black, WhiteUser.Name, BlackUser.Name, OfferRecipient, LiveClaim")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ["Position", "WhiteId", "BlackId", "WhiteName", "BlackName", "OfferRecipient", "LiveClaim"])
    if (gamedata == None): #invalid game id for user
        return b"FAILURE\r\nCouldn't find game with specified Id\r\n\r\n"
    else:
        recipient = gamedata["OfferRecipient"]
        return bytewrap("SUCCESS\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gamedata["Position"],'W' if uid==gamedata["WhiteId"] else 'B', gamedata["WhiteName"], gamedata["BlackName"], "NONE" if recipient==None else ("IN" if recipient==uid else "OUT"), int(bool(gamedata["LiveClaim"]))))
Example #9
0
def showchallenges(cursor, params, connhandler):
    if len(params) < 2:
        return (b'FAILURE\r\nInvalid command\r\n\r\n')
    jointemplate = '''Challenges INNER JOIN Users AS CurUser ON CurUser.Id=Challenges.%s
                       INNER JOIN Users AS OppUser ON Challenges.%s=OppUser.Id
                       INNER JOIN ColorSelections ON ColorSelections.Id=Challenges.ColorSelection'''
    curfield, oppfield = "Challengee", "Challenger"
    if params[0] == 'OUT':
        curfield, oppfield = oppfield, curfield
    elif params[0] != "IN":
        return (b'FAILURE\r\nInvalid command\r\n\r\n')
    jointable = jointemplate%(curfield, oppfield)
    uname = serverlogic.getunamefromsession(params[1], connhandler, True)
    print(uname)
    rescursor = dblogic.selectCommon(cursor, jointable, {"CurUser.Name":uname}, "Challenges.Id, OppUser.Name, ColorSelections.Name")
    data = rescursor.fetchall()
    if len(data) == 0:
        return bytewrap("%s\r\n\r\n"%params[0])
    else:
        formatted = "\r\n".join([" ".join([str(j) for j in i]) for i in data])
        return bytewrap("%s\r\n%s\r\n\r\n"%(params[0],formatted))
Example #10
0
def drawgame(cursor, params, connhandler):
    gameid, sessionid, drawtype = params[:3]
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {"(SELECT Id, Name FROM Users) AS BlackUser":"******", "(SELECT Id, Name FROM Users) AS WhiteUser":"******", "GameStatuses":"GameStatuses.Id=Games.Status"}, "Games.Id, Position, White, Black, WhiteUser.Name, BlackUser.Name, GameStatuses.Description, Games.OfferRecipient, Games.LiveClaim, WhiteClaimFaults, BlackClaimFaults")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ['Id', 'Position', 'White', 'Black', 'WhiteName', 'BlackName', 'PrevStatus', 'Recipient', 'LiveClaim', 'WhiteClaimFaults', 'BlackClaimFaults'])
    if gamedata["PrevStatus"] != "In Progress":
        return b"FAILURE\r\nGame is over\r\n\r\n"
    blackid = gamedata['Black']
    if len(gamedata) == 0:
        return b"FAILURE\r\nNo such game or you are not part of it\r\n\r\n"
    position = gamedata['Position']
    drawsubstatus = None
    #first, check if recipient of offer/claim has more than lone king- if not, draw by autoaccept
    isblackplayer = blackid==uid
    oppname = gamedata['WhiteName'] if isblackplayer else gamedata['BlackName']
    oppid = gamedata['White'] if isblackplayer else gamedata['Black']
    isRecipientNonKing = (lambda x: (x!='K' and x.isupper())) if isblackplayer else (lambda x: (x!='k' and x.islower()))
    receipientPieceGen = (i for i in position[:64] if isRecipientNonKing(i))
    try:
        next(receipientPieceGen)
    except StopIteration:
        drawsubstatus = "Autoaccept"
        response = "COMPLETEDDRAW\r\nAutoaccept"
    #check if live draw offer from opponent exists- if yes, draw by agreement
    updatedata = {}
    lossbypenalty = False
    if drawsubstatus == None:
        if gamedata['Recipient'] == uid:
            drawsubstatus = "Agreement"
            response = "COMPLETEDDRAW\r\nAgreement"
        elif drawtype == "CLAIM":
            if gamedata['LiveClaim'] == 1:
                return b"FAILURE\r\nCan only claim a draw once per turn.\r\n\r\n"
            claimtype = params[3]
            claimtime = params[4]
            is3x = claimtype=="THREEFOLD"
            if isblackplayer != (position[-1] == 'B'):
                return b"FAILURE\r\nCan only claim a draw during your turn\r\n\r\n"
            if claimtime=="NOW":
                success = chesslogic.checkDrawClaim(cursor, gameid, is3x)
                if success:
                    drawsubstatus = "3 Fold Rep" if is3x else "50 Move"
                    response = "COMPLETEDDRAW\r\n%s"%drawsubstatus
                else:
                    updatedata['LiveClaim'] = 1
                    updatedata['ClaimIsDeferred'] = 0
                    updatedata['OfferRecipient'] = oppid
                    faultindex = "BlackClaimFaults" if isblackplayer else "WhiteClaimFaults"
                    updatedata[faultindex] = nullwrap(gamedata[faultindex],0)+1
                    if updatedata[faultindex] >= 3:
                        lossbypenalty = True
                        response = "PENALTYLOSS"
                    else:
                        response = "CLAIM\r\nFAULT\r\n%s"%updatedata[faultindex]
            else:
                updatedata['LiveClaim'] = 1
                updatedata['ClaimIsDeferred'] = 1
                updatedata['ClaimIs3x'] = (1 if is3x else 0)
                updatedata['OfferRecipient'] = oppid
                response = "CLAIM\r\nDEFERRED"
        elif drawtype == "OFFER":
            if gamedata['Recipient'] == oppid:
                return b"FAILURE\r\nDraw offer already live\r\n\r\n"
            response = "OFFER"
            updatedata['OfferRecipient'] = oppid
        else:
            return b"FAILURE\r\nInvalid draw parameter\r\n\r\n"
    statuscursor = None
    if drawsubstatus != None:
        textstatus = "Draw"
        statuscursor = dblogic.selectCommon(cursor, "GameStatuses INNER JOIN GameSubstatuses ON GameStatuses.Id=GameSubstatuses.Superstatus", {"GameSubstatuses.Description": drawsubstatus}, "GameStatuses.Id, GameSubstatuses.Id")
    elif lossbypenalty:
        textstatus = "White win" if isblackplayer else "Black win"
        statuscursor = dblogic.selectCommon(cursor, "GameStatuses INNER JOIN GameSubstatuses ON GameStatuses.Id=GameSubstatuses.Superstatus", {"GameSubstatuses.Description": "Penalty", "GameStatuses.Description": textstatus}, "GameStatuses.Id, GameSubstatuses.Id")
        drawsubstatus = "Penalty"
    if statuscursor != None:
        statusdata = dblogic.unwrapCursor(statuscursor, False, ["StatusId","SubstatusId"])
        updatedata["Status"] = statusdata["StatusId"]
        updatedata["Substatus"] = statusdata["SubstatusId"]
    if "Status" in updatedata:
        oppnotification = "STATUSCHANGE\r\n%s\r\n%s\r\n%s"%(gameid, textstatus, drawsubstatus)
    else:
        oppnotification = "DRAWOFFER"
    serverlogic.notifyuser(oppname, bytewrap("NOTIFY\r\n%s\r\n\r\n"%oppnotification))
    print(updatedata)
    dblogic.updateCommon(cursor, "Games", updatedata, gameid)
    return bytewrap("SUCCESS\r\n%s\r\n\r\n"%response)
Example #11
0
def move(cursor, params, connhandler):
    gameid, initial, final, sessionid = params
    uname = serverlogic.getunamefromsession(sessionid, connhandler, True)
    usercursor = dblogic.selectCommon(cursor, "Users", {"Name":uname}, "Id")
    userdata = dblogic.unwrapCursor(usercursor, False, ["Id"])
    uid = userdata['Id']
    gamecursor = dblogic.selectGameWithPlayer(cursor, uid, {"Games.Id":gameid}, {"(SELECT Id, Name FROM Users) AS BlackUser":"******", "(SELECT Id, Name FROM Users) AS WhiteUser":"******", "GameStatuses":"GameStatuses.Id=Games.Status"}, "Position, White, Black, WhiteUser.Name, BlackUser.Name, LiveClaim, ClaimIsDeferred, ClaimIs3x, OfferRecipient, GameStatuses.Description, WhiteClaimFaults, BlackClaimFaults")
    gamedata = dblogic.unwrapCursor(gamecursor, False, ["Position", "WhiteId", "BlackId", "WhiteName", "BlackName", "LiveClaim", "ClaimIsDeferred", "ClaimIs3x", "OfferRecipient", "GameStatus", "WhiteClaimFaults", "BlackClaimFaults"])
    if gamedata["GameStatus"] != "In Progress":
        return b"FAILURE\r\nGame is over.\r\n\r\n"
    position = gamedata['Position']
    if chesslogic.promoteSquare(position) != None:
        return b"FAILURE\r\nPawn must be promoted before any further moves\r\n\r\n"
    turn = position[69]
    if (turn == 'W') != (gamedata['WhiteId'] == uid):
        return b"FAILURE\r\nOut of turn play\r\n\r\n"
    if chesslogic.isValidMove(position, initial, final):
        whiteid = gamedata["WhiteId"]
        blackid = gamedata["BlackId"]
        liveclaim = (gamedata["LiveClaim"]==1) and (gamedata["ClaimIsDeferred"]==1)
        is3x = bool(gamedata["ClaimIs3x"])
        offerrecipientid = gamedata["OfferRecipient"]
        isblackplayer = (uid == blackid)

        newposition, captured, isEnPassant, mover = chesslogic.move(position, initial, final)
        gamestatus = chesslogic.terminalStatus(newposition, gamedata['WhiteId'], gamedata['BlackId'])
        fault = False
        if gamestatus == chesslogic.NORMAL:
            gamestatus = chesslogic.checkAutoAccept(position, offerrecipientid, whiteid, blackid)
        if gamestatus == chesslogic.NORMAL:
            print("Evaluation: %s %s"%(liveclaim, turn))
            if liveclaim:
                print("Evaluating")
                isdraw = chesslogic.checkDrawClaim(cursor, gameid, is3x, {"Position":newposition,"From":initial,"To":final,"Mover":mover,"Captured":captured})
                print("IsDraw: %s"%isdraw)
                if isdraw:
                    gamestatus = chesslogic.CLAIM3X if is3x else chesslogic.CLAIM50
                else:
                    fault = True
                    faultindex = "BlackClaimFaults" if isblackplayer else "WhiteClaimFaults"
                    faults = nullwrap(gamedata[faultindex],0)+1
                    if faults >= 3:
                        gamestatus = chesslogic.CLAIMFAULTLOSS
                    
        status, substatus = chesslogic.unwrapStatus(gamestatus, turn=='W')
        statuscursor = dblogic.selectCommon(cursor, "GameStatuses INNER JOIN GameSubstatuses ON GameStatuses.Id=GameSubstatuses.Superstatus", {"GameStatuses.Description":status, "GameSubstatuses.Description":substatus}, "GameStatuses.Id, GameSubstatuses.Id")
        statusdata = dblogic.unwrapCursor(statuscursor, False, ["StatusId","SubstatusId"])
        gameupdate = {"Position": newposition, "Status":statusdata["StatusId"], "Substatus":statusdata["SubstatusId"],
                                                "LiveClaim": 0, "ClaimIsDeferred": 0}
        if gamedata["OfferRecipient"] == uid:
            gameupdate["OfferRecipient"] = None
        if fault:
            print("Claim fault")
            print(faultindex)
            print(faults)
            gameupdate[faultindex] = faults
        print(gameupdate)
        dblogic.updateCommon(cursor, "Games", gameupdate, gameid)
        movecountcursor = dblogic.selectCommon(cursor, "Moves", {"Game": gameid, "Player": uid}, "COUNT(Id)")
        sequence = dblogic.unwrapCursor(movecountcursor, False)[0] + 1
        annotation = chesslogic.annotateMove(position, newposition, initial, final, mover, captured)
        dblogic.insert(cursor, "Moves", {"SqFrom": initial, "SqTo": final,
                                        "Captured": captured, "isEnPassant": int(isEnPassant),
                                        "Player": uid, "Piece": mover,
                                        "Game": gameid, "Sequence": sequence,
                                        "PosBefore": position, "PosAfter": newposition,
                                        "Annotated": annotation})
        oppname = gamedata['BlackName'] if turn == 'W' else gamedata['WhiteName']
        serverlogic.notifyuser(oppname, bytewrap("NOTIFY\r\nOPPMOVE\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gameid, annotation, sequence, newposition, status, substatus)))
        return bytewrap("SUCCESS\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n"%(gameid, annotation, sequence, newposition, status, substatus))
    return b"Failure\r\nNot yet implemented\r\n\r\n"