-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from TINF21CS1/statistics
Statistics
- Loading branch information
Showing
13 changed files
with
467 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,4 +49,5 @@ dist/** | |
package.nls.*.json | ||
l10n/ | ||
launch.json | ||
venv | ||
venv | ||
*.db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import json | ||
from os.path import exists | ||
|
||
# Path to the profiles.json file | ||
path = ('../json_schema/profiles.json') | ||
|
||
class Profile: | ||
""" | ||
This class is used to handle the profiles.json file. It is used to get, set, and add profiles to the file. | ||
""" | ||
def check_file(self): | ||
""" | ||
This method checks if the file exists | ||
:return: True if the file exists, False if it does not | ||
""" | ||
if exists(path): | ||
print("found") | ||
return True | ||
else: | ||
print("not found") | ||
return False | ||
|
||
def get_profiles(self): | ||
""" | ||
This method returns all the profiles from the file | ||
:return: An array of all profiles | ||
""" | ||
if self.check_file(): | ||
with open(path, 'r') as file: | ||
data = json.load(file) | ||
return data | ||
else: | ||
return None | ||
def get_profile(self,profile_uuid): | ||
""" | ||
This method returns a profile by its uuid | ||
:param profile_uuid: | ||
:return: profile matching given uuid | ||
""" | ||
if self.check_file(): | ||
try: | ||
with open(path, 'r') as file: | ||
data = json.load(file) | ||
for profile in data: | ||
if profile["profile_uuid"] == profile_uuid: | ||
return profile | ||
except: | ||
print("json error: Make sure profiles.json is formatted correctly") | ||
return None | ||
def set_profile(self, profile_uuid , profile_name = None, profile_color = None): | ||
""" | ||
This method sets the profile name and/or color by the uuid | ||
:param profile_uuid: | ||
:param profile_name: *optional* | ||
:param profile_color: *optional* | ||
""" | ||
if self.check_file(): | ||
try: | ||
with open(path, 'r+') as file: | ||
data = json.load(file) | ||
for profile in data: | ||
if profile["profile_uuid"] == profile_uuid: | ||
if profile_name != None: | ||
profile["profile_name"] = profile_name | ||
if profile_color != None: | ||
profile["profile_color"] = profile_color | ||
break | ||
with open(path, 'w') as file: | ||
json.dump(data, file) | ||
except: | ||
print("json error: Make sure profiles.json is formatted correctly") | ||
return None | ||
def get_profile_by_name(self, profile_name): | ||
if self.check_file(): | ||
""" | ||
This method returns a profile by its name | ||
:param profile_name: | ||
:return: profile matching given name | ||
""" | ||
try: | ||
with open(path, 'r') as file: | ||
data = json.load(file) | ||
for profile in data: | ||
if profile["profile_name"] == profile_name: | ||
return profile | ||
except: | ||
print("json error: Make sure profiles.json is formatted correctly") | ||
return None | ||
|
||
def add_new_profile(self, profile_name, profile_uuid, profile_color): | ||
""" | ||
This method adds a new profile to the file | ||
:param profile_name: | ||
:param profile_uuid: | ||
:param profile_color: | ||
""" | ||
if self.check_file(): | ||
entry = {"profile_name": profile_name, "profile_uuid": profile_uuid, "profile_color": profile_color} | ||
try: | ||
with open(path, 'r+') as file: | ||
data = json.load(file) | ||
file.seek(0) | ||
data.append(entry) | ||
json.dump(data, file) | ||
file.truncate() | ||
except: | ||
print("json error: Make sure profiles.json is formatted correctly") | ||
|
||
else: | ||
with open(path, 'w') as file: | ||
entry = [{"profile_name": profile_name, "profile_uuid": profile_uuid, "profile_color": profile_color}] | ||
json.dump(entry, file) | ||
|
||
#Testing | ||
#profile = Profile() | ||
#profile.add_new_profile("test", "test", "test") | ||
#print(profile.get_profiles()) | ||
#print(profile.get_profile("test")) | ||
#profile.set_profile("test", "test2", "test3") | ||
#print(profile.get_profiles()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,204 @@ | ||
import emoji | ||
import sqlite3 | ||
import os | ||
|
||
from Server.player import Player | ||
|
||
|
||
class Statistics: | ||
def __init__(self) -> None: | ||
pass | ||
""" | ||
Handle Statistics and Writing to permanent storage. | ||
Methods: | ||
get_statistics() -> list: returns all statistics | ||
increment_emojis(player: Player, message: str) -> None: counts the emojis in the given message and updates the emoji statistics of a profile by its player object | ||
increment_moves(player: Player) -> None: increments the moves of a profile by its player object | ||
increment_games(player_list: list[Player], winner: int) -> None: increments the wins and losses of both players by their player objects | ||
Private Methods: | ||
_increment_win(player: Player) -> None: increments the wins of a profile by its player object | ||
_increment_loss(player: Player) -> None: increments the losses of a profile by its player object | ||
_increment_draws(player: Player) -> None: increments the draws of a profile by its player object | ||
_check_add_profile(player: Player) -> None: checks if a profile with the given uuid exists and adds it if it doesn't | ||
_check_profile(uuid: str) -> bool: checks if a profile with the given uuid exists | ||
_add_profile(player: Player) -> None: adds a new profile to the database | ||
""" | ||
|
||
|
||
def __init__(self, path: str = os.path.abspath('Server/Data/statistics.db')) -> None: | ||
""" | ||
Initializes the statistics object by creating a connection to the database | ||
and creating the table if it doesn't exist | ||
:param path: path to db file, default is './Data/statistics.db' | ||
""" | ||
self.path = path | ||
self.conn = sqlite3.connect(self.path) | ||
self.cursor = self.conn.cursor() | ||
with self.conn: | ||
self.cursor.execute(f""" | ||
CREATE TABLE IF NOT EXISTS statistics( | ||
uuid TEXT, | ||
display_name TEXT, | ||
color INT, | ||
wins INT, | ||
losses INT, | ||
draws INT, | ||
moves INT, | ||
emojis INT | ||
) | ||
""") | ||
|
||
|
||
def get_statistics(self) -> list: | ||
""" | ||
Returns the statistics of all players | ||
:return: all statistics | ||
""" | ||
with self.conn: | ||
self.cursor.execute(f""" | ||
SELECT * FROM statistics | ||
""") | ||
return self.cursor.fetchall() | ||
|
||
|
||
def increment_emojis(self, player: Player, message: str) -> None: | ||
""" | ||
Counts the emojis in the given message and updates the emoji | ||
statistics of a profile by its uuid | ||
:param player: | ||
:param message: message that is checked for emojis | ||
""" | ||
|
||
self._check_add_profile(player) | ||
|
||
with self.conn: | ||
self.cursor.execute(f""" | ||
UPDATE statistics | ||
SET emojis = emojis + ? | ||
WHERE uuid = ? | ||
""", | ||
(emoji.emoji_count(message), str(player.uuid))) | ||
|
||
def increment_moves(self, player: Player) -> None: | ||
""" | ||
Increments the moves of a profile by its uuid | ||
:param player: | ||
""" | ||
|
||
self._check_add_profile(player) | ||
|
||
with self.conn: | ||
self.cursor.execute(f""" | ||
UPDATE statistics | ||
SET moves = moves + 1 | ||
WHERE uuid = ? | ||
""", (str(player.uuid),)) | ||
|
||
def increment_games(self, player_list: list[Player], winner: int) -> None: | ||
""" | ||
Increments the wins and losses of both players by their player objects | ||
:param player_list: list of None, player1, player2 | ||
:param winner: 0 if draw, 1 if player1 wins, 2 if player2 wins | ||
""" | ||
|
||
self._check_add_profile(player_list[1]) | ||
self._check_add_profile(player_list[2]) | ||
|
||
if winner == 0: | ||
self._increment_draws(player_list[1]) | ||
self._increment_draws(player_list[2]) | ||
elif winner == 1: | ||
self._increment_win(player_list[1]) | ||
self._increment_loss(player_list[2]) | ||
elif winner == 2: | ||
self._increment_win(player_list[2]) | ||
self._increment_loss(player_list[1]) | ||
else: | ||
raise ValueError("Winner must be 0, 1 or 2") | ||
|
||
def _increment_win(self, player: Player) -> None: | ||
""" | ||
Increments the wins of a profile by its uuid | ||
:param player: player object of the profile that is updated | ||
""" | ||
|
||
self._check_add_profile(player) | ||
|
||
with self.conn: | ||
self.cursor.execute(f""" | ||
UPDATE statistics | ||
SET wins = wins + 1 | ||
WHERE uuid = ? | ||
""", | ||
(str(player.uuid),) | ||
) | ||
|
||
def _increment_loss(self, player: Player) -> None: | ||
""" | ||
Increments the losses of a profile by its uuid | ||
:param player: player object of the profile that is updated | ||
""" | ||
|
||
self._check_add_profile(player) | ||
|
||
with self.conn: | ||
self.cursor.execute(f""" | ||
UPDATE statistics | ||
SET losses = losses + 1 | ||
WHERE uuid = ? | ||
""", | ||
(str(player.uuid),) | ||
) | ||
|
||
def _increment_draws(self, player: Player) -> None: | ||
""" | ||
Increments the draws of a profile by its uuid | ||
:param player: player object of the profile that is updated | ||
""" | ||
|
||
self._check_add_profile(player) | ||
|
||
with self.conn: | ||
self.cursor.execute(f""" | ||
UPDATE statistics | ||
SET draws = draws + 1 | ||
WHERE uuid = ? | ||
""", | ||
(str(player.uuid),) | ||
) | ||
|
||
|
||
def _check_add_profile(self, player: Player) -> None: | ||
""" | ||
Checks if a profile with the given uuid exists and adds it if it doesn't | ||
:param uuid: uuid of the profile that is checked | ||
:return: True if the profile exists, False if it doesn't | ||
""" | ||
if not self._check_profile(str(player.uuid)): | ||
self._add_profile(player) | ||
|
||
def _check_profile(self, uuid_str: str) -> bool: | ||
""" | ||
Checks if a profile with the given uuid exists | ||
:param uuid: uuid of the profile that is checked | ||
:return: True if the profile exists, False if it doesn't | ||
""" | ||
with self.conn: | ||
self.cursor.execute(f""" | ||
SELECT * FROM statistics | ||
WHERE uuid = ? | ||
""", (uuid_str,)) | ||
return True if self.cursor.fetchone() is not None else False | ||
|
||
def _add_profile(self, player: Player) -> None: | ||
""" | ||
Adds a new profile to the database | ||
:param player: player object of the profile that is added | ||
""" | ||
with self.conn: | ||
self.cursor.execute(f""" | ||
INSERT INTO statistics ('uuid', 'display_name', 'color', 'wins', 'losses', 'draws', 'moves', 'emojis') | ||
VALUES (?, ?, ?, 0, 0, 0, 0, 0) | ||
""", | ||
(str(player.uuid), player.display_name, player.color,) | ||
) |
Oops, something went wrong.