Created
July 22, 2021 04:39
-
-
Save blackjack4494/7ccc84c53f120a60e8675049f1eeaf29 to your computer and use it in GitHub Desktop.
Code Snippet around buildings including calculating costs.
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
# @Author: Tom-Oliver Heidel <theidel/blackjack4494> | |
# @Email: [email protected] | |
# @Date: 2021-07-21 | |
# @Last modified by: theidel | |
# @Last modified time: 2021-07-22 | |
__author__ = '[email protected] (Tom-Oliver Heidel <theidel>)' | |
import json | |
from typing import Union, Tuple | |
# DEBUG | |
dbg = True | |
# can be put into dedicated class | |
# CONSTANTS | |
_DESCRIPTION_KEY = 'description' | |
_NAME_KEY = 'building_name' # 'name' | |
_LEVELS_KEY = 'levels' | |
_BONUSES_KEY = 'bonuses' | |
_COSTS_KEY = 'build_costs' | |
_TIME_KEY = 'build_time' | |
### https://github.com/STFCcommunity/data/blob/32a13b580d8e36221a9e8fe99aaeb1fb6c283049/buildings/operations.json | |
# f = open('buildings.json') | |
# f = open('academy.json') | |
f = open('operations.json') | |
a = json.load(f) | |
f.close() | |
# workaround to make sure data is sorted by level | |
a['levels'].sort(key=lambda x: (x.get('level'))) | |
_data = a | |
# name = input('Enter name: ') | |
# level = int(input('Enter level: ')) | |
name = 'Operations' | |
# name = 'Academy' | |
lvl = 18 | |
lvl_upper = 21 | |
def get_building(name: str = name, lvl: Union[int, Tuple[int, int]] = 1, | |
data: dict = _data, max_distance: int = 10) -> list: | |
''' | |
Wrapper for _get_building | |
Get a building by name and level if provided. | |
Params: | |
name (str): Name of the building | |
lvl (int)(Tuple[int, int]): Level of the building | |
data (dict): Data to search in | |
max_distance (int): Maximum level distance to search | |
Returns: | |
list: List of level objects of the building | |
Raises: | |
Exception: If building not found | |
Note: | |
name checking is loose and will match any substring | |
''' | |
return _get_building(name, lvl, data, max_distance) | |
def _get_building(name: str = name, lvl: Union[int, Tuple[int, int]] = None, | |
data: dict = _data, max_distance: int = 99) -> list: | |
''' | |
Get a building by name and level if provided. | |
Params: | |
name (str): Name of the building | |
lvl (int)(Tuple[int, int]): Level of the building | |
data (dict): Data to search in | |
max_distance (int): Maximum level distance to search | |
Returns: | |
list: List of level objects of the building | |
Raises: | |
Exception: If building not found | |
Note: | |
name checking is loose and will match any substring | |
''' | |
if name is None: | |
raise Exception('Name is required') | |
if lvl is None: | |
if name in data[_NAME_KEY]: | |
return data | |
if isinstance(lvl, int): | |
if lvl < 0: | |
raise ValueError('Level cannot be lower than 0') | |
if lvl > 50: | |
raise ValueError('Level cannot be greater than 50') | |
# arrays starts at 0 so take offset into account | |
if lvl > 0: | |
lvl -= 1 | |
if name in data[_NAME_KEY]: | |
# check if it's really the right level | |
if data[_LEVELS_KEY][lvl]['level'] == lvl+1: | |
return data[_LEVELS_KEY][lvl] | |
else: | |
if dbg: | |
print('[DEBUG] MISMATCH ERROR - Returned (%s, Level %s) but requested level %s' % (name, data[_LEVELS_KEY][lvl]['level'], lvl+1)) | |
raise ValueError('Level not found') | |
if isinstance(lvl, tuple): | |
if len(lvl) != 2: | |
raise ValueError('Level tuple must be of length 2') | |
_lower, _upper = lvl | |
if not isinstance(_lower, int): | |
raise ValueError('Level lower bound must be an integer') | |
if not isinstance(_upper, int): | |
raise ValueError('Level upper bound must be an integer') | |
if not isinstance(max_distance, int): | |
raise ValueError('Max distance must be an integer') | |
if abs(_lower - _upper) > max_distance: | |
raise ValueError('Level range too large') | |
if _lower < 0: | |
raise ValueError('Level lower bound cannot be lower than 0') | |
if _lower > 50: | |
raise ValueError('Level lower bound cannot be greater than 50') | |
if _upper < 0: | |
raise ValueError('Level upper bound cannot be lower than 0') | |
if _upper > 50: | |
raise ValueError('Level upper bound cannot be greater than 50') | |
if _lower > _upper: | |
raise ValueError('Level lower bound cannot be greater than upper bound') | |
if _lower == lvl_upper: | |
raise ValueError('Level lower bound cannot be equal to upper bound') | |
if _lower > 0: | |
_lower -= 1 | |
if _upper > 0: | |
_upper -= 1 | |
if name in data[_NAME_KEY]: | |
for _, _lvl in enumerate(data[_LEVELS_KEY][_lower:_upper+1], _lower): | |
if not (_lower <= _lvl['level'] <= _upper+1): | |
if dbg: | |
print('[DEBUG] MISMATCH ERROR - Returned (%s, Level %s) but requested level %s' % (name, _lvl['level'], _+1)) | |
raise ValueError('Level range validation failed') | |
return data[_LEVELS_KEY][_lower:_upper+1] | |
raise Exception('Building not found') | |
def get_building_ALL(name: str = name, lvl: Union[int, Tuple[int, int]] = 1, | |
data: dict = _data, max_distance: int = 10) -> list: | |
''' | |
Wrapper for _get_building | |
Get a building by name and level if provided. | |
Params: | |
name (str): Name of the building | |
lvl (int)(Tuple[int, int]): Level of the building | |
data (dict): Data to search in | |
max_distance (int): Maximum level distance to search | |
Returns: | |
list: List of level objects of the building | |
Raises: | |
Exception: If building not found | |
Note: | |
name checking is loose and will match any substring | |
''' | |
return _get_building_ALL(name, lvl, data, max_distance) | |
def _get_building_ALL(name: str = name, lvl: Union[int, Tuple[int, int]] = None, | |
data: dict = _data, max_distance: int = 99) -> list: | |
''' | |
Get a building by name and level if provided. | |
Params: | |
name (str): Name of the building | |
lvl (int)(Tuple[int, int]): Level of the building | |
data (dict): Data to search in | |
max_distance (int): Maximum level distance to search | |
Returns: | |
list: List of level objects of the building | |
Raises: | |
Exception: If building not found | |
Note: | |
name checking is loose and will match any substring | |
''' | |
if name is None: | |
raise Exception('Name is required') | |
if lvl is None: | |
for _ in data: | |
if name in _[_NAME_KEY]: | |
return _ | |
if isinstance(lvl, int): | |
if lvl < 0: | |
raise ValueError('Level cannot be lower than 0') | |
if lvl > 50: | |
raise ValueError('Level cannot be greater than 50') | |
# arrays starts at 0 so take offset into account | |
if lvl > 0: | |
lvl -= 1 | |
for _ in data: | |
if name in _[_NAME_KEY]: | |
# check if it's really the right level | |
if _[_LEVELS_KEY][lvl]['level'] == lvl+1: | |
return _[_LEVELS_KEY][lvl] | |
else: | |
raise ValueError('Level not found') | |
if isinstance(lvl, tuple): | |
if len(lvl) != 2: | |
raise ValueError('Level tuple must be of length 2') | |
_lower, _upper = lvl | |
if not isinstance(_lower, int): | |
raise ValueError('Level lower bound must be an integer') | |
if not isinstance(_upper, int): | |
raise ValueError('Level upper bound must be an integer') | |
if not isinstance(max_distance, int): | |
raise ValueError('Max distance must be an integer') | |
if abs(_lower - _upper) > max_distance: | |
raise ValueError('Level range too large') | |
if _lower < 0: | |
raise ValueError('Level lower bound cannot be lower than 0') | |
if _lower > 50: | |
raise ValueError('Level lower bound cannot be greater than 50') | |
if _upper < 0: | |
raise ValueError('Level upper bound cannot be lower than 0') | |
if _upper > 50: | |
raise ValueError('Level upper bound cannot be greater than 50') | |
if _lower > _upper: | |
raise ValueError('Level lower bound cannot be greater than upper bound') | |
if _lower == lvl_upper: | |
raise ValueError('Level lower bound cannot be equal to upper bound') | |
if _lower > 0: | |
_lower -= 1 | |
if _upper > 0: | |
_upper -= 1 | |
for _ in data: | |
if name in _[_NAME_KEY]: | |
for _lvl in _[_LEVELS_KEY][_lower:_upper+1]: | |
if not (_lower <= _lvl['level'] <= _upper+1): | |
raise ValueError('Level range validation failed') | |
return _[_LEVELS_KEY][_lower:_upper+1] | |
raise Exception('Building not found') | |
def calculate_costs(data: list) -> list: | |
''' | |
Calculate the cost of a building | |
Params: | |
data (list): List of level objects of the building | |
Returns: | |
list: List of costs of the building | |
Note: Also generates a dictionary of the costs but won't be returned | |
''' | |
range_costs = [{'mats': [], 'rss': []}] | |
range_costs_dict = {'mats': [], 'rss': []} | |
mat_sums = dict() | |
rss_sums = dict() | |
mats = [] | |
rss = [] | |
for level in data: | |
for mat in level[_COSTS_KEY]['materials']: | |
mats.append(mat) | |
for rs in level[_COSTS_KEY]['resources']: | |
rss.append(rs) | |
for item in mats: | |
key = item['type'], item['grade'], item['rarity'] | |
value = item['value'] | |
try: | |
mat_sums[key]['value'] += value | |
except KeyError: | |
mat_sums[key] = item.copy() | |
for item in rss: | |
key = item['type'] | |
value = item['value'] | |
try: | |
rss_sums[key]['value'] += value | |
except KeyError: | |
rss_sums[key] = item.copy() | |
# mat_result = list(mat_sums.values()) | |
range_costs[0]['mats'] = list(mat_sums.values()) | |
range_costs_dict['mats'] = list(mat_sums.values()) | |
range_costs[0]['rss'] = list(rss_sums.values()) | |
range_costs_dict['rss'] = list(rss_sums.values()) | |
return range_costs | |
print(calculate_costs(_get_building(name, (30, 42)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment