aoc_1218.slt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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_1218.md
  10. mode cockroach
  11. statement ok
  12. CREATE TABLE input (input TEXT);
  13. statement ok
  14. INSERT INTO input VALUES (
  15. 'R 1 (#53d732)
  16. L 5 (#292431)
  17. U 6 (#4c7272)
  18. L 9 (#49ace3)
  19. U 3 (#7b94e6)
  20. R 1 (#5579d4)
  21. L 9 (#1d7886)
  22. U 3 (#171219)
  23. R 9 (#45fa39)
  24. R 11 (#222422)
  25. U 6 (#91c869)
  26. L 8 (#7581c5)
  27. U 9 (#46aab5)
  28. R 9 (#6f72a5)
  29. L 7 (#42abb1)');
  30. query II
  31. WITH MUTUALLY RECURSIVE
  32. lines(r INT, line TEXT) AS (
  33. SELECT r, regexp_split_to_array(input, '\n')[r] as line
  34. FROM input, generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) r
  35. ),
  36. split1(r INT, dr INT, dc INT, steps INT) AS (
  37. SELECT
  38. r,
  39. CASE WHEN regexp_split_to_array(line, ' ')[1] = 'U' THEN -1
  40. WHEN regexp_split_to_array(line, ' ')[1] = 'D' THEN 1
  41. ELSE 0
  42. END,
  43. CASE WHEN regexp_split_to_array(line, ' ')[1] = 'L' THEN -1
  44. WHEN regexp_split_to_array(line, ' ')[1] = 'R' THEN 1
  45. ELSE 0
  46. END,
  47. regexp_split_to_array(line, ' ')[2]::INT
  48. FROM lines
  49. ),
  50. -- Part 1 is prefix sum followed by area calculations.
  51. -- We'll brute force the prefix sum part, and use the
  52. -- "trapezoid formula", summing + and - contributions
  53. -- as the path moves around.
  54. path1(r1 INT, c1 INT, r2 INT, c2 INT, rounds INT) AS (
  55. SELECT 0, 0, 0, 0, 1
  56. UNION
  57. SELECT
  58. path1.r2,
  59. path1.c2,
  60. path1.r2 + split1.dr * split1.steps,
  61. path1.c2 + split1.dc * split1.steps,
  62. path1.rounds + 1
  63. FROM path1, split1
  64. WHERE path1.rounds = split1.r
  65. ),
  66. -- The area carved by the path, plus half a unit of area
  67. -- for each path step, plus 4 * (1/4) units for the net
  68. -- four 90 degree turns.
  69. part1(part1 BIGINT) AS (
  70. SELECT
  71. ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path1)) / 2
  72. + (SELECT SUM(steps) FROM split1) / 2
  73. + 1
  74. ),
  75. -- Part 2 changes how we parse each line to give long paths.
  76. split2(r INT, dr INT, dc INT, steps INT) AS (
  77. SELECT
  78. r,
  79. CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '3' THEN -1
  80. WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '1' THEN 1
  81. ELSE 0
  82. END,
  83. CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '2' THEN -1
  84. WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '0' THEN 1
  85. ELSE 0
  86. END,
  87. 256 * 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 0)
  88. + 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 1)
  89. + get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 2)
  90. FROM lines
  91. ),
  92. path2(r1 BIGINT, c1 BIGINT, r2 BIGINT, c2 BIGINT, rounds INT) AS (
  93. SELECT 0, 0, 0, 0, 1
  94. UNION
  95. SELECT
  96. path2.r2,
  97. path2.c2,
  98. path2.r2 + split2.dr * split2.steps,
  99. path2.c2 + split2.dc * split2.steps,
  100. path2.rounds + 1
  101. FROM path2, split2
  102. WHERE path2.rounds = split2.r
  103. ),
  104. -- The area carved by the path, plus half a unit of area
  105. -- for each path step, plus 4 * (1/4) units for the net
  106. -- four 90 degree turns.
  107. part2(part2 BIGINT) AS (
  108. SELECT
  109. ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path2)) / 2
  110. + (SELECT SUM(steps) FROM split2) / 2
  111. + 1
  112. )
  113. SELECT * FROM part1, part2;
  114. ----
  115. 73 34133752459
  116. query T multiline
  117. EXPLAIN OPTIMIZED PLAN WITH(humanized expressions, arity, join implementations) AS VERBOSE TEXT FOR
  118. WITH MUTUALLY RECURSIVE
  119. lines(r INT, line TEXT) AS (
  120. SELECT r, regexp_split_to_array(input, '\n')[r] as line
  121. FROM input, generate_series(1, array_length(regexp_split_to_array(input, '\n'), 1)) r
  122. ),
  123. split1(r INT, dr INT, dc INT, steps INT) AS (
  124. SELECT
  125. r,
  126. CASE WHEN regexp_split_to_array(line, ' ')[1] = 'U' THEN -1
  127. WHEN regexp_split_to_array(line, ' ')[1] = 'D' THEN 1
  128. ELSE 0
  129. END,
  130. CASE WHEN regexp_split_to_array(line, ' ')[1] = 'L' THEN -1
  131. WHEN regexp_split_to_array(line, ' ')[1] = 'R' THEN 1
  132. ELSE 0
  133. END,
  134. regexp_split_to_array(line, ' ')[2]::INT
  135. FROM lines
  136. ),
  137. -- Part 1 is prefix sum followed by area calculations.
  138. -- We'll brute force the prefix sum part, and use the
  139. -- "trapezoid formula", summing + and - contributions
  140. -- as the path moves around.
  141. path1(r1 INT, c1 INT, r2 INT, c2 INT, rounds INT) AS (
  142. SELECT 0, 0, 0, 0, 1
  143. UNION
  144. SELECT
  145. path1.r2,
  146. path1.c2,
  147. path1.r2 + split1.dr * split1.steps,
  148. path1.c2 + split1.dc * split1.steps,
  149. path1.rounds + 1
  150. FROM path1, split1
  151. WHERE path1.rounds = split1.r
  152. ),
  153. -- The area carved by the path, plus half a unit of area
  154. -- for each path step, plus 4 * (1/4) units for the net
  155. -- four 90 degree turns.
  156. part1(part1 BIGINT) AS (
  157. SELECT
  158. ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path1)) / 2
  159. + (SELECT SUM(steps) FROM split1) / 2
  160. + 1
  161. ),
  162. -- Part 2 changes how we parse each line to give long paths.
  163. split2(r INT, dr INT, dc INT, steps INT) AS (
  164. SELECT
  165. r,
  166. CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '3' THEN -1
  167. WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '1' THEN 1
  168. ELSE 0
  169. END,
  170. CASE WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '2' THEN -1
  171. WHEN substring(regexp_split_to_array(line, ' ')[3], 8, 1) = '0' THEN 1
  172. ELSE 0
  173. END,
  174. 256 * 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 0)
  175. + 256 * get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 1)
  176. + get_byte(decode('0' || substring(regexp_split_to_array(line, ' ')[3], 3, 5), 'hex'), 2)
  177. FROM lines
  178. ),
  179. path2(r1 BIGINT, c1 BIGINT, r2 BIGINT, c2 BIGINT, rounds INT) AS (
  180. SELECT 0, 0, 0, 0, 1
  181. UNION
  182. SELECT
  183. path2.r2,
  184. path2.c2,
  185. path2.r2 + split2.dr * split2.steps,
  186. path2.c2 + split2.dc * split2.steps,
  187. path2.rounds + 1
  188. FROM path2, split2
  189. WHERE path2.rounds = split2.r
  190. ),
  191. -- The area carved by the path, plus half a unit of area
  192. -- for each path step, plus 4 * (1/4) units for the net
  193. -- four 90 degree turns.
  194. part2(part2 BIGINT) AS (
  195. SELECT
  196. ABS((SELECT SUM((r1 + r2) * (c1 - c2)) FROM path2)) / 2
  197. + (SELECT SUM(steps) FROM split2) / 2
  198. + 1
  199. )
  200. SELECT * FROM part1, part2;
  201. ----
  202. Explained Query:
  203. With
  204. cte l0 =
  205. Project (#1, #2) // { arity: 2 }
  206. Map (array_index(regexp_split_to_array["\n", case_insensitive=false](#0{input}), integer_to_bigint(#1{r}))) // { arity: 3 }
  207. FlatMap generate_series(1, (regexp_split_to_array["\n", case_insensitive=false](#0{input}) array_length 1), 1) // { arity: 2 }
  208. ReadStorage materialize.public.input // { arity: 1 }
  209. cte l1 =
  210. Reduce aggregates=[sum(#0{steps})] // { arity: 1 }
  211. Project (#2) // { arity: 1 }
  212. Map (text_to_integer(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 2))) // { arity: 3 }
  213. Get l0 // { arity: 2 }
  214. cte l2 =
  215. Union // { arity: 1 }
  216. Get l1 // { arity: 1 }
  217. Map (null) // { arity: 1 }
  218. Union // { arity: 0 }
  219. Negate // { arity: 0 }
  220. Project () // { arity: 0 }
  221. Get l1 // { arity: 1 }
  222. Constant // { arity: 0 }
  223. - ()
  224. Return // { arity: 2 }
  225. With Mutually Recursive
  226. cte l3 =
  227. Distinct project=[#0..=#4] // { arity: 5 }
  228. Union // { arity: 5 }
  229. Project (#0, #1, #7..=#9) // { arity: 5 }
  230. Map ((#0{r2} + (#4{dr} * #6{steps})), (#1{c2} + (#5{dc} * #6{steps})), (#2{rounds} + 1)) // { arity: 10 }
  231. Join on=(#2{rounds} = #3{r}) type=differential // { arity: 7 }
  232. implementation
  233. %0:l3[#2{rounds}]K » %1:l0[#0{r}]K
  234. ArrangeBy keys=[[#2{rounds}]] // { arity: 3 }
  235. Project (#2..=#4) // { arity: 3 }
  236. Get l3 // { arity: 5 }
  237. ArrangeBy keys=[[#0{r}]] // { arity: 4 }
  238. Project (#0, #4..=#6) // { arity: 4 }
  239. Map (regexp_split_to_array[" ", case_insensitive=false](#1{line}), array_index(#2, 1), case when (#3 = "U") then -1 else case when ("D" = array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 1)) then 1 else 0 end end, case when (#3 = "L") then -1 else case when ("R" = array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 1)) then 1 else 0 end end, text_to_integer(array_index(#2, 2))) // { arity: 7 }
  240. Get l0 // { arity: 2 }
  241. Constant // { arity: 5 }
  242. - (0, 0, 0, 0, 1)
  243. cte l4 =
  244. Reduce aggregates=[sum(((#0{r1} + #2{r2}) * (#1{c1} - #3{c2})))] // { arity: 1 }
  245. Project (#0..=#3) // { arity: 4 }
  246. Get l3 // { arity: 5 }
  247. cte l5 =
  248. Union // { arity: 1 }
  249. Get l4 // { arity: 1 }
  250. Map (null) // { arity: 1 }
  251. Union // { arity: 0 }
  252. Negate // { arity: 0 }
  253. Project () // { arity: 0 }
  254. Get l4 // { arity: 1 }
  255. Constant // { arity: 0 }
  256. - ()
  257. cte l6 =
  258. Distinct project=[#0..=#4] // { arity: 5 }
  259. Union // { arity: 5 }
  260. Project (#0, #1, #7..=#9) // { arity: 5 }
  261. Map ((#0{r2} + integer_to_bigint((#4{dr} * #6{steps}))), (#1{c2} + integer_to_bigint((#5{dc} * #6{steps}))), (#2{rounds} + 1)) // { arity: 10 }
  262. Join on=(#2{rounds} = #3{r}) type=differential // { arity: 7 }
  263. implementation
  264. %0:l6[#2{rounds}]K » %1:l0[#0{r}]K
  265. ArrangeBy keys=[[#2{rounds}]] // { arity: 3 }
  266. Project (#2..=#4) // { arity: 3 }
  267. Get l6 // { arity: 5 }
  268. ArrangeBy keys=[[#0{r}]] // { arity: 4 }
  269. Project (#0, #4, #5, #7) // { arity: 4 }
  270. Map (array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), substr(#2, 8, 1), case when (#3 = "3") then -1 else case when ("1" = substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 8, 1)) then 1 else 0 end end, case when (#3 = "2") then -1 else case when ("0" = substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 8, 1)) then 1 else 0 end end, decode(("0" || substr(#2, 3, 5)), "hex"), (((65536 * get_byte(#6, 0)) + (256 * get_byte(#6, 1))) + get_byte(#6, 2))) // { arity: 8 }
  271. Get l0 // { arity: 2 }
  272. Constant // { arity: 5 }
  273. - (0, 0, 0, 0, 1)
  274. Return // { arity: 2 }
  275. With
  276. cte l7 =
  277. Reduce aggregates=[sum(((#0{r1} + #2{r2}) * (#1{c1} - #3{c2})))] // { arity: 1 }
  278. Project (#0..=#3) // { arity: 4 }
  279. Get l6 // { arity: 5 }
  280. cte l8 =
  281. Union // { arity: 1 }
  282. Get l7 // { arity: 1 }
  283. Map (null) // { arity: 1 }
  284. Union // { arity: 0 }
  285. Negate // { arity: 0 }
  286. Project () // { arity: 0 }
  287. Get l7 // { arity: 1 }
  288. Constant // { arity: 0 }
  289. - ()
  290. cte l9 =
  291. Reduce aggregates=[sum(#0{steps})] // { arity: 1 }
  292. Project (#3) // { arity: 1 }
  293. Map (decode(("0" || substr(array_index(regexp_split_to_array[" ", case_insensitive=false](#1{line}), 3), 3, 5)), "hex"), (((65536 * get_byte(#2, 0)) + (256 * get_byte(#2, 1))) + get_byte(#2, 2))) // { arity: 4 }
  294. Get l0 // { arity: 2 }
  295. cte l10 =
  296. Union // { arity: 1 }
  297. Get l9 // { arity: 1 }
  298. Map (null) // { arity: 1 }
  299. Union // { arity: 0 }
  300. Negate // { arity: 0 }
  301. Project () // { arity: 0 }
  302. Get l9 // { arity: 1 }
  303. Constant // { arity: 0 }
  304. - ()
  305. Return // { arity: 2 }
  306. Project (#4, #5) // { arity: 2 }
  307. Map ((((abs(#0{sum}) / 2) + (#1{sum} / 2)) + 1), numeric_to_bigint((((abs(#2{sum}) / 2) + bigint_to_numeric((#3{sum} / 2))) + 1))) // { arity: 6 }
  308. CrossJoin type=delta // { arity: 4 }
  309. implementation
  310. %0 » %1[×]U » %2[×]U » %3[×]U
  311. %1 » %0[×]U » %2[×]U » %3[×]U
  312. %2 » %0[×]U » %1[×]U » %3[×]U
  313. %3 » %0[×]U » %1[×]U » %2[×]U
  314. ArrangeBy keys=[[]] // { arity: 1 }
  315. Union // { arity: 1 }
  316. Get l5 // { arity: 1 }
  317. Map (null) // { arity: 1 }
  318. Union // { arity: 0 }
  319. Negate // { arity: 0 }
  320. Project () // { arity: 0 }
  321. Get l5 // { arity: 1 }
  322. Constant // { arity: 0 }
  323. - ()
  324. ArrangeBy keys=[[]] // { arity: 1 }
  325. Union // { arity: 1 }
  326. Get l2 // { arity: 1 }
  327. Map (null) // { arity: 1 }
  328. Union // { arity: 0 }
  329. Negate // { arity: 0 }
  330. Project () // { arity: 0 }
  331. Get l2 // { arity: 1 }
  332. Constant // { arity: 0 }
  333. - ()
  334. ArrangeBy keys=[[]] // { arity: 1 }
  335. Union // { arity: 1 }
  336. Get l8 // { arity: 1 }
  337. Map (null) // { arity: 1 }
  338. Union // { arity: 0 }
  339. Negate // { arity: 0 }
  340. Project () // { arity: 0 }
  341. Get l8 // { arity: 1 }
  342. Constant // { arity: 0 }
  343. - ()
  344. ArrangeBy keys=[[]] // { arity: 1 }
  345. Union // { arity: 1 }
  346. Get l10 // { arity: 1 }
  347. Map (null) // { arity: 1 }
  348. Union // { arity: 0 }
  349. Negate // { arity: 0 }
  350. Project () // { arity: 0 }
  351. Get l10 // { arity: 1 }
  352. Constant // { arity: 0 }
  353. - ()
  354. Source materialize.public.input
  355. Target cluster: quickstart
  356. EOF