Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuration for Profile #13

Merged
merged 12 commits into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

720 changes: 720 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions .idea/ratings-calculator.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions 2023-jan-can.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Category,Chief Arbiter,Chief Organizer,City,Country,Crosstable,Date received,Date registered,Deputy Chief Arbiter,End Date,Event code,Hybrid,Number of players,Organizer,PGN file,Start Date,System,Time Control,Tournament Name,Type,Zone,arbiter1_code,arbiter1_name,arbiter2_code,arbiter2_name,arbiter3_code,arbiter3_name,arbiter4_code,arbiter4_name,arbiter5_code,arbiter5_name,arbiter6_code,arbiter6_name,arbiter7_code,arbiter7_name,arbiter8_code,arbiter8_name,arbiter9_code,arbiter9_name,rating_type
0,Bhavik Dave (IND),"Lowther, Lars (CAN)",Calgary,CAN,Size: 5888 bytes,2022-12-25,2022-05-15,"Sembrano, Joshua (CAN)",2022-11-27,289950,NO,40,,,2022-11-26,s,Standard: 90 minutes with 30 second increment from move 1,2022 Southern Alberta Open,,,,,,,,,,,,,,,,,,,,,Standard
0,"Zeggelaar, Mike (CAN)","Seehagen, Terry (CAN)",Edmonton,CAN,Size: 5171 bytes,2022-12-26,2022-05-15,"Koperski, Dustin (CAN)",2022-12-18,289951,NO,40,,,2022-12-17,s,Standard: 90 minutes with 30 second increment from move 1,2022 WBX Tournament,,,,,,,,,,,,,,,,,,,,,Standard
0,"Munir, Zeeshan (CAN)","Lowther, Lars (CAN)",Calgary,CAN,Size: 4462 bytes,2022-12-26,2022-08-22,"Lowther, Lars (CAN)",2022-12-06,298462,NO,20,,,2022-11-08,s,Standard: 90 minutes with 30 second increment from move 1,2022 Calgary CC Grand Tour 3 Open,,,,,,,,,,,,,,,,,,,,,Standard
0,"Munir, Zeeshan (CAN)","Lowther, Lars (CAN)",Calgary,CAN,Size: 1731 bytes,2022-12-26,2022-08-22,"Lowther, Lars (CAN)",2022-12-06,298463,NO,20,,,2022-11-08,s,Standard: 90 minutes with 30 second increment from move 1,2022 Calgary CC Grand Tour 3 FM,,,,,,,,,,,,,,,,,,,,,Standard
0,"Palsson, Halldor Peter (CAN)","Palsson, Halldor Peter (CAN)",Ottawa,CAN,Size: 4329 bytes,2022-12-27,2022-09-19,,2022-12-11,302194,NO,40,,,2022-12-09,s,Standard: 90 minutes with 30 second increment from move 1,2022 RA December Open,,,,,,,,,,,,,,,,,,,,,Standard
0,"Gillanders, Robert (CAN)","Gooding, Gordon (CAN)",Milton,CAN,Size: 1446 bytes,2022-12-27,2022-09-21,,2022-12-03,302664,NO,20,,,2022-12-03,s,Rapid: 25 minutes for game with 5 seconds increment from move 1,2022 Bob & Gord's Xmas Active,,,,,,,,,,,,,,,,,,,,,Rapid
0,"Ber, Alexandre (CAN)","Ber, Alexandre (CAN)",Laval,CAN,Size: 2734 bytes,2022-12-28,2022-10-02,,2022-12-06,304197,NO,20,,,2022-11-08,s,Standard: 90 minutes with 30 second increment from move 1,2022-2023 Laval GP2,,,,,,,,,,,,,,,,,,,,,Standard
0,"Boron, Anthony (CAN)","Boron, Anthony (CAN)",Winnipeg,CAN,Size: 4593 bytes,2022-12-27,2022-10-26,"Macpherson, Al (CAN)",2022-11-29,307105,NO,24,,,2022-11-01,s,Standard: All Moves in 90 Min. Incr. 5 Sec. / /,2022 Jay Khedkar Memorial,,,,,,,,,,,,,,,,,,,,,Standard
0,"Ferreira, Alex (CAN)","Zheng, Victor (CAN)",Toronto,CAN,Size: 3912 bytes,2022-12-26,2022-12-04,,2022-12-11,310994,NO,25,,,2022-12-09,s,Standard: 90 minutes with 30 second increment from move 1,2022 Holidays Open - Crown,,,,,,,,,,,,,,,,,,,,,Standard
0,"Ferreira, Alex (CAN)","Zheng, Victor (CAN)",Toronto,CAN,Size: 4198 bytes,2022-12-26,2022-12-04,,2022-12-11,310995,NO,35,,,2022-12-09,s,Standard: 90 minutes with 30 second increment from move 1,2022 Holidays Open - U2200,,,,,,,,,,,,,,,,,,,,,Standard
0,"Ferreira, Alex (CAN)","Zheng, Victor (CAN)",Toronto,CAN,Size: 6772 bytes,2022-12-26,2022-12-04,,2022-12-11,310996,NO,35,,,2022-12-09,s,Standard: 90 minutes with 30 second increment from move 1,2022 Holidays Open - U1900,,,,,,,,,,,,,,,,,,,,,Standard
0,"Boron, Anthony (CAN)","Boron, Anthony (CAN)",Winnipeg,CAN,Size: 2971 bytes,2022-12-28,2022-12-06,"Macpherson, Al (CAN)",2022-12-27,311092,NO,24,,,2022-12-06,s,Standard: 90 minutes with 30 second increment from move 1,2022 Zoltan Bodnar Memorial,,,,,,,,,,,,,,,,,,,,,Standard
0,"Ber, Alexandre (CAN)","Ber, Alexandre (CAN)",Laval,CAN,Size: 2734 bytes,2022-12-28,2022-12-28,,2022-12-20,313091,NO,13,,,2022-09-27,s,Standard: 60 minutes with 30 seconds increment from move 1,2022-2023 Laval GP1,,,,,,,,,,,,,,,,,,,,,Standard
78 changes: 71 additions & 7 deletions src/ratings_calculator/Profile.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
"""Class to get cfc profile information of the user"""
import json
import requests
from config import Config


