Quest 7: Namegraph

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

Link to participate: https://everybody.codes/

you are viewing a single comment's thread
view the rest of the comments
[โ€“] 1 point 11 months ago*

Python

# pairwise helps picking consecutive values easier
#   [A,B,C,D] -> [AB, BC, CD]
from itertools import pairwise

# returns names and dict[str, set[str]] of allowed transitions
def parse_data(data: str):
    transition_map = {}
    lines = data.splitlines()

    for rule_str in lines[2:]:
        before, after = rule_str.split(" > ")
        transition_map[before] = set(after.split(','))

    names = lines[0].split(',')
    return names, transition_map

# checks if name is valid according to transition_map
def is_name_valid(transition_map: dict[str, set[str]], name: str) -> bool:
    for a, b in pairwise(name):
        if a not in transition_map or b not in transition_map[a]:
            return False
    return True


def part1(data: str):
    names, transition_map = parse_data(data)
    for name in names:
        if is_name_valid(transition_map, name):
            return name

# <assert snipped>

def part2(data: str):
    ans = 0
    names, transition_map = parse_data(data)
    for i, name in enumerate(names):
        if is_name_valid(transition_map, name):
            ans += i + 1
    return ans

# <assert snipped>

def part3(data: str):
    prefixes, transition_map = parse_data(data)

    # remove prefixes that are sub-prefixes of others
    #   to avoid double counting
    superset_prefixes = []
    for i, p1 in enumerate(prefixes):
        for j, p2 in enumerate(prefixes):
            if i != j and p1.startswith(p2):
                break
        else:
            # no break -> p1 is not a sub-prefix
            superset_prefixes.append(p1)

    variants = 0
    for prefix in superset_prefixes:
        if not is_name_valid(transition_map, prefix):
            continue
        
        # DFS to count all valid name extensions
        stack = [(prefix[-1], len(prefix))]
        while stack:
            prev, name_len = stack.pop()
            if name_len >= 7:
                variants += 1
            if name_len == 11:
                continue

            for next_letter in transition_map.get(prev, []):
                stack.append((next_letter, name_len + 1))
        
    return variants

# <assert snipped>
  • source