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))
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))
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)
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)
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)
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"