aoc_1224.slt 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. # https://github.com/MaterializeInc/advent-of-code-2023/blob/main/week1/aoc_1224.md
  10. mode cockroach
  11. statement ok
  12. CREATE TABLE input (input TEXT);
  13. # no input data
  14. query T multiline
  15. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
  16. WITH MUTUALLY RECURSIVE
  17. lines(r INT, line TEXT) AS (
  18. SELECT r, regexp_split_to_array(input, '\n')[r] as line
  19. FROM input, generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) r
  20. ),
  21. observation(r INT, x NUMERIC, y NUMERIC, z NUMERIC, dx NUMERIC, dy NUMERIC, dz NUMERIC) AS (
  22. SELECT
  23. r,
  24. trim(',' FROM regexp_split_to_array(line, ' ')[1])::NUMERIC,
  25. trim(',' FROM regexp_split_to_array(line, ' ')[2])::NUMERIC,
  26. trim(',' FROM regexp_split_to_array(line, ' ')[3])::NUMERIC,
  27. trim(',' FROM regexp_split_to_array(line, ' ')[5])::NUMERIC,
  28. trim(',' FROM regexp_split_to_array(line, ' ')[6])::NUMERIC,
  29. trim(',' FROM regexp_split_to_array(line, ' ')[7])::NUMERIC
  30. FROM
  31. lines
  32. ),
  33. -- Part one: for each pair, solve for a future (x,y) intersection of their traced paths.
  34. -- https://en.wikipedia.org/wiki/Line–line_intersection#Given_two_points_on_each_line_segment
  35. meeting(r1 INT, r2 INT, x NUMERIC, y NUMERIC, t1 NUMERIC, t2 NUMERIC) AS (
  36. SELECT
  37. o1.r,
  38. o2.r,
  39. o1.x + o1.dx * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  40. o1.y + o1.dy * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  41. (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  42. (((o2.x - o1.x) * o1.dy) - ((o2.y - o1.y) * o1.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx)
  43. FROM observation o1, observation o2
  44. WHERE o1.dx * o2.dy != o1.dy * o2.dx
  45. AND o1.r < o2.r
  46. ),
  47. part1(part1 BIGINT) AS (
  48. SELECT COUNT(*)
  49. FROM meeting
  50. WHERE t1 >= 0
  51. AND t2 >= 0
  52. AND x BETWEEN 200000000000000 AND 400000000000000
  53. AND y BETWEEN 200000000000000 AND 400000000000000
  54. ),
  55. -- Part two: find an initial x, y, z, dx, dy, dz such that you intersect every observation in the future.
  56. -- Hypothesize dx and dy, subtract them, and assses the number of coincidences.
  57. hypotheses(r INT, x NUMERIC, y NUMERIC, dx NUMERIC, dy NUMERIC, ox NUMERIC, oy NUMERIC) AS (
  58. SELECT
  59. r, x, y, dx - ox, dy - oy, ox, oy
  60. FROM
  61. observation,
  62. generate_series(-500, 500) ox,
  63. generate_series(-500, 500) oy
  64. WHERE r < 10
  65. AND 5 * (ox + 21) = 16 * (oy + 39) -- derived from input pair with same (dx, dy).
  66. ),
  67. coincidence(r1 INT, r2 INT, x NUMERIC, y NUMERIC, ox NUMERIC, oy NUMERIC) AS (
  68. SELECT
  69. o1.r,
  70. o2.r,
  71. o1.x + o1.dx * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  72. o1.y + o1.dy * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  73. o1.ox,
  74. o1.oy
  75. FROM hypotheses o1, hypotheses o2
  76. WHERE o1.dx * o2.dy != o1.dy * o2.dx
  77. AND o1.r < o2.r
  78. AND o1.ox = o2.ox
  79. AND o1.oy = o2.oy
  80. ),
  81. hypotheses_xz(r INT, x NUMERIC, y NUMERIC, dx NUMERIC, dy NUMERIC, ox NUMERIC, oy NUMERIC) AS (
  82. SELECT
  83. r, x, z, dx - ox, dz - oz, ox, oz
  84. FROM
  85. observation,
  86. generate_series(-117, -117) ox,
  87. generate_series(-500, 500) oz
  88. WHERE r < 10
  89. ),
  90. coincidence_xz(r1 INT, r2 INT, x NUMERIC, y NUMERIC, ox NUMERIC, oy NUMERIC) AS (
  91. SELECT
  92. o1.r,
  93. o2.r,
  94. o1.x + o1.dx * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  95. o1.y + o1.dy * (((o2.x - o1.x) * o2.dy) - ((o2.y - o1.y) * o2.dx)) / (o1.dx * o2.dy - o1.dy * o2.dx),
  96. o1.ox,
  97. o1.oy
  98. FROM hypotheses_xz o1, hypotheses_xz o2
  99. WHERE o1.dx * o2.dy != o1.dy * o2.dx
  100. AND o1.r < o2.r
  101. AND o1.ox = o2.ox
  102. AND o1.oy = o2.oy
  103. ),
  104. potato (x INT) AS ( SELECT 1 )
  105. -- SELECT x, y, ox, oy, COUNT(*) FROM coincidence GROUP BY x, y, ox, oy HAVING COUNT(*) > 1;
  106. SELECT x, y, ox, oy, COUNT(*) FROM coincidence_xz GROUP BY x, y, ox, oy HAVING COUNT(*) > 1;
  107. ----
  108. Explained Query:
  109. With
  110. cte l0 =
  111. ArrangeBy keys=[[#5{oy}]] // { arity: 6 }
  112. Project (#0..=#2, #6, #8, #7) // { arity: 6 }
  113. Map ((#3{dx} - -117), integer_to_numeric(#5{oz}), (#4{dz} - #7)) // { arity: 9 }
  114. CrossJoin type=differential // { arity: 6 }
  115. implementation
  116. %0[×]if » %1[×]if
  117. ArrangeBy keys=[[]] // { arity: 5 }
  118. Project (#1, #3..=#6) // { arity: 5 }
  119. Filter (#1{r} < 10) // { arity: 7 }
  120. Map (regexp_split_to_array[" ", case_insensitive=false](array_index(regexp_split_to_array["\n", case_insensitive=false](#0{input}), integer_to_bigint(#1{r}))), text_to_numeric(btrim(array_index(#2, 1), ",")), text_to_numeric(btrim(array_index(#2, 3), ",")), text_to_numeric(btrim(array_index(#2, 5), ",")), text_to_numeric(btrim(array_index(#2, 7), ","))) // { arity: 7 }
  121. FlatMap generate_series(1, (regexp_split_to_array["\n", case_insensitive=false](#0{input}) array_length 1), 1) // { arity: 2 }
  122. ReadStorage materialize.public.input // { arity: 1 }
  123. ArrangeBy keys=[[]] // { arity: 1 }
  124. Constant // { arity: 1 }
  125. total_rows (diffs absed): 1001
  126. first_rows:
  127. - (0)
  128. - (-1)
  129. - (1)
  130. - (2)
  131. - (3)
  132. - (4)
  133. - (5)
  134. - (6)
  135. - (7)
  136. - (8)
  137. - (9)
  138. - (10)
  139. - (11)
  140. - (12)
  141. - (13)
  142. - (14)
  143. - (15)
  144. - (16)
  145. - (17)
  146. - (18)
  147. Return // { arity: 5 }
  148. Project (#0, #1, #4, #2, #3{count}) // { arity: 5 }
  149. Filter (#3{count} > 1) // { arity: 5 }
  150. Map (-117) // { arity: 5 }
  151. Reduce group_by=[(#0{x} + ((#2{dx} * (((#5{x} - #0{x}) * #8{dy}) - ((#6{y} - #1{y}) * #7{dx}))) / ((#2{dx} * #8{dy}) - (#3{dy} * #7{dx})))), (#1{y} + ((#3{dy} * (((#5{x} - #0{x}) * #8{dy}) - ((#6{y} - #1{y}) * #7{dx}))) / ((#2{dx} * #8{dy}) - (#3{dy} * #7{dx})))), #4] aggregates=[count(*)] // { arity: 4 }
  152. Project (#1..=#5, #7..=#10) // { arity: 9 }
  153. Filter (#0{r} < #6{r}) AND ((#3{dx} * #10{dy}) != (#4{dy} * #9{dx})) // { arity: 12 }
  154. Join on=(#5{oy} = #11{oy}) type=differential // { arity: 12 }
  155. implementation
  156. %0:l0[#5{oy}]K » %1:l0[#5{oy}]K
  157. Get l0 // { arity: 6 }
  158. Get l0 // { arity: 6 }
  159. Source materialize.public.input
  160. Target cluster: quickstart
  161. EOF