class CFCProfile:
"""User id of the user that we are trying to get data for"""

# default constructor for ratings calculator
def __init__(self, user_id: int, request=True) -> None:
def __init__(self, user_id: int, config: Config = Config()) -> None:
self.user_id = user_id
self.profile = self.initialize_profile(request)
self.use_profile = config.use_profile
self.web_profile = config.web_profile
self.quick = config.quick

self.profile = self.initialize_profile()
return

def initialize_profile(self, request=True) -> dict:
def initialize_profile(self) -> dict:
"""
Gets the profile of the user
:param request: boolean indicating whether to use the web to search for this fvalue or not.
:return: json dictionary mapping of the player and its fields
"""
if request:
if self.web_profile:
URL = f"https://server.chess.ca/api/player/v1/{self.user_id}"
page = requests.get(URL)
return page.json()
else:
# open the json file and place the file as the value into the page
filepath = "player_info.json"
filepath = f"../player_info_{self.user_id}.json"
f = open(filepath)
data = json.load(f)
return data
Expand All @@ -36,17 +40,48 @@ def get_profile(self) -> dict:
"""
return self.profile

def get_games_played(self) -> int:
"""
Gets the profile of the current user
:return: json dictionary mapping of the player and its fields
"""
games = 0
for tournament in self.profile["player"]["events"]:
if tournament["rating_type"] == "R" and not self.quick:
games += tournament["games_played"]
elif tournament["rating_type"] == "Q" and self.quick:
games += tournament["games_played"]
else:
# not matching
pass

return games

def get_events_played(self) -> int:
"""
Gets the number of events that this user has participated in
:return: events that this user has played in
"""
numEvents = 0
if self.profile["player"]["events"] == []:
return 0
else:
return len(self.profile["player"]["events"])

def get_lifetime_high(self) -> int:
"""
Gets the lifetime high for the event that the user is participating in
:return: the lifetime high for this user based on whether quick or regular rating
"""
search_name = "regular_indicator"
if self.quick:
search_name = "quick_indicator"

# if the regular indicator is null, that means they haven't played enough games
if self.profile["player"][search_name] == []:
return 0
else:
return self.profile["player"][search_name]

def get_last_tournaments(self, num_tournaments: int) -> []:
"""
Gets the number of events that this user has participated in
Expand All @@ -65,6 +100,35 @@ def get_last_tournaments(self, num_tournaments: int) -> []:

