add Tournament creation and tournament game start

This commit is contained in:
2024-10-13 22:03:06 +02:00
parent d6fdd6fbc7
commit 8f993caefb
10 changed files with 205 additions and 71 deletions

View File

@ -6,7 +6,7 @@
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/05 03:54:20 by tomoron #+# #+# #
# Updated: 2024/10/10 19:25:56 by tomoron ### ########.fr #
# Updated: 2024/10/13 21:24:19 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -19,9 +19,10 @@ import asyncio
import time
class Bot(Player):
def __init__(self, game):
def __init__(self, game=None, tournament=None):
self.socket = DummySocket(game)
self.game = game
self.tournament = tournament
self.ready = True
self.pos = {"pos":0, "up": False}
self.lastCalculated = {"pos":0, "up":False}
@ -46,7 +47,7 @@ class Bot(Player):
return(self.objective)
self.lastCalculated = {"pos":pos, "up" : up}
if(not center):
offset = random.randint(-100, 100) / 100
offset = random.randint(-99, 99) / 100
if(offset == 0):
offset = 0.1
pos += offset * (GameSettings.playerLength / 2)
@ -65,24 +66,37 @@ class Bot(Player):
self.objective = self.genRandomBallDirection(0, 0, True)
return
self.objective = self.genRandomBallDirection(tempBall.pos[0], tempBall.up, False)
def isEnd(self):
if(self.tournament != None):
return(self.tournament.end)
else:
return(self.game.end)
async def updateLoop(self):
while not self.game.end:
await self.getExpectedPos()
while not self.isEnd():
if(self.game):
await self.getExpectedPos()
await asyncio.sleep(1)
async def goToObjectiveLoop(self):
lastUpdate = time.time()
while not self.game.end:
while not self.isEnd():
if(self.pos["pos"] != self.objective["pos"] or self.pos["up"] != self.objective["up"]):
self.pos["up"] = self.objective["up"]
maxDistance = GameSettings.maxPlayerSpeed * (time.time() - lastUpdate)
lastUpdate = time.time()
print("maxDistance :", maxDistance)
travel = self.objective["pos"] - self.pos["pos"]
if(travel >= 0):
travel = min(self.objective["pos"] - self.pos["pos"], GameSettings.maxPlayerSpeed)
travel = min(self.objective["pos"] - self.pos["pos"], maxDistance)
else:
travel = max(self.objective["pos"] - self.pos["pos"], -GameSettings.maxPlayerSpeed)
travel = max(self.objective["pos"] - self.pos["pos"], -maxDistance)
print("travel :", travel)
self.game.move(self.socket, self.pos["pos"] + travel, self.pos["up"])
lastUpdate = time.time()
await asyncio.sleep(1 / 20)
def setGame(self, game):
self.game = game
self.socket.game = game

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/09/13 16:20:58 by tomoron #+# #+# #
# Updated: 2024/10/10 19:24:02 by tomoron ### ########.fr #
# Updated: 2024/10/13 21:50:58 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -16,31 +16,36 @@ from .models import GameResults, User
from .GameSettings import GameSettings
from .Bot import Bot
from .Ball import Ball
from typing import Union
import time
import json
import asyncio
import random
import math
from multimethod import multimethod
class Game:
waitingForPlayer = None
def __init__(self, socket, withBot, skinId = 0, goalId = 0, opponent = None):
self.p1 = None
self.p2 = None
self.started = False
self.end = False
self.left = None
self.winner = None
self.gameStart = 0
self.gameTime = 0
self.withBot = withBot
@multimethod
def __init__(self, p1 , p2 , isTournament = False):
self.initAttributes()
if(isinstance(p1, Bot) and isinstance(p2, Bot)):
self.winner=1
self.pWinner=p1
return
elif(isinstance(p2,Bot)):
p2,p1 = p1, p2
self.withBot = isinstance(p1,Bot)
self.isTournament = isTournament
p1.setGame(self)
p2.setGame(self)
print("game created with ", p1.socket.username, "vs", p2.socket.username)
self.ball = Ball()
self.speed = GameSettings.startSpeed
self.score = [0, 0]
self.obstacles = []
self.lastWin = 2
@multimethod
def __init__(self, socket, withBot : bool, skinId = 0, goalId = 0 , opponent = None):
self.initAttributes()
self.withBot = withBot
self.opponentLock = opponent
if(1 or withBot):
@ -67,6 +72,24 @@ class Game:
def __del__(self):
print("game destroy")
def initAttributes(self):
self.p1 = None
self.p2 = None
self.isTournament=False
self.started = False
self.end = False
self.left = None
self.winner = None
self.pWinner = None
self.gameStart = 0
self.gameTime = 0
self.ball = Ball()
self.speed = GameSettings.startSpeed
self.score = [0, 0]
self.obstacles = []
self.lastWin = 2
def obstaclesInvLength(self):
for x in self.obstacles:
x["pos"]["z"] = -x["pos"]["z"]
@ -100,7 +123,8 @@ class Game:
try:
if(self.p1 == None):
print("game created, set as player 1")
self.p1 = Player(socket, self)
self.p1 = Player(socket)
self.p1.setGame(self)
self.p1.skin = skin
self.p1.goal = goal
else:
@ -108,7 +132,8 @@ class Game:
socket.sendError("You are not invited to this game", 9103)
return
print("joined game, set as player 2")
self.p2 = Player(socket, self)
self.p2 = Player(socket)
self.p2.setGame(self)
self.p2.skin = skin
self.p2.goal = goal
if(self.p2 != None and self.p1 != None):
@ -138,14 +163,16 @@ class Game:
self.p1.socket.sync_send({"type":"game","content":{"action":10,"won":winner==1, "opponentLeft":self.left == 2}})
self.p2.socket.sync_send({"type":"game","content":{"action":10,"won":winner==2, "opponentLeft":self.left == 1}})
self.winner = winner
self.pWinner = self.p1 if winner == 1 else self.p2
self.end = True
def leave(self, socket):
socket.game = None
if (socket == self.p1.socket):
self.left = 1
self.p1.setGame(None)
else:
self.left = 2
self.p2.setGame(None)
if(Game.waitingForPlayer == self):
Game.waitingForPlayer = None
if(self.p2 != None):
@ -238,9 +265,9 @@ class Game:
self.sendNewBallInfo()
print("game end")
if(self.p1.socket.game == self):
self.p1.socket.game = None
self.p1.setGame(None)
if(self.p2.socket.game == self):
self.p2.socket.game = None
self.p2.setGame(None)
if(not self.withBot):
await self.saveResults()
del self

