Skip to content

Commit

Permalink
Finished Project
Browse files Browse the repository at this point in the history
  • Loading branch information
Yash committed Apr 12, 2021
1 parent 17f316a commit dcba32c
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 114 deletions.
6 changes: 6 additions & 0 deletions GUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ def __init__(self):
self.game_mode = None

def change_frame(self, change_frame, *player_info):
"""
Needed to handle frame changes so that the user can move from one window to the other
"""
new_frame = change_frame(self)
if self._frame is not None:
self._frame.destroy()
Expand All @@ -32,5 +35,8 @@ def change_frame(self, change_frame, *player_info):


if __name__ == "__main__":
"""
Runs the application
"""
app = FirstGUI()
app.mainloop()
96 changes: 53 additions & 43 deletions Pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@


class PageOne(tk.Frame):
"""
The introduction page to the GUI
"""
def __init__(self, parent):
global img
tk.Frame.__init__(self, parent)
Expand All @@ -29,23 +32,18 @@ def __init__(self, parent):
self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30)
# Default text shown
self.game_choices.set("Select a game")
# Possible games to choose from: Cold war and WoW are examples for now
self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW']
# Possible games to choose from: We used Overwatch
self.game_choices['values'] = ['Overwatch']
self.game_choices.grid(row=1, column=1)

"""
Idea: Maybe we can use validate commands for the entries
To use the logo image on the front page
"""
for filename in glob.glob('logo.png'):
img = ImageTk.PhotoImage(Image.open(filename).resize((380, 221)))
self.panel = Label(self, image=img)
self.panel.grid(row=0, column=1, columnspan=4)

# img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221)))

# self.panel = Label(self, image=img)
# self.panel.grid(row=0, column=1, columnspan=4)

self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello"))
self.sub_btn.grid(row=2, column=1)
self.sub_btn["state"] = DISABLED
Expand All @@ -55,14 +53,17 @@ def __init__(self, parent):
self.game_choices.bind("<<ComboboxSelected>>", self.callback)

def callback(self, event_object):
"""
To ensure a game is selected to enable the submit button
"""
self.game = event_object.widget.get()
if self.game != "Select a game":
self.sub_btn["state"] = NORMAL


class PageTwo(tk.Frame):
"""
For Overwatch
The second page for accepting player to compare stats with.
"""

def __init__(self, parent):
Expand Down Expand Up @@ -135,14 +136,19 @@ def __init__(self, parent):
"\nMore than 2 players are allowed.",
anchor="e", width = 30, justify=LEFT).grid(row=5, column=1, columnspan=1)



def validate_tag(self, id):
if "#" or " " in id.get():
def validate_tag(self, check_id):
"""
Battle tags used in the API request must not contain spaces or #'s (-'s are used to replace them).
"""
if "#" or " " in check_id.get():
self.battle_id.set(self.battle_id.get().replace("#", "-").replace(" ", ""))

def add_player(self):

"""
Validates a player in the API, and adds it to the list of all players who have been registered.
If the player is not found in the API it is not valid, and error messages are used to inform users
about this. There must be at least two players registered to submit.
"""
try:
o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get())

Expand Down Expand Up @@ -183,29 +189,30 @@ def add_player(self):
self.sub_btn["state"] = NORMAL

def clear(self):
"""
Clears all the players registered in the treeview
"""
for player in self.ow_tree.get_children():
self.ow_tree.delete(player)
self.parent.all_players.clear()
self.sub_btn["state"] = DISABLED

def remove_players(self):
curItem = self.ow_tree.focus()
deleted_player = self.ow_tree.item(curItem)['values']
"""
Remove selected players registered in the treeview
"""
cur_item = self.ow_tree.focus()
deleted_player = self.ow_tree.item(cur_item)['values']
for player in self.parent.all_players:
if set(player.information) == set(deleted_player):
self.parent.all_players.remove(player)
selected = self.ow_tree.selection()[0]
self.ow_tree.delete(selected)

# for player in t:
# self.ow_tree.delete(player)
# print(int(player))
# del self.parent.all_players[int(player) - 1]


class PageThree(tk.Frame):
"""
The Third page
The Third page for looking at the potential filters to compare the selected players with from page two.
"""

