14_defrag.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #!/usr/bin/env python3
  2. from functools import reduce
  3. from operator import xor
  4. def knot_round(nums, lengths, pos=0, skip=0, n=256):
  5. for length in lengths:
  6. for i in range(length // 2):
  7. left = (pos + i) % n
  8. right = (pos + length - i - 1) % n
  9. nums[left], nums[right] = nums[right], nums[left]
  10. pos = (pos + length + skip) % n
  11. skip = (skip + 1) % n
  12. return pos, skip
  13. def knot_hash(inp, rounds=64):
  14. lengths = tuple(map(ord, inp)) + (17, 31, 73, 47, 23)
  15. pos = skip = 0
  16. sparse = list(range(256))
  17. for r in range(rounds):
  18. pos, skip = knot_round(sparse, lengths, pos, skip)
  19. dense = 0
  20. for i in range(0, 256, 16):
  21. group = reduce(xor, sparse[i:i + 16])
  22. dense = (dense << 8) | group
  23. return dense
  24. def hamming_weight(n):
  25. return sum((n >> i) & 1 for i in range(n.bit_length()))
  26. def used_squares(key):
  27. return sum(hamming_weight(knot_hash(f'{key}-{i}')) for i in range(128))
  28. def used_regions(key):
  29. grid = []
  30. for y in range(128):
  31. h = knot_hash(f'{key}-{y}')
  32. grid.extend(-((h >> i) & 1) for i in range(128))
  33. def spread(x, y, region):
  34. i = y * 128 + x
  35. if grid[i] == -1:
  36. grid[i] = region
  37. if x > 0:
  38. spread(x - 1, y, region)
  39. if x < 127:
  40. spread(x + 1, y, region)
  41. if y > 0:
  42. spread(x, y - 1, region)
  43. if y < 127:
  44. spread(x, y + 1, region)
  45. region = 1
  46. for i, cell in enumerate(grid):
  47. if cell == -1:
  48. y, x = divmod(i, 128)
  49. spread(x, y, region)
  50. region += 1
  51. return region - 1
  52. print(used_squares('ljoxqyyw'))
  53. print(used_regions('ljoxqyyw'))