View File

@ -6,7 +6,7 @@
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/06 16:33:56 by tomoron #+# #+# #
# Updated: 2024/10/10 03:48:00 by tomoron ### ########.fr #
# Updated: 2024/10/12 23:31:00 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -38,20 +38,11 @@ class GameSettings:
{ "type":1, "name":"J6", "pos":{"x": 1.5, "y": 0.2, "z": -mapLength / 4}, "isUp": False },
{ "type":1, "name":"J7", "pos":{"x": 1.5, "y": 3.2, "z": -mapLength / 4}, "isUp": True }
]
skins = [
{id: 0, 'color': 0xff53aa, 'texture': None},
{id: 1, 'color': 0xaa24ea, 'texture': None},
{id: 2, 'color': 0x2c9c49, 'texture': None},
{id: 3, 'color': 0x101099, 'texture': None},
{id: 4, 'color': None, 'texture': '/static/img/skin/1.jpg'},
{id: 5, 'color': None, 'texture': '/static/img/skin/2.jpg'},
{id: 6, 'color': None, 'texture': '/static/img/skin/3.jpg'},
{id: 7, 'color': None, 'texture': '/static/img/skin/4.jpg'},
]
nbSkins = 8
nbGoals = 4
wallLength = 1
wallWidth = 0.05
bounceSpeedIncrease = 0.2
maxScore = 5
maxPlayerSpeed = 0.4
maxPlayerSpeed = 6

View File

