Advent of Code 2019 🤯 (יום 6)

תגיות: ,

שרשור Advent of Code יום 1 נחל הצלחה גדולה, וצלחנו גם את ימים 2 , 3, 4 ו־5. בואו נתקדם :slight_smile:

אני מניח שהאתגר הזה ישאר פה לפחות ליומיים שלושה, אז קחו את הזמן :slight_smile:
ואם לא הספקתם לפתור את הימים הקודמים – לא חובה, אבל לכו על זה! אלו תרגילים נחמדים מאוד שישפרו את היכולות שלכם מאוד.

אז קדימה, פרסמו פה את הפתרונות שלכם ליום השישי של Advent of Code!

2 לייקים
1

2

לייק 1

מכאן ההשראה לעץ פילוגנטי? :palm_tree:
:star2: :star2:

חלק 1 ו-2
#day 6

def get_puzzle_input(puzzle):
    orbit_map = {}
    with open(puzzle, "r") as orbits:
        for orbit in orbits.readlines():
            center, around = orbit.replace("\n","").split(")")
            orbit_map[around] = center
    return orbit_map


def direct_indirect_orbits(puzzle):
    orbit_map = get_puzzle_input(puzzle)
    indirect = 0
    for orb in orbit_map:
        while orbit_map[orb] in orbit_map:
            indirect += 1
            orb = orbit_map[orb]
    return indirect + len(orbit_map)


def me_and_san(puzzle):
    path_create = set()
    orbit_map = get_puzzle_input(puzzle)
    counter = 0
    for orb in ["YOU", "SAN"]:
        while orbit_map[orb] in orbit_map:
            if orbit_map[orb] in path_create:
                path_create.remove(orbit_map[orb])
            else:
                path_create.add(orbit_map[orb])
            orb = orbit_map[orb]
    return len(path_create)

        

print(direct_indirect_orbits("resources//day6.txt"))  # part 1
print(me_and_san("resources//day6.txt"))  # part 2
2 לייקים

כן :slightly_smiling_face:

לייק 1

קצת בעיכוב, המחשב שלי בתקלה :frowning:

Advent of Code, Day 6
# Advent of Code, Day 6
def get_inputs(path):
   """Create a dictionary of planets and their center.
   
   Args:
       path (str): The source file path.

   Returns:
       A dictionary of planets and their center as values.
   
   Raises:
       FileNotFoundError: If the file path is invalid.
   """
   with open(path, 'r') as file:
       orbits = file.read().splitlines()
       orbits = map(lambda o: o.split(")"), orbits)
       return {planet: center for center, planet in orbits}


def count_orbits(path):
   """Count the number of direct and indirect orbits.
   
   Args:
       path (str): The source file path.

   Returns:
       The number of orbits.
   
   Raises:
       FileNotFoundError: If the file path is invalid.
   """
   orbits = get_inputs(path)
   count = 0
   for planet in orbits:
       while orbits.get(planet) != 'COM':
           planet = orbits[planet]
           count += 1
   return count + len(orbits)


def get_orbits(orbits, planet):
   """Create a list of orbits from planet to COM.
   
   Args:
       orbits (dict): The orbits map.
       planet (str): The planet to start from.

   Returns:
       List of planets from planet to COM based on the orbits map.
   """
   if planet == "COM":
       return ["COM"]
   return [planet] + get_orbits(orbits, orbits[planet])


def get_orbital_distance(path):
   """Calculate the orbital distance between YOU and SAN.
   
   Args:
       path (str): The source file path.

   Returns:
       The orbital distance between YOU and SAN.
   
   Raises:
       FileNotFoundError: If the file path is invalid.
   """
   orbits = get_inputs(path)
   count = 0
   you_orbits = set(get_orbits(orbits, "YOU")[1:])
   san_orbits = set(get_orbits(orbits, "SAN")[1:])
   return len(you_orbits ^ san_orbits)
           
   

print(count_orbits("input.txt"))
print(get_orbital_distance("input.txt"))
לייק 1
הלך לי הסופש
FILE_LOCATION = 'resources/input.txt'