def __init__(self, parent):
Expand All @@ -229,8 +236,8 @@ def __init__(self, parent):
self.filter_list = self.parent.displayed_stats

self.filter_lb = Listbox(self, selectmode=MULTIPLE, width=50, yscrollcommand=self.scrollbar.set)
for filter in self.filter_list[1:]:
self.filter_lb.insert(END, filter)
for new_filter in self.filter_list[1:]:
self.filter_lb.insert(END, new_filter)
self.filter_lb.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W)
self.filter_lb["state"] = DISABLED
self.filter_lb.bind("<<ListboxSelect>>", self.selected_stats)
Expand All @@ -244,11 +251,14 @@ def __init__(self, parent):
self.back_btn.grid(row=3, column=2)

def selected_stats(self, lb):
"""
To retrieve selected stats from the listbox the player can select filters from. At least one filter must be
selected, not included the default name to proceed. Resource to help us with this feature was listed in sources.
"""
selected_stats = lb.widget.curselection()
self.parent.compared_stats = ["Name"]
if (selected_stats != ()):
for stat in selected_stats:

if self.filter_list[int(stat) + 1] not in self.parent.compared_stats:
self.parent.compared_stats.append(self.filter_list[int(stat) + 1])
if len(self.parent.compared_stats) >= 2:
Expand All @@ -267,7 +277,7 @@ def gameplay_chosen(self):

class PageFour(tk.Frame):
"""
The Fourth page
The fourth page used to display the players in a treeview to
"""

def __init__(self, parent):
Expand All @@ -278,19 +288,19 @@ def __init__(self, parent):
self.Label_table = Label(self, text='Table')
self.Label_table.grid(row=0, column=1, columnspan=2)
self.tree_stats = {}

# Needed to organize the filters
self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze',
'Silver Medals': 'medalsSilver',
'Gold Medals': 'medalsGold'}
self.sub_game_results = {'Games Won': 'gamesWon', 'gamesLost': 'gamesLost', 'gamesPlayed': 'gamesPlayed'}
self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths',
'eliminations': 'eliminations', 'soloKills': 'soloKills',
'objectiveKills': 'objectiveKills'}
self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame',
'barrierDamageDoneMostInGame': 'barrierDamageDoneMostInGame',
'eliminationsMostInGame': 'eliminationsMostInGame',
'healingDoneMostInGame': 'healingDoneMostInGame',
'killsStreakBest': 'killsStreakBest', 'multikillsBest': 'multikillsBest'}
self.sub_game_results = {'Games Won': 'gamesWon', 'GamesLost': 'gamesLost', 'Games Played': 'gamesPlayed'}
self.in_game_stats = {'Barrier DamageDone': 'barrierDamageDone', 'Damage Done': 'damageDone', 'Deaths': 'deaths',
'Eliminations': 'eliminations', 'Solo Kills': 'soloKills',
'Objective Kills': 'objectiveKills'}
self.best_game_results = {'All Damage Done Most In Game': 'allDamageDoneMostInGame',
'Barrier Damage Done Most In Game': 'barrierDamageDoneMostInGame',
'Eliminations Most In Game': 'eliminationsMostInGame',
'Healing Done Most In Game': 'healingDoneMostInGame',
'Kills Streak Best': 'killsStreakBest', 'Multi kills Best': 'multikillsBest'}
self.in_game_index = 0
self.best_in_game_index = 0
self.game_outcome_index = 0
Expand Down Expand Up @@ -353,13 +363,11 @@ def __init__(self, parent):
else:
self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat])

# self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats',
# 'Best In-Game Stats', 'Game Outcomes', 'Awards']
# self.api_filters.extend(
# ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats',
# 'Game Outcomes', 'Awards'])

def transfer_second_page(self):
"""
To revisit the second page from the third page, clearing information about the filters that could
have been selected
"""
self.parent.all_players.clear()
self.parent.game_filters = {}
self.parent.displayed_stats.clear()
Expand All @@ -370,7 +378,9 @@ def transfer_second_page(self):
self.parent.change_frame(PageTwo)

def get_player_info(self, stat):

