16_dance.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env python3
  2. import sys
  3. from functools import partial
  4. def init():
  5. # 16 4-bit dancers in a 64-bit number
  6. return 0xfedcba9876543210
  7. def spin(n, dancers):
  8. nbits = 64 - n * 4
  9. mask_first = (1 << nbits) - 1
  10. mask_last = (1 << 64) - (1 << nbits)
  11. first = dancers & mask_first
  12. last = dancers & mask_last
  13. return (first << (64 - nbits)) | (last >> nbits)
  14. def swap_indices(i, j, dancers):
  15. if j < i:
  16. return swap_indices(j, i, dancers)
  17. a = dancers & (0xf << (4 * i))
  18. b = dancers & (0xf << (4 * j))
  19. rest = dancers ^ a ^ b
  20. diff = 4 * (j - i)
  21. return rest | (a << diff) | (b >> diff)
  22. def swap_values(a, b, dancers):
  23. return swap_indices(index(a, dancers), index(b, dancers), dancers)
  24. def index(ident, dancers):
  25. i = 0
  26. while dancers & 0xf != ident:
  27. dancers >>= 4
  28. i += 1
  29. return i
  30. def stringify(dancers):
  31. s = ''
  32. for i in range(16):
  33. ident = dancers & 0xf
  34. dancers >>= 4
  35. s += chr(ident + ord('a'))
  36. return s
  37. def parse(f):
  38. for move in f.readline().rstrip().split(','):
  39. if move[0] == 's':
  40. yield partial(spin, int(move[1:]))
  41. elif move[0] == 'x':
  42. i, j = move[1:].split('/')
  43. yield partial(swap_indices, int(i), int(j))
  44. elif move[0] == 'p':
  45. a, b = move[1:].split('/')
  46. yield partial(swap_values, ord(a) - ord('a'), ord(b) - ord('a'))
  47. def move_all(moves, dancers):
  48. for move in moves:
  49. dancers = move(dancers)
  50. return dancers
  51. def dance_many_times(dance, times):
  52. dancers = init()
  53. seen = set()
  54. patlen = 0
  55. while dancers not in seen:
  56. seen.add(dancers)
  57. dancers = dance(dancers)
  58. patlen += 1
  59. for i in range(times % patlen):
  60. dancers = dance(dancers)
  61. return dancers
  62. # part 1
  63. dance = partial(move_all, list(parse(sys.stdin)))
  64. print(stringify(dance(init())))
  65. # part 2
  66. print(stringify(dance_many_times(dance, 1000000000)))