@ -6,14 +6,13 @@
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/05 03:22:32 by tomoron #+# #+# #
# Updated: 2024/10/10 03:52:40 by tomoron ### ########.fr #
# Updated: 2024/10/13 21:24:16 by tomoron ### ########.fr #
# #
# **************************************************************************** #
class Player():
def __init__(self, socket, game):
def __init__(self, socket):
self.socket = socket
socket.game = game
self.ready = False
self.pos = {"pos":0, "up": False}
self.skin = 0
@ -21,3 +20,7 @@ class Player():
def __del__(self):
print("player destroy")
def setGame(self, game):
self.game = game
self.socket.game = game

View File

@ -6,28 +6,29 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 17:17:07 by tomoron #+# #+# #
# Updated: 2024/10/10 06:12:28 by tomoron ### ########.fr #
# Updated: 2024/10/13 21:11:56 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import string
import asyncio
from .Bot import Bot
from .Player import Player
from .utils import genString
from .TournamentGame import TournamentGame
class Tournament:
currentTournamentsLock = False
currentTournaments = {}
playerLimit = 8
def __init__(self, socket):
levels = 3
def __init__(self, socket, nbBot):
self.messages = []
self.players = []
while(Tournament.currentTournamentsLock):
continue;
Tournament.currentTournamentsLock = True
self.nbBot = nbBot
self.end = False
self.genCode()
Tournament.currentTournaments[self.code] = self
Tournament.currentTournamentsLock = False
self.join(socket)
def genCode(self):
@ -43,12 +44,12 @@ class Tournament:
def broadcast(self, content):
for x in self.players:
x.sync_send("tournament",content)
x.socket.sync_send("tournament",content)
def sendAllInfo(self, socket):
players = []
for x in self.players:
players.append({"id":x.id,"username":x.username, "pfp":x.pfp})
players.append({"id":x.socket.id,"username":x.socket.username, "pfp":x.socket.pfp})
socket.sync_send("tournament",{"action":5, "players":players, "messages" : self.messages})
def sendMessage(self, socket, message):
@ -57,22 +58,56 @@ class Tournament:
self.messages.pop(0)
self.broadcast({"action":3, "username":socket.username, "message":message})
def playerFromSocket(self, socket):
for x in range(len(self.players)):
if(self.players[x].socket == socket):
return(x)
return(-1)
def leave(self, socket):
if(socket not in self.players):
index = self.playerFromSocket(socket)
if(index == -1):
return;
index = self.players.index(socket)
self.players.pop(index)
socket.tournament = None
self.broadcast({"action":2,"id":socket.id})
def join(self, socket):
if(socket.tournament != None):
def join(self, socket, isBot=False):
if(not isBot and socket.tournament != None):
socket.sendError("already in a tournament", 9036)
return
if(len(self.players) == Tournament.playerLimit):
if(not isBot and len(self.players) == Tournament.playerLimit):
socket.sync_send("tournament",{"action":0, "isFull":True})
return
if(isBot):
player = Bot(None, self)
socket = player.socket
else:
player = Player(socket)
socket.tournament = self
self.players.append(socket)
socket.sync_send("tournament",{"action":0,"isFull":False, "isStarted":False,"exist":True, "code":self.code})
self.players.append(player)
socket.sync_send("tournament",{"action":0, "code":self.code})
self.broadcast({"action":1, "id":socket.id, "username": socket.username,"pfp":socket.pfp})
if(len(self.players) == Tournament.playerLimit):
self.start()
if(len(self.players) == Tournament.playerLimit - self.nbBot):
for x in range(self.nbBot):
self.join(None, True)
def createGames(self, players, level=1):
left = None
right = None
if(level == Tournament.levels):
try:
right = players.pop(0)
left = players.pop(0)
except IndexError:
pass
else:
right = self.createGames(players, level + 1)
left = self.createGames(players, level + 1)
return(TournamentGame(left, right))
def start(self):
self.started = True
self.createGames(self.players.copy())

View File