"""
Organizes the information for each player for each particular filter to access it later on.
"""
for player in self.compared_players:
if stat == 'Awards':
sub_awards = self.sub_awards
Expand Down
100 changes: 29 additions & 71 deletions apicollect.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import requests

"""
Required installments: requests
"""
# API address we can fill the parameters: platform, region and battle tag of a player to get their profile
url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete'


class Overwatch:
"""
This is the class for the game which keeps track of all the players in it.
It sends requests to the Overwatch API online to fetch stats of players in the game.
To fetch the results the user needs to input a valid platform, region and battle tag of their account.
"""
def __init__(self, platform, region, battle_tag):
self.information = [platform, region, battle_tag]
# Send a request to the api to get information about the user profile
Expand Down Expand Up @@ -36,89 +43,40 @@ def get_filters(self):
for x, stat in enumerate(self.displayed_filters):
filter_dict[stat] = self.api_filters[x]

#
# for match_filter in ['quickPlayStats', 'competitiveStats']:
# qp_game_filters = []
# qp_award_filters = []
# qp_total_filters = []
# for qp_filter in self.result_json[match_filter]:
# if qp_filter == 'games':
# for game_filter in self.result_json[match_filter]['games']:
# qp_game_filters.extend(([game_filter]))
# qp_total_filters.extend([qp_filter, qp_game_filters])
# elif qp_filter == 'awards':
#
# for award_filter in self.result_json[match_filter]['awards']:
# qp_award_filters.extend(([award_filter]))
#
# qp_total_filters.extend([qp_filter, qp_award_filters])
# self.filters.extend([[match_filter, qp_total_filters]])
return filter_dict

# self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats',
# 'Best In-Game Stats', 'Game Outcomes', 'Awards']
# self.api_filters.extend(
# ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats',
# 'Game Outcomes', 'Awards'])
def get_stat(self, find_filter, game_mode):
"""
Retrieve the required stat from the api, based on the user choice and game mode.
Certain stats/filters are not applicable for all gamers and as such they are not
listed in the API. N/A is used for such cases.
def get_stat(self, stat, game_mode):
:return: A stat from the api based on inputted game mode and filter
"""
try:
if stat == 'Name':
if find_filter == 'Name':
return self.result_json['name']
elif stat == 'Level':
elif find_filter == 'Level':
return self.result_json['level']
elif stat == 'Endorsement Level':
elif find_filter == 'Endorsement Level':
return self.result_json['endorsement']
elif stat == 'Rating':
elif find_filter == 'Rating':
return self.result_json['rating']
elif stat == 'Prestige':
elif find_filter == 'Prestige':
return self.result_json['prestige']
elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']:
return self.result_json[game_mode]['awards'][stat]
elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']:
return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat]
elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame',
elif find_filter in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']:
return self.result_json[game_mode]['awards'][find_filter]
elif find_filter in ['gameWon', 'gamesLost', 'gamesPlayed']:
return self.result_json[game_mode]['careerStats']['allHeroes']['game'][find_filter]
elif find_filter in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame',
'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']:
return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat]
elif stat in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']:
return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat]
return self.result_json[game_mode]['careerStats']['allHeroes']['best'][find_filter]
elif find_filter in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']:
return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][find_filter]
else:
return self.result_json[stat]
return self.result_json[find_filter]
except TypeError:
# If the api does not have the information associated with a profile
return 'N/A'
except KeyError:
return 'N/A'

# def analyze_stats(self, player):
# """
# analyze the stats of a player and return an integer value representing its final
# score after evaluation
#
# :param player: Battle Tag of player
# :return: evaluation score
# """
# if player == self.test_get_player_info()[0]:
# player_stats = self.test_get_player_info()
# return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations
# return "Invalid player"

# def compare_2players(self, player1, player2):
# """
# compares stats of 2 players, and returns the winning player
#
# :param player1: Battle Tag of player1
# :param player2: Battle Tag of player 2
# :return: player with higher stats, else return a message saying players are equal
# """
# if self.analyze_stats(player1) > self.analyze_stats(player2):
# return player1
# elif self.analyze_stats(player1) < self.analyze_stats(player2):
# return player2
# return "Players are equal in comparison"


# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch


ov = Overwatch('pc', 'us', 'cats-11481')

0 comments on commit dcba32c

Please sign in to comment.