add ranked matchmaking and add elo calculations

This commit is contained in:
2024-10-22 18:43:10 +02:00
parent 648c9e12fa
commit 3cd3f41be7
8 changed files with 82 additions and 11 deletions

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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 #
# #
# **************************************************************************** #

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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:
waitingForPlayer = None
rankedWaitingForPlayer = []
@multimethod
def __init__(self, p1 , p2 , tournamentCode):
@ -43,12 +44,28 @@ class Game:
p1.setGame(self)
p2.setGame(self)
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
def __init__(self, socket, withBot : bool, skinId : int, goalId :int , ranked = False, opponent = None):
self.initAttributes()
if(ranked):
self.rankedInnit()
self.rankedInit(socket, skinId, goalId)
return;
self.withBot = withBot
@ -80,14 +97,17 @@ class Game:
def initAttributes(self):
self.p1 = None
self.p2 = None
self.ranked = False
self.tournamentCode = None
self.started = False
self.end = False
self.left = None
self.winner = None
self.pWinner = None
self.withBot = False
self.gameStart = 0
self.gameTime = 0
self.opponentLock = None
self.ball = Ball()
self.speed = GameSettings.startSpeed
@ -280,8 +300,49 @@ class Game:
self.p2.setGame(None)
if(not self.withBot):
await self.saveResults()
if(self.ranked):
await self.updateElo()
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
def saveResults(self):
try:

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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
OOBTolerance = 0.01
maxEloDiff = 100
ratingAdjustmentHigh = 30
ratingAdjustmentLow = 10
experiencedThreshold = 500

View File

@ -13,6 +13,7 @@ class User(models.Model):
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)
last_login = models.DateTimeField()
elo = models.DecimalField(max_digits=15, decimal_places=0, default=150)
class Message(models.Model):
id = models.AutoField(primary_key=True)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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):
socket.sendError("Goal id out of range", 9039)
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)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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()):
return({"found":False})
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):
try:
@ -34,7 +34,7 @@ async def loginByPass(socket, content):
if(not u_info["mail_verified"]):
socket.sendError("Account not verified, please verify your account before logging in",9025)
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()
socket.sync_send(json.dumps({"type":"logged_in", "content":{
"status":True,

View File

@ -123,6 +123,7 @@ def login42(request):
request.session["username"] = db_user[0].username
request.session["id"] = db_user[0].id
request.session["pfp"] = db_user[0].pfp
request.session["elo"] = db_user[0].elo
request.session.save()
return redirect("/")

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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)
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)):
print("already logged in")
return(0)
@ -96,9 +96,11 @@ class WebsocketHandler(AsyncWebsocketConsumer):
await self.session_set("id",uid)
await self.session_set("username",username)
await self.session_set("pfp", pfp)
await self.session_set("elo", elo)
await self.session_save()
self.logged_in = True
self.id = uid
self.elo = elo
self.username = username
self.pfp = pfp
return(1)
@ -120,6 +122,7 @@ class WebsocketHandler(AsyncWebsocketConsumer):
self.id = await self.session_get("id",0)
self.username = await self.session_get("username", None)
self.pfp = await self.session_get("pfp",None)
self.elo = await self.session_get("elo", 0)
self.logged_in = True
await self.send(text_data=json.dumps({"type":"logged_in", "content":{
"status":await self.session_get("logged_in",False),