19.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from itertools import product
  2. lines = []
  3. with open("19.input") as f:
  4. for line in f.readlines():
  5. lines.append(line.strip())
  6. rules = {}
  7. i = 0
  8. while lines[i] != "":
  9. [id, rule] = lines[i].split(":")
  10. if '"' in rule:
  11. rules[int(id)] = rule.strip().replace('"', "")
  12. i += 1
  13. continue
  14. alternatives = rule.strip().split("|")
  15. for j in range(0, len(alternatives)):
  16. alternatives[j] = [int(n) for n in alternatives[j].strip().split(" ")]
  17. rules[int(id)] = alternatives
  18. i += 1
  19. words = lines[i+1:]
  20. def matching_words(rule_id):
  21. rule = rules[rule_id]
  22. if type(rule) is str:
  23. return set(rule)
  24. words = set()
  25. for alt in rule:
  26. if len(alt) == 1:
  27. words = words.union(matching_words(alt[0]))
  28. elif len(alt) == 2:
  29. for (x, y) in product(matching_words(alt[0]), matching_words(alt[1])):
  30. words.add(x + y)
  31. else:
  32. print("Invalid length: ", len(alt))
  33. return words
  34. allowed_words = matching_words(0)
  35. matched_words = [word for word in words if word in allowed_words]
  36. print("Answer 1:", len(matched_words))
  37. special_42 = matching_words(42)
  38. special_31 = matching_words(31)
  39. def try_match(word):
  40. count_42 = 0
  41. count_31 = 0
  42. original_word = word
  43. while True:
  44. for special in special_42:
  45. if word.find(special) == 0:
  46. word = word[len(special):]
  47. count_42 += 1
  48. break
  49. else:
  50. break
  51. while True:
  52. for special in special_31:
  53. if word.find(special) == 0:
  54. word = word[len(special):]
  55. count_31 += 1
  56. break
  57. else:
  58. break
  59. # Must match the entire word
  60. if len(word) != 0:
  61. return False
  62. return count_31 >= 1 and count_42 >= count_31 + 1
  63. matched_words = [word for word in words if try_match(word)]
  64. print("Answer 2:", len(matched_words))