def get_info():
    with open(FILE_LOCATION, 'r') as file:
        orbits = file.read().split()
    all_orbits = {}
    for couple in orbits:
        star, orbitstar = couple.split(')')
        if star in all_orbits:
            all_orbits[star].append(orbitstar)
        else:
            all_orbits[star] = [orbitstar]
    return all_orbits


def path(all_orbits, star, lvl=0):
    orbitstars = all_orbits.get(star)
    if orbitstars is None:
        return 0
    lvl += 1
    if len(orbitstars) == 1:
        return path(all_orbits, orbitstars[0], lvl) + lvl
    else:
        return path(all_orbits, orbitstars[0], lvl) + path(all_orbits, orbitstars[1], lvl) + lvl * 2


def get_key(all_orbits, star):
    for orbit, orbitstars  in all_orbits.items():
        if star in orbitstars:
            return orbit

def find_split_points(all_orbits, position):
    counter = 0
    split_points = {}
    while position != 'COM':
        counter += 1
        position = get_key(all_orbits, position)
        if len(all_orbits.get(position)) > 1:
            split_points[position] = counter
    return split_points

def find_shortest_path(all_orbits, x, y):
    point_x = find_split_points(all_orbits, get_key(all_orbits, x))
    point_y = find_split_points(all_orbits, get_key(all_orbits, y))
    shortest = len(all_orbits)

    for key, value in point_y.items():
        if key in point_x:
            s = value + point_x.get(key)
            if s < shortest:
                shortest = s
    return shortest


all_orbits = get_info()
path(all_orbits, 'COM')
find_shortest_path(all_orbits, 'YOU', 'SAN')

לא עשיתי פיין טיונינג בשל מגבלות זמן :slight_smile:

2 לייקים

מחר אסגור את האתגר :slight_smile:

שני החלקים
def build_orbit_map(orbit_list):
    orbit_map = {}
    for orbit in orbit_list:
        mass, obj = orbit.split(')')
        if mass not in orbit_map:
            orbit_map[mass] = [obj]
        else:
            orbit_map[mass].append(obj)
    return orbit_map


def get_distance(orbit_map, mass):
    distance = 0
    temp = orbit_map.copy()
    if mass == 'COM':
        return 0
    for obj in orbit_map:
        if mass in orbit_map[obj]:
            temp.pop(obj)
            distance += 1 + get_distance(temp, obj)
    return distance


def count_orbits(orbit_map):
    count = 0
    orbits = [mass for orbits in orbit_map.values() for mass in orbits]
    for mass in orbits:
        count += get_distance(orbit_map, mass)
    return count


def get_orbit_path(orbit_map, mass, path=None):
    if path is None:
        path = set()
    for obj in orbit_map:
        if mass in orbit_map[obj]:
            path.add(obj)
            path.update(get_orbit_path(orbit_map, obj, path))
    return path


def count_transfers(orbit_map, origin, destination):
    return len(get_orbit_path(orbit_map, origin) ^ get_orbit_path(orbit_map, destination))


with open('Day 6.txt', 'r') as file_handler:
    challenge_input = file_handler.read()

orbit_list = challenge_input.split()
orbit_map = build_orbit_map(orbit_list)

print(count_orbits(orbit_map))
print(count_transfers(orbit_map, 'YOU', 'SAN'))
לייק 1
הפתרון שלי
import functools
from collections import defaultdict


def get_input():
    with open('input.txt', 'r') as challenge_input:
        return map(str.strip, challenge_input.readlines())


def parse_input(inputs):
    planets = defaultdict(list)
    for line in inputs:
        planet, _, orbiter = line.partition(')')
        planets[orbiter].append(planet)
    return planets


def map_flatter(starmap):
    @functools.lru_cache(maxsize=None)
    def flat_map(start):
        if start not in starmap:
            return []
        stars = [s for star in starmap[start] for s in flat_map(star)]
        return starmap[start] + stars
    return {star: flat_map(star) for star in starmap}


# Part 1
data = parse_input(get_input())
flat_orbiters = map_flatter(data)
print(sum(map(len, flat_orbiters.values())))

# Part 2
print(len(set(flat_orbiters['YOU']) ^ set(flat_orbiters['SAN'])))

