add ranked matchmaking and add elo calculations
This commit is contained in:
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/10/08 07:33:29 by tomoron #+# #+# #
|
# Created: 2024/10/08 07:33:29 by tomoron #+# #+# #
|
||||||
# Updated: 2024/10/22 01:19:10 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 17:08:58 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/09/13 16:20:58 by tomoron #+# #+# #
|
# Created: 2024/09/13 16:20:58 by tomoron #+# #+# #
|
||||||
# Updated: 2024/10/22 16:28:36 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 18:40:03 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ from multimethod import multimethod
|
|||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
waitingForPlayer = None
|
waitingForPlayer = None
|
||||||
|
rankedWaitingForPlayer = []
|
||||||
|
|
||||||
@multimethod
|
@multimethod
|
||||||
def __init__(self, p1 , p2 , tournamentCode):
|
def __init__(self, p1 , p2 , tournamentCode):
|
||||||
@ -43,12 +44,28 @@ class Game:
|
|||||||
p1.setGame(self)
|
p1.setGame(self)
|
||||||
p2.setGame(self)
|
p2.setGame(self)
|
||||||
print("game created with ", p1.socket.username, "vs", p2.socket.username)
|
print("game created with ", p1.socket.username, "vs", p2.socket.username)
|
||||||
|
|
||||||
|
def lookForRankedGame(self, socket):
|
||||||
|
for x in Game.rankedWaitingForPlayer:
|
||||||
|
if(abs(x.p1.socket.elo - socket.elo) < GameSettings.maxEloDiff):
|
||||||
|
return(x)
|
||||||
|
return(None)
|
||||||
|
|
||||||
|
|
||||||
|
def rankedInit(self, socket, skinId, goalId):
|
||||||
|
existingGame = self.lookForRankedGame(socket)
|
||||||
|
self.ranked = True
|
||||||
|
if(existingGame != None):
|
||||||
|
existingGame.join(socket, skinId, goalId)
|
||||||
|
else:
|
||||||
|
self.join(socket, skinId, goalId)
|
||||||
|
Game.rankedWaitingForPlayer.append(self)
|
||||||
|
|
||||||
@multimethod
|
@multimethod
|
||||||
def __init__(self, socket, withBot : bool, skinId : int, goalId :int , ranked = False, opponent = None):
|
def __init__(self, socket, withBot : bool, skinId : int, goalId :int , ranked = False, opponent = None):
|
||||||
self.initAttributes()
|
self.initAttributes()
|
||||||
if(ranked):
|
if(ranked):
|
||||||
self.rankedInnit()
|
self.rankedInit(socket, skinId, goalId)
|
||||||
return;
|
return;
|
||||||
self.withBot = withBot
|
self.withBot = withBot
|
||||||
|
|
||||||
@ -80,14 +97,17 @@ class Game:
|
|||||||
def initAttributes(self):
|
def initAttributes(self):
|
||||||
self.p1 = None
|
self.p1 = None
|
||||||
self.p2 = None
|
self.p2 = None
|
||||||
|
self.ranked = False
|
||||||
self.tournamentCode = None
|
self.tournamentCode = None
|
||||||
self.started = False
|
self.started = False
|
||||||
self.end = False
|
self.end = False
|
||||||
self.left = None
|
self.left = None
|
||||||
self.winner = None
|
self.winner = None
|
||||||
self.pWinner = None
|
self.pWinner = None
|
||||||
|
self.withBot = False
|
||||||
self.gameStart = 0
|
self.gameStart = 0
|
||||||
self.gameTime = 0
|
self.gameTime = 0
|
||||||
|
self.opponentLock = None
|
||||||
|
|
||||||
self.ball = Ball()
|
self.ball = Ball()
|
||||||
self.speed = GameSettings.startSpeed
|
self.speed = GameSettings.startSpeed
|
||||||
@ -280,8 +300,49 @@ class Game:
|
|||||||
self.p2.setGame(None)
|
self.p2.setGame(None)
|
||||||
if(not self.withBot):
|
if(not self.withBot):
|
||||||
await self.saveResults()
|
await self.saveResults()
|
||||||
|
if(self.ranked):
|
||||||
|
await self.updateElo()
|
||||||
del self
|
del self
|
||||||
|
|
||||||
|
|
||||||
|
def calcElo(self, playerElo, opponentElo, playerScore):
|
||||||
|
expectedScore = 1 / 1 + (10**((opponentElo - playerElo) / 400))
|
||||||
|
k = GameSettings.ratingAdjustmentHigh if playerElo < GameSettings.experiencedThreshold else GameSettings.ratingAdjustmentLow
|
||||||
|
playerElo = playerElo + k * ((playerScore / GameSettings.maxScore) - expectedScore)
|
||||||
|
return(playerElo)
|
||||||
|
|
||||||
|
@sync_to_async
|
||||||
|
def updateElo(self):
|
||||||
|
try:
|
||||||
|
if(self.winner == None):
|
||||||
|
print("unkown winner, setting to 1")
|
||||||
|
self.winner = 1
|
||||||
|
if(self.left != None):
|
||||||
|
self.score[self.left - 1] = 0
|
||||||
|
self.score[1 if self.left == 2 else 2] = 5
|
||||||
|
|
||||||
|
p1Elo = self.calcElo(self.p1.socket.elo, self.p2.socket.elo, self.score[0])
|
||||||
|
p2Elo = self.calcElo(self.p2.socket.elo, self.p1.socket.elo, self.score[1])
|
||||||
|
|
||||||
|
p1DbUser = User.objects.get(id=self.p1.socket.id)
|
||||||
|
p1DbUser.elo = p1Elo
|
||||||
|
p1DbUser.save()
|
||||||
|
self.p1.socket.elo = p1Elo
|
||||||
|
self.p1.socket.scope["session"].elo = p1Elo
|
||||||
|
self.p1.socket.scope["session"].save()
|
||||||
|
|
||||||
|
p2DbUser = User.objects.get(id=self.p2.socket.id)
|
||||||
|
p2DbUser.elo = p2Elo
|
||||||
|
p2DbUser.save()
|
||||||
|
self.p2.socket.elo = p2Elo
|
||||||
|
self.p2.socket.scope["session"].elo = p2Elo
|
||||||
|
self.p2.socket.scope["session"].save()
|
||||||
|
except Exception as e:
|
||||||
|
self.p1.socket.sendError("Couldn't update elo", 9104, e)
|
||||||
|
self.p2.socket.sendError("Couldn't update elo", 9104, e)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@sync_to_async
|
@sync_to_async
|
||||||
def saveResults(self):
|
def saveResults(self):
|
||||||
try:
|
try:
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/10/06 16:33:56 by tomoron #+# #+# #
|
# Created: 2024/10/06 16:33:56 by tomoron #+# #+# #
|
||||||
# Updated: 2024/10/22 16:33:39 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 18:40:34 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
@ -52,3 +52,8 @@ class GameSettings:
|
|||||||
maxTimePlayerWait = 10
|
maxTimePlayerWait = 10
|
||||||
|
|
||||||
OOBTolerance = 0.01
|
OOBTolerance = 0.01
|
||||||
|
|
||||||
|
maxEloDiff = 100
|
||||||
|
ratingAdjustmentHigh = 30
|
||||||
|
ratingAdjustmentLow = 10
|
||||||
|
experiencedThreshold = 500
|
||||||
|
@ -13,6 +13,7 @@ class User(models.Model):
|
|||||||
github_link = models.CharField(max_length=1024, null=True, blank=True, default=None)
|
github_link = models.CharField(max_length=1024, null=True, blank=True, default=None)
|
||||||
discord_username = models.CharField(max_length=1024, null=True, blank=True, default=None)
|
discord_username = models.CharField(max_length=1024, null=True, blank=True, default=None)
|
||||||
last_login = models.DateTimeField()
|
last_login = models.DateTimeField()
|
||||||
|
elo = models.DecimalField(max_digits=15, decimal_places=0, default=150)
|
||||||
|
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
id = models.AutoField(primary_key=True)
|
id = models.AutoField(primary_key=True)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/09/11 17:07:08 by tomoron #+# #+# #
|
# Created: 2024/09/11 17:07:08 by tomoron #+# #+# #
|
||||||
# Updated: 2024/10/22 16:02:51 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 17:33:31 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
@ -29,5 +29,5 @@ async def start(socket, content):
|
|||||||
if(goalId < 0 or goalId >= GameSettings.nbGoals):
|
if(goalId < 0 or goalId >= GameSettings.nbGoals):
|
||||||
socket.sendError("Goal id out of range", 9039)
|
socket.sendError("Goal id out of range", 9039)
|
||||||
return;
|
return;
|
||||||
Game(socket, content.get("with_bot", False), skinId, goalId, False, opponent)
|
Game(socket, content.get("with_bot", False), skinId, goalId, content.get("isRanked",False), opponent)
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
|
# Created: 2024/08/03 08:10:38 by edbernar #+# #+# #
|
||||||
# Updated: 2024/10/04 23:35:03 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 17:40:28 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ def userExists(mail, password):
|
|||||||
if(not user.exists()):
|
if(not user.exists()):
|
||||||
return({"found":False})
|
return({"found":False})
|
||||||
else:
|
else:
|
||||||
return({"found":True, "id":user[0].id, "username":user[0].username, "mail_verified":user[0].mail_verified, "pfp":user[0].pfp})
|
return({"found":True, "id":user[0].id, "username":user[0].username, "mail_verified":user[0].mail_verified, "pfp":user[0].pfp, "elo" : int(user[0].elo)})
|
||||||
|
|
||||||
async def loginByPass(socket, content):
|
async def loginByPass(socket, content):
|
||||||
try:
|
try:
|
||||||
@ -34,7 +34,7 @@ async def loginByPass(socket, content):
|
|||||||
if(not u_info["mail_verified"]):
|
if(not u_info["mail_verified"]):
|
||||||
socket.sendError("Account not verified, please verify your account before logging in",9025)
|
socket.sendError("Account not verified, please verify your account before logging in",9025)
|
||||||
return
|
return
|
||||||
if(await socket.login(u_info["id"], u_info["username"], u_info["pfp"])):
|
if(await socket.login(u_info["id"], u_info["username"], u_info["pfp"], u_info["elo"])):
|
||||||
await socket.setLastLogin()
|
await socket.setLastLogin()
|
||||||
socket.sync_send(json.dumps({"type":"logged_in", "content":{
|
socket.sync_send(json.dumps({"type":"logged_in", "content":{
|
||||||
"status":True,
|
"status":True,
|
||||||
|
@ -123,6 +123,7 @@ def login42(request):
|
|||||||
request.session["username"] = db_user[0].username
|
request.session["username"] = db_user[0].username
|
||||||
request.session["id"] = db_user[0].id
|
request.session["id"] = db_user[0].id
|
||||||
request.session["pfp"] = db_user[0].pfp
|
request.session["pfp"] = db_user[0].pfp
|
||||||
|
request.session["elo"] = db_user[0].elo
|
||||||
request.session.save()
|
request.session.save()
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
|
||||||
# +#+#+#+#+#+ +#+ #
|
# +#+#+#+#+#+ +#+ #
|
||||||
# Created: 2024/09/09 14:31:30 by tomoron #+# #+# #
|
# Created: 2024/09/09 14:31:30 by tomoron #+# #+# #
|
||||||
# Updated: 2024/10/14 20:33:31 by tomoron ### ########.fr #
|
# Updated: 2024/10/22 17:12:14 by tomoron ### ########.fr #
|
||||||
# #
|
# #
|
||||||
# **************************************************************************** #
|
# **************************************************************************** #
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class WebsocketHandler(AsyncWebsocketConsumer):
|
|||||||
print("\033[32monline : ", self.onlinePlayers)
|
print("\033[32monline : ", self.onlinePlayers)
|
||||||
return(0)
|
return(0)
|
||||||
|
|
||||||
async def login(self, uid: int, username: str, pfp : str) -> int:
|
async def login(self, uid: int, username: str, pfp : str, elo : int) -> int:
|
||||||
if(await self.session_get("logged_in", False)):
|
if(await self.session_get("logged_in", False)):
|
||||||
print("already logged in")
|
print("already logged in")
|
||||||
return(0)
|
return(0)
|
||||||
@ -96,9 +96,11 @@ class WebsocketHandler(AsyncWebsocketConsumer):
|
|||||||
await self.session_set("id",uid)
|
await self.session_set("id",uid)
|
||||||
await self.session_set("username",username)
|
await self.session_set("username",username)
|
||||||
await self.session_set("pfp", pfp)
|
await self.session_set("pfp", pfp)
|
||||||
|
await self.session_set("elo", elo)
|
||||||
await self.session_save()
|
await self.session_save()
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
self.id = uid
|
self.id = uid
|
||||||
|
self.elo = elo
|
||||||
self.username = username
|
self.username = username
|
||||||
self.pfp = pfp
|
self.pfp = pfp
|
||||||
return(1)
|
return(1)
|
||||||
@ -120,6 +122,7 @@ class WebsocketHandler(AsyncWebsocketConsumer):
|
|||||||
self.id = await self.session_get("id",0)
|
self.id = await self.session_get("id",0)
|
||||||
self.username = await self.session_get("username", None)
|
self.username = await self.session_get("username", None)
|
||||||
self.pfp = await self.session_get("pfp",None)
|
self.pfp = await self.session_get("pfp",None)
|
||||||
|
self.elo = await self.session_get("elo", 0)
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
await self.send(text_data=json.dumps({"type":"logged_in", "content":{
|
await self.send(text_data=json.dumps({"type":"logged_in", "content":{
|
||||||
"status":await self.session_get("logged_in",False),
|
"status":await self.session_get("logged_in",False),
|
||||||
|
Reference in New Issue
Block a user