t | def extract_classes(code): | t | def extract_classes(code): |
| result = {} | | result = {} |
| for statement in code.splitlines(): | | for statement in code.splitlines(): |
| statement = statement.strip() | | statement = statement.strip() |
| if not statement.startswith('class '): | | if not statement.startswith('class '): |
| continue | | continue |
| class_name_end = statement.find('(') | | class_name_end = statement.find('(') |
| if class_name_end == -1: | | if class_name_end == -1: |
| class_name_end = statement.find(':') | | class_name_end = statement.find(':') |
| class_name = statement[6:class_name_end].strip() | | class_name = statement[6:class_name_end].strip() |
| if '(' in statement: | | if '(' in statement: |
| parents_start = statement.find('(') + 1 | | parents_start = statement.find('(') + 1 |
| parents_end = statement.find(')') | | parents_end = statement.find(')') |
| parents = statement[parents_start:parents_end].strip() | | parents = statement[parents_start:parents_end].strip() |
| parents_list = [parent.strip() for parent in parents.split(' | | parents_list = [parent.strip() for parent in parents.split(' |
| ,')] if parents else [] | | ,')] if parents else [] |
| else: | | else: |
| parents_list = [] | | parents_list = [] |
| result[class_name] = parents_list | | result[class_name] = parents_list |
| return result | | return result |
| | | |
| def validate_hierarchy(classes): | | def validate_hierarchy(classes): |
| | | |
| def resolve_mro(class_name, resolved, unresolved): | | def resolve_mro(class_name, resolved, unresolved): |
| if class_name in resolved: | | if class_name in resolved: |
| return resolved[class_name] | | return resolved[class_name] |
| if class_name in unresolved: | | if class_name in unresolved: |
| raise ValueError('Cyclic dependency detected') | | raise ValueError('Cyclic dependency detected') |
| unresolved.add(class_name) | | unresolved.add(class_name) |
| bases = classes.get(class_name, []) | | bases = classes.get(class_name, []) |
| mro = [class_name] + combine_mros([resolve_mro(base, resolved, u | | mro = [class_name] + combine_mros([resolve_mro(base, resolved, u |
| nresolved) for base in bases] + [bases]) | | nresolved) for base in bases] + [bases]) |
| resolved[class_name] = mro | | resolved[class_name] = mro |
| unresolved.remove(class_name) | | unresolved.remove(class_name) |
| return mro | | return mro |
| | | |
| def combine_mros(sequences): | | def combine_mros(sequences): |
| result = [] | | result = [] |
| while any(sequences): | | while any(sequences): |
| for seq in sequences: | | for seq in sequences: |
| if not seq: | | if not seq: |
| continue | | continue |
| candidate = seq[0] | | candidate = seq[0] |
| if all((candidate not in s[1:] for s in sequences)): | | if all((candidate not in s[1:] for s in sequences)): |
| result.append(candidate) | | result.append(candidate) |
| for s in sequences: | | for s in sequences: |
| if s and s[0] == candidate: | | if s and s[0] == candidate: |
| s.pop(0) | | s.pop(0) |
| break | | break |
| else: | | else: |
| raise ValueError('Invalid MRO') | | raise ValueError('Invalid MRO') |
| return result | | return result |
| resolved = {} | | resolved = {} |
| for class_name in classes: | | for class_name in classes: |
| resolve_mro(class_name, resolved, set()) | | resolve_mro(class_name, resolved, set()) |
| return True | | return True |
| input_code = '' | | input_code = '' |
| while (line := input().strip()): | | while (line := input().strip()): |
| input_code += line + '\n' | | input_code += line + '\n' |
| try: | | try: |
| class_structure = extract_classes(input_code) | | class_structure = extract_classes(input_code) |
| print('Yes' if validate_hierarchy(class_structure) else 'No') | | print('Yes' if validate_hierarchy(class_structure) else 'No') |
| except ValueError: | | except ValueError: |
| print('No') | | print('No') |