@ -0,0 +1,58 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# TournamentGame.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <marvin@42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/12 22:49:00 by tomoron #+# #+# #
# Updated: 2024/10/13 22:01:59 by tomoron ### ########.fr #
# #
# **************************************************************************** #
import asyncio
from .Game import Game
class TournamentGame:
def __init__(self, left, right):
self.game = None
self.winner = None
self.right = right
self.left = left
asyncio.create_task(self.loop())
def startGame(self):
l = None
r = None
if(isinstance(self.left,TournamentGame)):
self.game = Game(self.left.winner, self.right.winner, True)
l = self.left.winner.socket
r = self.right.winner.socket
else:
self.game = Game(self.left, self.right, True)
l = self.left.socket
r = self.right.socket
l.sync_send("tournament", {
"action":4,
"id": r.id,
"username":r.username
})
r.sync_send("tournament", {
"action":4,
"id": l.id,
"username": l.username
})
async def loop(self):
while self.winner == None:
if(self.game == None):
if(isinstance(self.left, TournamentGame)):
if(self.left.winner != None and self.right.winner != None):
await asyncio.sleep(3)
self.startGame()
else:
await asyncio.sleep(3)
self.startGame()
else:
if(self.game.winner != None):
self.winner = self.game.pWinner
await asyncio.sleep(1)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/09/11 17:07:08 by tomoron #+# #+# #
# Updated: 2024/10/10 03:52:54 by tomoron ### ########.fr #
# Updated: 2024/10/12 23:31:22 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -22,7 +22,7 @@ async def start(socket, content):
socket.sendError("Your opponent isn't online",9032)
return;
skinId = content.get("skinId", 0)
if(skinId < 0 or skinId >= len(GameSettings.skins)):
if(skinId < 0 or skinId >= GameSettings.nbSkins):
socket.sendError("Skin id out of range", 9033)
return;
goalId = content.get("goalId",0)

View File

@ -6,7 +6,7 @@
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/10/04 17:16:02 by tomoron #+# #+# #
# Updated: 2024/10/05 02:28:50 by tomoron ### ########.fr #
# Updated: 2024/10/11 21:14:54 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -19,4 +19,8 @@ async def tournamentStart(socket, content):
else:
socket.sync_send("tournament",{"action":0, "exist":False})
else:
Tournament(socket)
nbBot = content.get("nbBot", 0)
if(nbBot < 0 or nbBot > 7):
socket.sendError("invalid number of bots", 9040)
return;
Tournament(socket, nbBot)

View File

@ -6,7 +6,7 @@
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/09/09 14:31:30 by tomoron #+# #+# #
# Updated: 2024/10/06 16:28:47 by tomoron ### ########.fr #
# Updated: 2024/10/12 02:43:29 by tomoron ### ########.fr #
# #
# **************************************************************************** #
@ -137,9 +137,9 @@ class WebsocketHandler(AsyncWebsocketConsumer):
uid = await self.session_get("id", 0)
if(uid in self.onlinePlayers):
del self.onlinePlayers[uid]
if(self.game !=None):
if(self.game != None):
self.game.leave(self)
if(self.tournament !=None):
if(self.tournament != None):
self.tournament.leave(self)
async def receive(self, text_data):
@ -148,7 +148,8 @@ class WebsocketHandler(AsyncWebsocketConsumer):
except json.JSONDecodeError:
self.sendError("Invalid JSON", 9002)
return
try:
#try:
if(1):
self.printDebug(jsonRequest, 0)
if (jsonRequest["type"] in typeRequest):
if (jsonRequest["type"] == "login" or jsonRequest["type"] == "create_account"):
@ -159,8 +160,8 @@ class WebsocketHandler(AsyncWebsocketConsumer):
await functionRequest[typeRequest.index(jsonRequest["type"])](self, jsonRequest["content"])
else:
self.sendError("Invalid type", 9004)
except Exception as e:
self.sendError("Invalid request", 9005, e)
# except Exception as e:
# self.sendError("Invalid request", 9005, e)
@multimethod
def sync_send(self, reqType : str, content:dict):

View File

@ -41,6 +41,7 @@
- 9037 : you're not in a tournament
- 9038 : missing message field
- 9039 : Goal id out of range
- 9040 : invalid number of bots
- 9100 : Action out of range
- 9101 : No game started