?? מה זה הדבר הזה … ??

השטרודל הזה נקרא decorator.
תכל’ס לא חייבים אותו שם כדי שזה יעבוד.
ספציפית השורה הזו גורמת לזה שפייתון יבנה מאחורי הקלעים מילון, שבו הוא זוכר איזה פרמטרים הועברו ל־flat_map (אלו המפתחות של המילון) ומה הוחזר כל פרמטר שהועבר (אלו ה־values של המילון).
פעם הבאה כש־flat_map נקראת עם פרמטר שכבר קיים כמפתח במילון, במקום להריץ את הפונקציה מחדש הוא פשוט יחזיר את מה ששמור לו ב־value של אותו key.
הקונספט עצמו נקרא memoization, המימוש הספציפי נקרא lru cache. זה גורם לדברים לזוז יותר מהר :slight_smile:

2 לייקים

שמתי לב עכשיו שיש תגית advent-of-code אבל לא כל הפוסטים נמצאים בה, וחבל.
מודה שלא ממש הבנתי אם להוסיף תגיות לפוסטים קיימים זה משהו שאני יכול לעשות או לא, אז אגלגל את זה הלאה. :upside_down_face:

תודה, טופל :slight_smile:

אנחנו נלמד את הנושאים האלה, של הדקורייטורס והממורייז ?

לפי הסילבוס בשבוע הבא :pray:

3 לייקים

יש היתרון מסויים בשימוש ב str.partition ע ל str.split ?
כי כאילו במקרה הזה אתה צריך ליצור את המשתנה הריק _

תמיד מחזיר 3 חלקים, גם אם מצא/לא מצא/מצא יותר מ־1

2 לייקים

בגדול אם נתון לנו שיש שלשה חלקים אז אפשר להניח שימוש ב split בגדול נכון ?

:man_shrugging:
החיים האמיתיים יותר קשוחים מתרגילים שאנשים מנקים עבורם את הקלט, אני בכ"מ תמיד לוקח משנה זהירות

3 לייקים

אחד הכיפיים!

חלקים 1 ו- 2
def get_input(path):
    with open(path, 'r') as puzzle_input:
        return puzzle_input.readlines()


def get_son_and_father(relationship):
    return relationship.split(')')[1].strip(), relationship.split(')')[0].strip()


def insert_into_relationships(relationships, father, son):
    if father not in relationships:
        relationships[father] =  {'Father': None, 'Sons': [son], 'Depth': 0}
    else:
        relationships[father]['Sons'].append(son)

    if son not in relationships:
        relationships[son] =  {'Father': father, 'Sons': [], 'Depth': 0}
    else:
        relationships[son]['Father'] = father

    return relationships


def get_relationships(puzzle_input):
    relationships = {}
    for relationship in puzzle_input:
        son, father = get_son_and_father(relationship)
        relationships = insert_into_relationships(relationships, father, son)
    return relationships


def traverse(relationships, root, depth):
    count = 0
    if not root:
        return

    sons = relationships[root]['Sons']
    for son in sons:
        relationships[son]['Depth'] = depth + 1
        traverse(relationships, son, depth + 1)

    return relationships


def get_path_to_root(relationships, x):
    obj = x
    path = set()
    while obj != 'COM':
        obj = relationships[obj]['Father']
        path.add(obj)
    return path


def part_one(traversal_result):
    res = 0
    for item in traversal_result:
        res += traversal_result[item]['Depth']
    return res


def part_two(relationships, first, second):
    path_from_you_to_root = get_path_to_root(relationships, first)
    path_from_san_to_root = get_path_to_root(relationships, second)
    part_two_result = len(path_from_you_to_root ^ path_from_san_to_root)
    return part_two_result


def main():
    puzzle_input = get_input('input.txt')
    relationships = get_relationships(puzzle_input)
    traversal_result = traverse(relationships, 'COM', 0)
    part_one_result = part_one(traversal_result)
    print(f'part_one_result: {part_one_result}')
    part_two_result = part_two(relationships, 'YOU', 'SAN')
    print(f'part_two_result: {part_two_result}')


main()
לייק 1