main.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import os, sys
  2. task_dir = os.path.dirname(__file__)
  3. sys.path.append(f"{task_dir}/..")
  4. import numpy as np
  5. from get_tasks import get_input, generate_readme, check_example, bench
  6. from itertools import takewhile
  7. from scipy.signal import convolve2d
  8. from numpy.lib.stride_tricks import sliding_window_view
  9. def parse(input, test=False):
  10. if test:
  11. code = (
  12. "".join([line for line in takewhile(lambda l: len(l) > 0, input)])
  13. .replace("#", "1")
  14. .replace(".", "0")
  15. )
  16. code = np.array(list(code), dtype=int)
  17. image = np.array([list(line) for line in input[8:]])
  18. else:
  19. code = np.array(list(input[0].replace("#", "1").replace(".", "0")), dtype=int)
  20. image = np.array([list(line) for line in input[2:]])
  21. image[image == "."] = 0
  22. image[image == "#"] = 1
  23. return image.astype(int), code
  24. def naive_virgin_enhance_image(image, code, steps):
  25. for step in range(steps):
  26. match code[0]:
  27. case 0: pad = 0; val = 0
  28. case _: pad = step % 2; val = 1 - pad
  29. sp = 3 if step == 0 else 1
  30. enhance_image = np.pad(image, sp, constant_values=pad)
  31. enhanced_image = np.full_like(enhance_image, val, dtype=int)
  32. for i in range(enhance_image.shape[0] - 2):
  33. for j in range(enhance_image.shape[1] - 2):
  34. win = enhance_image[i : i + 3, j : j + 3]
  35. enhanced_image[i + 1, j + 1] = code[
  36. win.flatten()[0] * 256 + np.packbits(win.flatten()[1:])
  37. ]
  38. image = enhanced_image
  39. return image
  40. def true_vectorized_chad_enhance_image(image, code, steps, outside=0, pad_size=2):
  41. for _ in range(steps):
  42. image = np.pad(image, pad_size, constant_values=outside)
  43. windows = sliding_window_view(image, (3, 3))
  44. windows = windows.reshape(*windows.shape[:2], 9)
  45. codes = windows[:, :, 0] * 256 + np.packbits(windows[:, :, 1:]).reshape(
  46. windows.shape[:2]
  47. )
  48. image = code[codes]
  49. outside = code[outside * 511]
  50. return image
  51. def literally_genious_conv_enhance_image(image, code, steps, outside=0):
  52. kernel = np.array(
  53. [
  54. [ 1, 2, 4],
  55. [ 8, 16, 32],
  56. [64,128,256]
  57. ]
  58. )
  59. for _ in range(steps):
  60. image = code[convolve2d(image, kernel, fillvalue=outside)]
  61. outside = code[outside*511]
  62. return image
  63. @bench
  64. def part1(input, test=False, method='conv_kernel'):
  65. image, code = parse(input, test)
  66. if method == 'conv_kernel':
  67. image = literally_genious_conv_enhance_image(image, code, steps=2)
  68. elif method == 'vectorized':
  69. image = true_vectorized_chad_enhance_image(image, code, steps=2)
  70. else:
  71. image = naive_virgin_enhance_image(image, code, steps=2)
  72. print("The answer of part1 is:", image.sum())
  73. @bench
  74. def part2(input, test=False, method='conv_kernel'):
  75. image, code = parse(input, test)
  76. if method == 'conv_kernel':
  77. image = literally_genious_conv_enhance_image(image, code, steps=50)
  78. elif method == 'vectorized':
  79. image = true_vectorized_chad_enhance_image(image, code, steps=50)
  80. else:
  81. image = naive_virgin_enhance_image(image, code, steps=50)
  82. print("The answer of part2 is:", image.sum())
  83. if __name__ == "__main__":
  84. input, example = get_input(task_dir, 20)
  85. part1(example, True)
  86. part2(example, True)
  87. part1(input, method='conv_kernel')
  88. part2(input, method='conv_kernel')
  89. generate_readme(task_dir, 20)