def test_search_multivalued_list__value_does_not_exists__return_false( self): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" assert alist.search(4) is False
def test_insert_at_tail__non_empty_list__ok(self): alist = LinkedList(Node("1")) assert alist.is_empty() is False assert alist.get_head() is not None data = 2 alist.insert_at_tail(data) assert alist.is_empty() is False assert str(alist) == f"1 -> {data} -> None" data = 3 alist.insert_at_tail(data) assert alist.is_empty() is False assert str(alist) == f"1 -> 2 -> {data} -> None"
def test_delete__empty_list__ok(self): alist = LinkedList() assert alist.is_empty() is True assert alist.get_head() is None alist.delete(10) assert alist.is_empty() is True assert alist.get_head() is None
def test_init__with_node__ok(self): first_node = Node("fake data") assert first_node.data == "fake data" assert first_node.next_element is None alist = LinkedList(first_node) assert alist.head_node == first_node
def test_insert_at_head__non_empty_list__ok(self): alist = LinkedList(Node("1")) assert alist.is_empty() is False assert alist.get_head() is not None data = 2 alist.insert_at_head(data) assert alist.is_empty() is False assert alist.get_head().data == data assert str(alist) == f"{data} -> 1 -> None"
def test_insert_at_tail__empty_list__ok(self): alist = LinkedList() assert alist.is_empty() is True assert alist.get_head() is None data = 1 alist.insert_at_tail(data) assert alist.is_empty() is False assert alist.get_head().data == data assert str(alist) == f"{data} -> None"
def test_delete_at_head__empty_list_with_many_elements__ok(self): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" assert alist.get_head().data == 3 alist.delete_at_head() assert str(alist) == "2 -> 1 -> None" assert alist.get_head().data == 2
def test_delete_at_head__non_empty_list_with_one_element__ok(self): alist = LinkedList(Node(1)) assert str(alist) == "1 -> None" assert alist.get_head().data == 1 alist.delete_at_head() assert alist.is_empty() is True assert alist.get_head() is None
def test_insert_at_position__position_equals_head__ok(self): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" data, position = "xxx", 0 alist.insert_at_position(data, position) assert alist.get_head().data == data assert str(alist) == f"xxx -> 3 -> 2 -> 1 -> None"
def test_insert_at_position__empty_list_position_one__ok(self): alist = LinkedList() data, position = 1, 0 alist.insert_at_position(data, position) assert alist.is_empty() is False assert alist.get_head().data == data assert str(alist) == f"{data} -> None"
def test_insert_at_position__position_out_of_range__raises(self): with pytest.raises(Exception): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" alist.insert_at_position("xxx", 3)
def test_delete__non_empty_list_multiple_value_exists__ok(self): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" alist.delete(2) assert str(alist) == "3 -> 1 -> None"
def test_insert_at_position__position_equals_tail__ok(self): alist = LinkedList() for i in range(1, 4): alist.insert_at_head(i) assert str(alist) == "3 -> 2 -> 1 -> None" data, position = "xxx", 2 alist.insert_at_position(data, position) assert str(alist) == f"3 -> 2 -> 1 -> xxx -> None"
def test_search__list_has_one_non_existing_element__return_true(self): alist = LinkedList(Node(1)) assert str(alist) == "1 -> None" assert alist.search(2) is False
def test_delete__non_empty_list_single_value_exists__ok(self): alist = LinkedList(Node(1)) assert str(alist) == "1 -> None" alist.delete(1) assert alist.is_empty() is True assert alist.get_head() is None
def test_get_head__ok(self): node = Node("a") alist = LinkedList(node) assert alist.get_head() == node
def test_search__empty_list__return_false(self): alist = LinkedList() assert alist.is_empty() is True assert alist.search(1) is False
def test_is_empty__empty_list__ok(self): alist = LinkedList() node = Node("a") blist = LinkedList(node) assert alist.is_empty() is True assert blist.is_empty() is False
async def populate_data(self): sn = Splatnet(self.session) timestamp = self.target_time.timestamp() data = None if self.mode_type is ModeTypes.REGULAR: data = await sn.get_turf() elif self.mode_type is ModeTypes.RANKED: data = await sn.get_ranked() elif self.mode_type is ModeTypes.LEAGUE: data = await sn.get_league() elif self.mode_type is ModeTypes.SALMON: data = await sn.get_salmon_detail() # find a regular/ranked/league session given the target time if self.mode_type is not ModeTypes.SALMON: for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = rotation["rule"]["name"] self.stage_a = rotation["stage_a"]["name"] self.stage_a_image = IMAGE_BASE + rotation["stage_a"][ "image"] self.stage_b = rotation["stage_b"]["name"] self.stage_b_image = IMAGE_BASE + rotation["stage_b"][ "image"] self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) return True return False # salmon run is a special exception, requires special processing else: for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = "Salmon Run" self.stage_a = rotation["stage"]["name"] self.stage_a_image = IMAGE_BASE + rotation["stage"]["image"] self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) self.weapons_array = LinkedList() # getting weapons, using SR_TERM_CHAR to separate b/t weapon name and weapon id for weapon in rotation["weapons"]: # weapon id of -1 indicates a random weapon (non shiny question mark) if weapon["id"] == '-1': self.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Weapon" + SR_TERM_CHAR + "r1" ) # using r1 for -1 as discord doesn't support "-" char # weapon id of -2 indicates a grizzco weapon elif weapon["id"] == '-2': self.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Grizzco Weapon" + SR_TERM_CHAR + "r2") # using r2 for -2 else: self.weapons_array.add(weapon["weapon"]["name"] + SR_TERM_CHAR + weapon["id"]) return True # if we can't find a detailed rotation, search some more in the other rotations data = await sn.get_salmon_schedule() for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = "Salmon Run" self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) return True return False
async def get_all_rotations(time: datetime, mode_type: ModeTypes, session=None): sn = Splatnet(session) data = None schedule_list = [] if mode_type is ModeTypes.REGULAR: data = await sn.get_turf() elif mode_type is ModeTypes.RANKED: data = await sn.get_ranked() elif mode_type is ModeTypes.LEAGUE: data = await sn.get_league() elif mode_type is ModeTypes.SALMON: data = await sn.get_salmon_detail() if data is None: raise Exception("Splatnet call failed.") if mode_type is not ModeTypes.SALMON: for schedule in data: start_time = datetime.fromtimestamp(schedule["start_time"], time.tzname()) element = SplatoonRotation(start_time, mode_type, session) element.mode = schedule["rule"]["name"] element.stage_a = schedule["stage_a"]["name"] element.stage_a_image = IMAGE_BASE + schedule["stage_a"][ "image"] element.stage_b = schedule["stage_b"]["name"] element.stage_b_image = IMAGE_BASE + schedule["stage_b"][ "image"] element.start_time = start_time element.end_time = datetime.fromtimestamp( schedule["end_time"], time.tzname()) schedule_list.append(element) # salmon run is a special exception, requires special processing else: # Adding detailed info to the list for sr_schedule in data: start_time = datetime.fromtimestamp(sr_schedule["start_time"], time.tzname()) element = SplatoonRotation(start_time, mode_type, session) element.mode = "Salmon Run" element.start_time = start_time element.end_time = datetime.fromtimestamp( sr_schedule["end_time"], time.tzname()) element.stage_a = sr_schedule["stage"]["name"] element.stage_a_image = IMAGE_BASE + sr_schedule["stage"][ "image"] element.weapons_array = LinkedList() # getting weapons for weapon in sr_schedule["weapons"]: # weapon id of -1 indicates a random weapon (non shiny question mark) if weapon["id"] == '-1': element.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Weapon" + SR_TERM_CHAR + "r1") # weapon id of -2 indicates grizzco weapon elif weapon["id"] == '-2': element.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Grizzco Weapon" + SR_TERM_CHAR + "r2") else: element.weapons_array.add(weapon["weapon"]["name"] + SR_TERM_CHAR + weapon["id"]) schedule_list.append(element) # Adding salmon schedules that we don't know anything about data = await sn.get_salmon_schedule() for sr_schedule in data: start_time_elm = datetime.fromtimestamp( sr_schedule["start_time"], time.tzname()) end_time_elm = datetime.fromtimestamp(sr_schedule["end_time"], time.tzname()) # Skipping the first 2 in the list as we already parsed that info above if schedule_list[ 0].start_time != start_time_elm and schedule_list[ 1].start_time != start_time_elm: element = SplatoonRotation(start_time_elm, mode_type, session) element.mode = "Salmon Run" element.start_time = start_time_elm element.end_time = end_time_elm schedule_list.append(element) return schedule_list
class SplatoonRotation: def __init__(self, target_time: datetime, mode_type: ModeTypes, session=None, restore_from_pickle: dict = None): self.target_time = target_time self.mode_type = mode_type self.session = session # when is object being created? if restore_from_pickle is None: # at runtime, the data will need to be populated by the program after construction self.mode = None self.stage_a = None self.stage_a_image = None if mode_type is not ModeTypes.SALMON: self.stage_b = None # Not populated for salmon run self.stage_b_image = None # Not populated for salmon run self.start_time = None self.end_time = None if mode_type is ModeTypes.SALMON: self.weapons_array = None # for salmon run only else: # we are restoring from the pickle, bring in all the data if "mode" in restore_from_pickle: self.mode = restore_from_pickle["mode"] else: self.mode = None if "stage_a" in restore_from_pickle: self.stage_a = restore_from_pickle["stage_a"] else: self.stage_a = None if "stage_a_image" in restore_from_pickle: self.stage_a_image = restore_from_pickle["stage_a_image"] else: self.stage_a_image = None if "stage_b" in restore_from_pickle: self.stage_b = restore_from_pickle["stage_b"] else: self.stage_b = None if "stage_b_image" in restore_from_pickle: self.stage_b_image = restore_from_pickle["stage_b_image"] else: self.stage_b_image = None if "start_time" in restore_from_pickle: self.start_time = restore_from_pickle["start_time"] else: self.start_time = None if "end_time" in restore_from_pickle: self.end_time = restore_from_pickle["end_time"] else: self.end_time = None if "weapons_array" in restore_from_pickle: self.weapons_array = restore_from_pickle["weapons_array"] else: self.weapons_array = None if "target_time" in restore_from_pickle: self.target_time = restore_from_pickle["target_time"] else: self.target_time = None if "mode_type" in restore_from_pickle: self.mode_type = restore_from_pickle["mode_type"] else: self.mode_type = None # NOTE: can't restore the session object def __reduce__(self): """ For pickling this object, we need to keep all data but the session :return: a tuple with class information as well as all needed data fields """ restore_from_pickle = { "mode": self.mode, "stage_a": self.stage_a, "stage_a_image": self.stage_a_image, "start_time": self.start_time, "end_time": self.end_time, } if self.mode_type is ModeTypes.SALMON: restore_from_pickle["weapons_array"] = self.weapons_array else: restore_from_pickle["stage_b"] = self.stage_b restore_from_pickle["stage_b_image"] = self.stage_b_image return (self.__class__, (self.target_time, self.mode_type, None, restore_from_pickle)) async def populate_data(self): sn = Splatnet(self.session) timestamp = self.target_time.timestamp() data = None if self.mode_type is ModeTypes.REGULAR: data = await sn.get_turf() elif self.mode_type is ModeTypes.RANKED: data = await sn.get_ranked() elif self.mode_type is ModeTypes.LEAGUE: data = await sn.get_league() elif self.mode_type is ModeTypes.SALMON: data = await sn.get_salmon_detail() # find a regular/ranked/league session given the target time if self.mode_type is not ModeTypes.SALMON: for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = rotation["rule"]["name"] self.stage_a = rotation["stage_a"]["name"] self.stage_a_image = IMAGE_BASE + rotation["stage_a"][ "image"] self.stage_b = rotation["stage_b"]["name"] self.stage_b_image = IMAGE_BASE + rotation["stage_b"][ "image"] self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) return True return False # salmon run is a special exception, requires special processing else: for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = "Salmon Run" self.stage_a = rotation["stage"]["name"] self.stage_a_image = IMAGE_BASE + rotation["stage"]["image"] self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) self.weapons_array = LinkedList() # getting weapons, using SR_TERM_CHAR to separate b/t weapon name and weapon id for weapon in rotation["weapons"]: # weapon id of -1 indicates a random weapon (non shiny question mark) if weapon["id"] == '-1': self.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Weapon" + SR_TERM_CHAR + "r1" ) # using r1 for -1 as discord doesn't support "-" char # weapon id of -2 indicates a grizzco weapon elif weapon["id"] == '-2': self.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Grizzco Weapon" + SR_TERM_CHAR + "r2") # using r2 for -2 else: self.weapons_array.add(weapon["weapon"]["name"] + SR_TERM_CHAR + weapon["id"]) return True # if we can't find a detailed rotation, search some more in the other rotations data = await sn.get_salmon_schedule() for rotation in data: if rotation["start_time"] <= timestamp < rotation["end_time"]: self.mode = "Salmon Run" self.start_time = datetime.fromtimestamp( rotation["start_time"], self.target_time.tzname()) self.end_time = datetime.fromtimestamp( rotation["end_time"], self.target_time.tzname()) return True return False @staticmethod async def get_all_rotations(time: datetime, mode_type: ModeTypes, session=None): sn = Splatnet(session) data = None schedule_list = [] if mode_type is ModeTypes.REGULAR: data = await sn.get_turf() elif mode_type is ModeTypes.RANKED: data = await sn.get_ranked() elif mode_type is ModeTypes.LEAGUE: data = await sn.get_league() elif mode_type is ModeTypes.SALMON: data = await sn.get_salmon_detail() if data is None: raise Exception("Splatnet call failed.") if mode_type is not ModeTypes.SALMON: for schedule in data: start_time = datetime.fromtimestamp(schedule["start_time"], time.tzname()) element = SplatoonRotation(start_time, mode_type, session) element.mode = schedule["rule"]["name"] element.stage_a = schedule["stage_a"]["name"] element.stage_a_image = IMAGE_BASE + schedule["stage_a"][ "image"] element.stage_b = schedule["stage_b"]["name"] element.stage_b_image = IMAGE_BASE + schedule["stage_b"][ "image"] element.start_time = start_time element.end_time = datetime.fromtimestamp( schedule["end_time"], time.tzname()) schedule_list.append(element) # salmon run is a special exception, requires special processing else: # Adding detailed info to the list for sr_schedule in data: start_time = datetime.fromtimestamp(sr_schedule["start_time"], time.tzname()) element = SplatoonRotation(start_time, mode_type, session) element.mode = "Salmon Run" element.start_time = start_time element.end_time = datetime.fromtimestamp( sr_schedule["end_time"], time.tzname()) element.stage_a = sr_schedule["stage"]["name"] element.stage_a_image = IMAGE_BASE + sr_schedule["stage"][ "image"] element.weapons_array = LinkedList() # getting weapons for weapon in sr_schedule["weapons"]: # weapon id of -1 indicates a random weapon (non shiny question mark) if weapon["id"] == '-1': element.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Weapon" + SR_TERM_CHAR + "r1") # weapon id of -2 indicates grizzco weapon elif weapon["id"] == '-2': element.weapons_array.add( weapon["coop_special_weapon"]["name"] + " Grizzco Weapon" + SR_TERM_CHAR + "r2") else: element.weapons_array.add(weapon["weapon"]["name"] + SR_TERM_CHAR + weapon["id"]) schedule_list.append(element) # Adding salmon schedules that we don't know anything about data = await sn.get_salmon_schedule() for sr_schedule in data: start_time_elm = datetime.fromtimestamp( sr_schedule["start_time"], time.tzname()) end_time_elm = datetime.fromtimestamp(sr_schedule["end_time"], time.tzname()) # Skipping the first 2 in the list as we already parsed that info above if schedule_list[ 0].start_time != start_time_elm and schedule_list[ 1].start_time != start_time_elm: element = SplatoonRotation(start_time_elm, mode_type, session) element.mode = "Salmon Run" element.start_time = start_time_elm element.end_time = end_time_elm schedule_list.append(element) return schedule_list @staticmethod def format_time(time: datetime): # returns <hour>:<time> <am/pm> return time.strftime("%I:%M %p") @staticmethod def format_time_sr(time: datetime): # returns <abbr. weekday> <abbr. month> <date> <hour>:<time> <am/pm> return time.strftime("%a %b %d %I:%M %p") @staticmethod def format_time_sch(time: datetime): # returns <hour> <am/pm> return time.strftime("%-I %p") @staticmethod def print_sr_weapons(weapons_array: LinkedList): # Used to print out salmon run weapons weapon_list_str = "" for weapon in weapons_array: # we split based off SR_TERM_CHAR: <weapon name>SR_TERM_CHAR<weapon id> weapon_name = weapon.split(SR_TERM_CHAR)[0] weapon_id = weapon.split(SR_TERM_CHAR)[1] weapon_list_str += gen_emote_id( weapon_id) + " " + weapon_name + "\n" return weapon_list_str
def test_delete__non_empty_list_value_not_found__ok(self): alist = LinkedList(Node(1)) assert str(alist) == "1 -> None" alist.delete(2) assert str(alist) == "1 -> None"
async def create(self, ctx, *args): lobby = self.find_lobby(ctx.channel) if lobby is None: # default argument values name = "Splatoon Lobby" num_players = 4 lobby_type = None # default time is the next hour time = datetime.now() time += timedelta(minutes=60 - time.minute) # get arguments if they exist if len(args) >= NAME + 1: name = args[NAME] lobby_type = Lobby.parse_special_lobby_type(name) if lobby_type == ModeTypes.LEAGUE: name = "League Battle" elif lobby_type == ModeTypes.SALMON: name = "Salmon Run" elif lobby_type == ModeTypes.REGULAR: name = "Turf War" elif lobby_type == ModeTypes.PRIVATE: name = "Private Battle" num_players = 8 if len(args) >= NUM_PLAYERS + 1: try: num_players = int(args[NUM_PLAYERS]) except ValueError as e: await ctx.send( ":warning: You gave an invalid number of players, defaulting to " + str(num_players) + " players.") if len(args) >= TIME + 1: try: time = parse(args[TIME]) # if the time has already happened, delay the lobby start time to the next day if DateDifference.subtract_datetimes( time, datetime.now()) <= DateDifference(0): time = time + timedelta(days=1) except ValueError as e: await ctx.send( ":warning: You gave an invalid lobby time, defaulting to the next hour." ) # attach extra data if applicable if lobby_type is ModeTypes.LEAGUE: rotation = await Lobby.generate_league(name, time, self.bot.session) elif lobby_type is ModeTypes.SALMON: rotation = await Lobby.generate_salmon(name, time, self.bot.session) # checking if there is a salmon run rotation happening right now if rotation is None: await Lobby.send_sal_err(ctx, time, session=self.bot.session) elif lobby_type is ModeTypes.REGULAR: rotation = await Lobby.generate_regular( name, time, self.bot.session) else: rotation = None # add the lobby to the list lobby = LobbyData(LinkedList(), ctx.channel, name, rotation, num_players, time, False) self.lobbies.append(lobby) # generate and send off the embed await ctx.send(":white_check_mark: Created a lobby in " + ctx.channel.mention) await Lobby.attach_send_gif( embed=Lobby.generate_lobby_embed(lobby), lobby=lobby, ctx=ctx) else: await ctx.send(":x: A lobby already exists in " + ctx.channel.mention)
from modules.linked_list import LinkedList link_list = LinkedList() link_list.add(5) link_list.add("Hello") link_list.add(3.8) link_list.add(2, 1) print(link_list.remove(5)) print(link_list.find(2)) print(link_list.find(3.8)) print(link_list.find("Hello"))