solution.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/python3
  2. import sys
  3. def pattern_str(pattern):
  4. return '\n'.join(map(''.join, pattern))
  5. def rotate(pattern):
  6. return list(map(list, zip(*reversed(pattern))))
  7. def shift(pattern):
  8. shifted = True
  9. while shifted:
  10. shifted = False
  11. for y in range(len(pattern)):
  12. for x in range(len(pattern[y]) - 1, 0, -1):
  13. if pattern[y][x] == '.' and pattern[y][x - 1] == 'O':
  14. pattern[y][x], pattern[y][x - 1] = pattern[y][x - 1], pattern[y][x]
  15. shifted = True
  16. return pattern
  17. def part1():
  18. print('part 1')
  19. pattern = list(map(list, map(str.strip, sys.stdin.readlines())))
  20. print(f'pattern:\n{pattern_str(pattern)}')
  21. rotated = rotate(pattern)
  22. print(f'rotated:\n{pattern_str(rotated)}')
  23. shift(rotated)
  24. back = rotate(rotated)
  25. print(f'shifted:\n{pattern_str(back)}')
  26. total = 0
  27. for i, row in enumerate(back):
  28. total += sum([i + 1 for c in row if c == 'O'])
  29. print(f'total is {total}')
  30. def pattern_hash(pattern):
  31. #return sum([sum([ord(pattern[k][l]) * l * k for l in range(len(pattern[k]))]) for k in range(len(pattern))])
  32. return hash(tuple(([hash(tuple(row)) for row in pattern])))
  33. def part2():
  34. print('part 2')
  35. pattern = list(map(list, map(str.strip, sys.stdin.readlines())))
  36. #print(f'pattern:\n{pattern_str(pattern)}')
  37. cache = {}
  38. #patterns = {}
  39. for i in range(1000000000):
  40. for j in range(4):
  41. pattern = shift(rotate(pattern))
  42. hashed = pattern_hash(pattern)
  43. #print(f'cycle {i}: hash {hashed}')
  44. if hashed not in cache:
  45. cache[hashed] = i
  46. #patterns[hashed] = pattern
  47. else:
  48. break
  49. i += 1
  50. cache[hashed] += 1
  51. print(f'found repetition @{i} with hash {hashed} (previously occured @{cache[hashed]})')
  52. remaining = (1000000000 - cache[hashed]) % (i - cache[hashed])
  53. print(f'{remaining} cycles remaining')
  54. #print(f'first\n{pattern_str(patterns[hashed])}')
  55. #print(f'second\n{pattern_str(pattern)}')
  56. for i in range(remaining):
  57. for j in range(4):
  58. pattern = shift(rotate(pattern))
  59. total = 0
  60. # rotate upside down to compute easily
  61. pattern = rotate(rotate(pattern))
  62. for i, row in enumerate(pattern):
  63. total += sum([i + 1 for c in row if c == 'O'])
  64. print(f'total is {total}')
  65. if sys.argv[1] in '1':
  66. part1()
  67. else:
  68. part2()