return tournament_data

def calc_national_master_norms(self) -> tuple:
"""
National Master can be achieved by achieving a minimum 2200 and 3 performances of over 2300. This can happen at
any point in one's chess career. Titles can also be awarded retroactively.

Some additional notes:
- player must not be a foreign flag
- only regular ratings count
- player must have played at least 5 games
- matches may not be used as a norm
- achieved at least 2300 in their lifetime

:return: A tuple, with index 0 indicating whether they have achieved National Master, and
index 1 indicating the tournaments which account for the National Master title.
"""
title_valid = False

perf_tournaments = [x for x in self.profile["player"]["events"] if
x["rating_perf"] >= 2300 and
x["games_played"] >= 5 and
x["rating_type"] == "R"]

min_rating_reached = [x for x in self.profile["player"]["events"] if x["rating_post"] >= 2200]

if len(perf_tournaments) >= 3 and min_rating_reached:
title_valid = True

return title_valid, perf_tournaments


class FIDEProfile:
"""Gets user id data for FIDE profile"""
Expand Down
3 changes: 2 additions & 1 deletion src/ratings_calculator/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__version__ = "0.0.1"
"""Initialization file for python project"""
__version__ = "0.0.1"
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions src/ratings_calculator/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Configuration file"""
from dataclasses import dataclass


@dataclass
class Config:
"""Configuration class for entire project"""
use_profile: bool = True
web_profile: bool = True # for web ratings
quick: bool = False
Original file line number Diff line number Diff line change
@@ -1,17 +1,87 @@
"""Unit tests for the application"""

import unittest
from src.ratings_calculator.Profile import CFCProfile
from src.ratings_calculator.RatingsCalculator import RatingsCalculator
# from src.ratings_calculator.Profile import CFCProfile
# from src.ratings_calculator.RatingsCalculator import RatingsCalculator

from Profile import CFCProfile
from RatingsCalculator import RatingsCalculator
from config import Config


class TestProfileFunctionality(unittest.TestCase):
def test_name_input_correct(self) -> None:
profile = CFCProfile(150532, False) # for now, input int
def test_name_input_correct_web(self) -> None:
config = Config()

profile = CFCProfile(150532, config) # for now, input int
profile_dict = profile.get_profile()
self.assertEqual(profile_dict["player"]["name_first"], "Victor")
self.assertEqual(profile_dict["player"]["name_last"], "Zheng")

tour_data = profile.get_last_tournaments(5)
print(tour_data)
assert len(tour_data) == 5

games_played = profile.get_games_played()
print(games_played)

def test_name_input_correct_local(self) -> None:
config = Config(web_profile=False)

profile = CFCProfile(150532, config) # for now, input int
profile_dict = profile.get_profile()
self.assertEqual(profile_dict["player"]["name_first"], "Victor")
self.assertEqual(profile_dict["player"]["name_last"], "Zheng")

tour_data = profile.get_last_tournaments(5)
print(tour_data)
assert len(tour_data) == 5

games_played = profile.get_games_played()
print(games_played)

def test_get_lifetime_high_regular(self) -> None:
config = Config(web_profile=False, quick=False)

profile = CFCProfile(150532, config) # for now, input int

regular_high = profile.get_lifetime_high()
assert regular_high == 2160

def test_get_lifetime_high_quick(self) -> None:
config = Config(web_profile=False, quick=True)

profile = CFCProfile(150532, config) # for now, input int

regular_high = profile.get_lifetime_high()
assert regular_high == 2092

def test_get_lifetime_high_fail(self) -> None:
config = Config(web_profile=False, quick=True)

profile = CFCProfile(150532, config) # for now, input int

regular_high = profile.get_lifetime_high()
assert not regular_high == 2091

def test_get_national_master_norms_invalid(self) -> None:
config = Config(web_profile=False, quick=False)

profile = CFCProfile(150532, config) # for now, input int

nm_norms = profile.calc_national_master_norms()
print(nm_norms)
assert nm_norms[0] is False

def test_get_national_master_norms_valid(self) -> None:
config = Config(web_profile=True, quick=False)

profile = CFCProfile(154677, config) # for now, input int

nm_norms = profile.calc_national_master_norms()
print(nm_norms)

assert nm_norms[0] is True


class TestBasicFunctionalities(unittest.TestCase):
Expand Down
Loading