OSDN Git Service

Some work on docs.
[joypy/Thun.git] / docs / Advent_of_Code_2017_December_2nd.ipynb
1 {
2  "cells": [
3   {
4    "cell_type": "markdown",
5    "metadata": {},
6    "source": [
7     "# Advent of Code 2017\n",
8     "\n",
9     "## December 2nd\n",
10     "\n",
11     "For each row, determine the difference between the largest value and the smallest value; the checksum is the sum of all of these differences.\n",
12     "\n",
13     "For example, given the following spreadsheet:\n",
14     "\n",
15     "    5 1 9 5\n",
16     "    7 5 3\n",
17     "    2 4 6 8\n",
18     "\n",
19     "* The first row's largest and smallest values are 9 and 1, and their difference is 8.\n",
20     "* The second row's largest and smallest values are 7 and 3, and their difference is 4.\n",
21     "* The third row's difference is 6.\n",
22     "\n",
23     "In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18.\n",
24     "\n",
25     "I'll assume the input is a Joy sequence of sequences of integers.\n",
26     "\n",
27     "    [[5 1 9 5]\n",
28     "     [7 5 3]\n",
29     "     [2 4 6 8]]\n",
30     "\n",
31     "So, obviously, the initial form will be a `step` function:\n",
32     "\n",
33     "    AoC2017.2 == 0 swap [F +] step\n",
34     "\n",
35     "This function `F` must get the `max` and `min` of a row of numbers and subtract.  We can define a helper function `maxmin` which does this:"
36    ]
37   },
38   {
39    "cell_type": "code",
40    "execution_count": 1,
41    "metadata": {},
42    "outputs": [
43     {
44      "name": "stdout",
45      "output_type": "stream",
46      "text": []
47     }
48    ],
49    "source": [
50     "[maxmin [max] [min] cleave] inscribe"
51    ]
52   },
53   {
54    "cell_type": "code",
55    "execution_count": 2,
56    "metadata": {},
57    "outputs": [
58     {
59      "name": "stdout",
60      "output_type": "stream",
61      "text": [
62       "3 1"
63      ]
64     }
65    ],
66    "source": [
67     "[1 2 3] maxmin"
68    ]
69   },
70   {
71    "cell_type": "markdown",
72    "metadata": {},
73    "source": [
74     "Then `F` just does that then subtracts the min from the max:\n",
75     "\n",
76     "    F == maxmin -\n",
77     "\n",
78     "So:"
79    ]
80   },
81   {
82    "cell_type": "code",
83    "execution_count": 3,
84    "metadata": {},
85    "outputs": [
86     {
87      "name": "stdout",
88      "output_type": "stream",
89      "text": [
90       "3 1"
91      ]
92     }
93    ],
94    "source": [
95     "[AoC2017.2 [maxmin - +] step_zero] inscribe"
96    ]
97   },
98   {
99    "cell_type": "code",
100    "execution_count": 4,
101    "metadata": {},
102    "outputs": [
103     {
104      "name": "stdout",
105      "output_type": "stream",
106      "text": [
107       "18"
108      ]
109     }
110    ],
111    "source": [
112     "clear\n",
113     "\n",
114     "[[5 1 9 5]\n",
115     " [7 5 3]\n",
116     " [2 4 6 8]] AoC2017.2"
117    ]
118   },
119   {
120    "cell_type": "markdown",
121    "metadata": {},
122    "source": [
123     "...find the only two numbers in each row where one evenly divides the other - that is, where the result of the division operation is a whole number. They would like you to find those numbers on each line, divide them, and add up each line's result.\n",
124     "\n",
125     "For example, given the following spreadsheet:\n",
126     "\n",
127     "    5 9 2 8\n",
128     "    9 4 7 3\n",
129     "    3 8 6 5\n",
130     "\n",
131     "*    In the first row, the only two numbers that evenly divide are 8 and 2; the result of this division is 4.\n",
132     "*    In the second row, the two numbers are 9 and 3; the result is 3.\n",
133     "*    In the third row, the result is 2.\n",
134     "\n",
135     "In this example, the sum of the results would be 4 + 3 + 2 = 9.\n",
136     "\n",
137     "What is the sum of each row's result in your puzzle input?"
138    ]
139   },
140   {
141    "cell_type": "code",
142    "execution_count": 24,
143    "metadata": {},
144    "outputs": [
145     {
146      "name": "stdout",
147      "output_type": "stream",
148      "text": []
149     }
150    ],
151    "source": [
152     "clear"
153    ]
154   },
155   {
156    "cell_type": "code",
157    "execution_count": 25,
158    "metadata": {},
159    "outputs": [
160     {
161      "name": "stdout",
162      "output_type": "stream",
163      "text": [
164       "[2 5 8 9]"
165      ]
166     }
167    ],
168    "source": [
169     "[5 9 2 8] sort"
170    ]
171   },
172   {
173    "cell_type": "code",
174    "execution_count": 26,
175    "metadata": {},
176    "outputs": [
177     {
178      "name": "stdout",
179      "output_type": "stream",
180      "text": [
181       "[5 8 9] [2 mod not]"
182      ]
183     }
184    ],
185    "source": [
186     "uncons swap [mod not] cons"
187    ]
188   },
189   {
190    "cell_type": "code",
191    "execution_count": 23,
192    "metadata": {},
193    "outputs": [
194     {
195      "name": "stdout",
196      "output_type": "stream",
197      "text": [
198       "[false true false]"
199      ]
200     }
201    ],
202    "source": [
203     "map"
204    ]
205   },
206   {
207    "cell_type": "code",
208    "execution_count": 27,
209    "metadata": {},
210    "outputs": [
211     {
212      "name": "stdout",
213      "output_type": "stream",
214      "text": [
215       "false true false"
216      ]
217     }
218    ],
219    "source": [
220     "step"
221    ]
222   },
223   {
224    "cell_type": "code",
225    "execution_count": 28,
226    "metadata": {},
227    "outputs": [
228     {
229      "name": "stdout",
230      "output_type": "stream",
231      "text": [
232       "false true false"
233      ]
234     }
235    ],
236    "source": [
237     "[P 2 mod not] inscribe"
238    ]
239   },
240   {
241    "cell_type": "code",
242    "execution_count": 31,
243    "metadata": {},
244    "outputs": [
245     {
246      "name": "stdout",
247      "output_type": "stream",
248      "text": [
249       "[4 5 6 7]"
250      ]
251     }
252    ],
253    "source": [
254     "clear\n",
255     "[4 5 6 7]"
256    ]
257   },
258   {
259    "cell_type": "code",
260    "execution_count": 30,
261    "metadata": {},
262    "outputs": [
263     {
264      "name": "stdout",
265      "output_type": "stream",
266      "text": [
267       "[true false true false]"
268      ]
269     }
270    ],
271    "source": [
272     "[P] map"
273    ]
274   },
275   {
276    "cell_type": "code",
277    "execution_count": 32,
278    "metadata": {},
279    "outputs": [
280     {
281      "name": "stdout",
282      "output_type": "stream",
283      "text": [
284       "[] [4 5 6 7]"
285      ]
286     }
287    ],
288    "source": [
289     "[] swap"
290    ]
291   },
292   {
293    "cell_type": "code",
294    "execution_count": 33,
295    "metadata": {},
296    "outputs": [
297     {
298      "name": "stdout",
299      "output_type": "stream",
300      "text": [
301       "[] 4"
302      ]
303     }
304    ],
305    "source": [
306     "first"
307    ]
308   },
309   {
310    "cell_type": "code",
311    "execution_count": 34,
312    "metadata": {},
313    "outputs": [
314     {
315      "name": "stdout",
316      "output_type": "stream",
317      "text": [
318       "[4]"
319      ]
320     }
321    ],
322    "source": [
323     "[P][swons][pop]ifte"
324    ]
325   },
326   {
327    "cell_type": "code",
328    "execution_count": 35,
329    "metadata": {},
330    "outputs": [
331     {
332      "name": "stdout",
333      "output_type": "stream",
334      "text": [
335       "[4] 5"
336      ]
337     }
338    ],
339    "source": [
340     "5"
341    ]
342   },
343   {
344    "cell_type": "code",
345    "execution_count": 36,
346    "metadata": {},
347    "outputs": [
348     {
349      "name": "stdout",
350      "output_type": "stream",
351      "text": [
352       "[4]"
353      ]
354     }
355    ],
356    "source": [
357     "[P][swons][pop]ifte"
358    ]
359   },
360   {
361    "cell_type": "code",
362    "execution_count": null,
363    "metadata": {},
364    "outputs": [],
365    "source": []
366   },
367   {
368    "cell_type": "code",
369    "execution_count": 37,
370    "metadata": {},
371    "outputs": [
372     {
373      "name": "stdout",
374      "output_type": "stream",
375      "text": [
376       "[4 5 6 7]"
377      ]
378     }
379    ],
380    "source": [
381     "clear\n",
382     "[4 5 6 7]"
383    ]
384   },
385   {
386    "cell_type": "code",
387    "execution_count": 38,
388    "metadata": {},
389    "outputs": [
390     {
391      "name": "stdout",
392      "output_type": "stream",
393      "text": [
394       "[6 4]"
395      ]
396     }
397    ],
398    "source": [
399     "[] swap [[P][swons][pop]ifte] step"
400    ]
401   },
402   {
403    "cell_type": "markdown",
404    "metadata": {},
405    "source": [
406     "           [...] [P] filter\n",
407     "    -----------------------------------------\n",
408     "       [] [...] [[P][swons][pop]ifte] step\n",
409     "\n",
410     "But that `[]` could get in the way of `P`, no?"
411    ]
412   },
413   {
414    "cell_type": "code",
415    "execution_count": null,
416    "metadata": {},
417    "outputs": [],
418    "source": []
419   },
420   {
421    "cell_type": "code",
422    "execution_count": null,
423    "metadata": {},
424    "outputs": [],
425    "source": []
426   },
427   {
428    "cell_type": "code",
429    "execution_count": null,
430    "metadata": {},
431    "outputs": [],
432    "source": []
433   },
434   {
435    "cell_type": "code",
436    "execution_count": null,
437    "metadata": {},
438    "outputs": [],
439    "source": []
440   },
441   {
442    "cell_type": "code",
443    "execution_count": null,
444    "metadata": {},
445    "outputs": [],
446    "source": []
447   },
448   {
449    "cell_type": "code",
450    "execution_count": 9,
451    "metadata": {},
452    "outputs": [
453     {
454      "name": "stdout",
455      "output_type": "stream",
456      "text": [
457       "[8 5 2] [9 divmod] [8 5 2]"
458      ]
459     }
460    ],
461    "source": [
462     "uncons [swap [divmod] cons] dupdip"
463    ]
464   },
465   {
466    "cell_type": "markdown",
467    "metadata": {},
468    "source": [
469     "\n",
470     "    [9 8 5 2] uncons [swap [divmod] cons F] dupdip G\n",
471     "      [8 5 2]            [9 divmod]      F [8 5 2] G\n",
472     "\n"
473    ]
474   },
475   {
476    "cell_type": "code",
477    "execution_count": 8,
478    "metadata": {},
479    "outputs": [
480     {
481      "name": "stdout",
482      "output_type": "stream",
483      "text": [
484       "                                      â€¢ [8 5 2] [9 divmod] [uncons swap] dip dup [i not] dip\n",
485       "                              [8 5 2] â€¢ [9 divmod] [uncons swap] dip dup [i not] dip\n",
486       "                   [8 5 2] [9 divmod] â€¢ [uncons swap] dip dup [i not] dip\n",
487       "     [8 5 2] [9 divmod] [uncons swap] â€¢ dip dup [i not] dip\n",
488       "                              [8 5 2] â€¢ uncons swap [9 divmod] dup [i not] dip\n",
489       "                              8 [5 2] â€¢ swap [9 divmod] dup [i not] dip\n",
490       "                              [5 2] 8 â€¢ [9 divmod] dup [i not] dip\n",
491       "                   [5 2] 8 [9 divmod] â€¢ dup [i not] dip\n",
492       "        [5 2] 8 [9 divmod] [9 divmod] â€¢ [i not] dip\n",
493       "[5 2] 8 [9 divmod] [9 divmod] [i not] â€¢ dip\n",
494       "                   [5 2] 8 [9 divmod] â€¢ i not [9 divmod]\n",
495       "                              [5 2] 8 â€¢ 9 divmod not [9 divmod]\n",
496       "                            [5 2] 8 9 â€¢ divmod not [9 divmod]\n",
497       "                            [5 2] 1 1 â€¢ not [9 divmod]\n",
498       "                        [5 2] 1 False â€¢ [9 divmod]\n",
499       "             [5 2] 1 False [9 divmod] â€¢ \n"
500      ]
501     }
502    ],
503    "source": [
504     "V('[8 5 2] [9 divmod] [uncons swap] dip dup [i not] dip')"
505    ]
506   },
507   {
508    "cell_type": "markdown",
509    "metadata": {},
510    "source": [
511     "## Tricky\n",
512     "\n",
513     "Let's think.\n",
514     "\n",
515     "Given a *sorted* sequence (from highest to lowest) we want to \n",
516     "* for head, tail in sequence\n",
517     "    * for term in tail:\n",
518     "        * check if the head % term == 0\n",
519     "            * if so compute head / term and terminate loop\n",
520     "            * else continue"
521    ]
522   },
523   {
524    "cell_type": "markdown",
525    "metadata": {},
526    "source": [
527     "### So we want a `loop` I think\n",
528     "\n",
529     "    [a b c d] True [Q] loop\n",
530     "    [a b c d] Q    [Q] loop\n",
531     "\n",
532     "`Q` should either leave the result and False, or the `rest` and True.\n",
533     "\n",
534     "       [a b c d] Q\n",
535     "    -----------------\n",
536     "        result 0\n",
537     "\n",
538     "       [a b c d] Q\n",
539     "    -----------------\n",
540     "        [b c d] 1"
541    ]
542   },
543   {
544    "cell_type": "markdown",
545    "metadata": {},
546    "source": [
547     "This suggests that `Q` should start with:\n",
548     "\n",
549     "    [a b c d] uncons dup roll<\n",
550     "    [b c d] [b c d] a\n",
551     "\n",
552     "Now we just have to `pop` it if we don't need it.\n",
553     "\n",
554     "    [b c d] [b c d] a [P] [T] [cons] app2 popdd [E] primrec\n",
555     "    [b c d] [b c d] [a P] [a T]                 [E] primrec\n",
556     "\n",
557     "-------------------\n",
558     "\n",
559     "    w/ Q == [% not] [T] [F] primrec\n",
560     "\n",
561     "            [a b c d] uncons\n",
562     "            a [b c d] tuck\n",
563     "    [b c d] a [b c d] uncons\n",
564     "    [b c d] a b [c d] roll>\n",
565     "    [b c d] [c d] a b Q\n",
566     "    [b c d] [c d] a b [% not] [T] [F] primrec\n",
567     "\n",
568     "    [b c d] [c d] a b T\n",
569     "    [b c d] [c d] a b / roll> popop 0\n",
570     "\n",
571     "    [b c d] [c d] a b F                   Q\n",
572     "    [b c d] [c d] a b pop swap uncons ... Q\n",
573     "    [b c d] [c d] a       swap uncons ... Q\n",
574     "    [b c d] a [c d]            uncons ... Q\n",
575     "    [b c d] a c [d]                   roll> Q\n",
576     "    [b c d] [d] a c Q\n",
577     "\n",
578     "    Q == [% not] [/ roll> popop 0] [pop swap uncons roll>] primrec\n",
579     "    \n",
580     "    uncons tuck uncons roll> Q"
581    ]
582   },
583   {
584    "cell_type": "code",
585    "execution_count": 9,
586    "metadata": {},
587    "outputs": [
588     {
589      "name": "stdout",
590      "output_type": "stream",
591      "text": [
592       "[8 5 3 2] [9 swap] [9 % not]\n"
593      ]
594     }
595    ],
596    "source": [
597     "J('[8 5 3 2] 9 [swap] [% not] [cons] app2 popdd')"
598    ]
599   },
600   {
601    "cell_type": "markdown",
602    "metadata": {},
603    "source": [
604     "-------------------\n",
605     "\n",
606     "            [a b c d] uncons\n",
607     "            a [b c d] tuck\n",
608     "    [b c d] a [b c d] [not] [popop 1] [Q] ifte\n",
609     "\n",
610     "    [b c d] a [] popop 1\n",
611     "    [b c d] 1\n",
612     "\n",
613     "    [b c d] a [b c d] Q \n",
614     "\n",
615     "\n",
616     "       a [...] Q\n",
617     "    ---------------\n",
618     "       result 0\n",
619     "\n",
620     "       a [...] Q\n",
621     "    ---------------\n",
622     "           1\n",
623     "\n",
624     "\n",
625     "    w/ Q == [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
626     "\n",
627     "\n",
628     "\n",
629     "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
630     "    a [b c d]  first % not\n",
631     "    a b % not\n",
632     "    a%b not\n",
633     "    bool(a%b)\n",
634     "\n",
635     "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
636     "    a [b c d]                first / 0\n",
637     "    a b / 0\n",
638     "    a/b 0\n",
639     "\n",
640     "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]]   [ifte]\n",
641     "    a [b c d]                            rest [not] [popop 1] [Q] ifte\n",
642     "    a [c d]                                   [not] [popop 1] [Q] ifte\n",
643     "    a [c d]                                   [not] [popop 1] [Q] ifte\n",
644     "\n",
645     "    a [c d] [not] [popop 1] [Q] ifte\n",
646     "    a [c d]  not\n",
647     "\n",
648     "    a [] popop 1\n",
649     "    1\n",
650     "\n",
651     "    a [c d] Q\n",
652     "\n",
653     "\n",
654     "    uncons tuck [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
655     "    \n",
656     "    \n"
657    ]
658   },
659   {
660    "cell_type": "markdown",
661    "metadata": {},
662    "source": [
663     "### I finally sat down with a piece of paper and blocked it out.\n",
664     "\n",
665     "First, I made a function `G` that expects a number and a sequence of candidates and return the result or zero:\n",
666     "\n",
667     "       n [...] G\n",
668     "    ---------------\n",
669     "        result\n",
670     "\n",
671     "       n [...] G\n",
672     "    ---------------\n",
673     "           0\n",
674     "\n",
675     "It's a recursive function that conditionally executes the recursive part of its recursive branch\n",
676     "\n",
677     "    [Pg] [E] [R1 [Pi] [T]] [ifte] genrec\n",
678     "\n",
679     "The recursive branch is the else-part of the inner `ifte`:\n",
680     "\n",
681     "    G == [Pg] [E] [R1 [Pi] [T]]   [ifte] genrec\n",
682     "      == [Pg] [E] [R1 [Pi] [T] [G] ifte] ifte\n",
683     "\n",
684     "But this is in hindsight.  Going forward I derived:\n",
685     "\n",
686     "    G == [first % not]\n",
687     "         [first /]\n",
688     "         [rest [not] [popop 0]]\n",
689     "         [ifte] genrec\n",
690     "\n",
691     "The predicate detects if the `n` can be evenly divided by the `first` item in the list.  If so, the then-part returns the result.  Otherwise, we have:\n",
692     "\n",
693     "    n [m ...] rest [not] [popop 0] [G] ifte\n",
694     "    n [...]        [not] [popop 0] [G] ifte\n",
695     "\n",
696     "This `ifte` guards against empty sequences and returns zero in that case, otherwise it executes `G`."
697    ]
698   },
699   {
700    "cell_type": "code",
701    "execution_count": 10,
702    "metadata": {},
703    "outputs": [],
704    "source": [
705     "define('G [first % not] [first /] [rest [not] [popop 0]] [ifte] genrec')"
706    ]
707   },
708   {
709    "cell_type": "markdown",
710    "metadata": {},
711    "source": [
712     "Now we need a word that uses `G` on each (head, tail) pair of a sequence until it finds a (non-zero) result.  It's going to be designed to work on a stack that has some candidate `n`, a sequence of possible divisors, and a result that is zero to signal to continue (a non-zero value implies that it is the discovered result):\n",
713     "\n",
714     "       n [...] p find-result\n",
715     "    ---------------------------\n",
716     "              result\n",
717     "\n",
718     "It applies `G` using `nullary` because if it fails with one candidate it needs the list to get the next one (the list is otherwise consumed by `G`.)\n",
719     "\n",
720     "    find-result == [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec\n",
721     "\n",
722     "    n [...] p [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec\n",
723     "\n",
724     "The base-case is trivial, return the (non-zero) result.  The recursive branch...\n",
725     "\n",
726     "    n [...] p roll< popop uncons [G] nullary find-result\n",
727     "    [...] p n       popop uncons [G] nullary find-result\n",
728     "    [...]                 uncons [G] nullary find-result\n",
729     "    m [..]                       [G] nullary find-result\n",
730     "    m [..] p                                 find-result\n",
731     "\n",
732     "The puzzle states that the input is well-formed, meaning that we can expect a result before the row sequence empties and so do not need to guard the `uncons`."
733    ]
734   },
735   {
736    "cell_type": "code",
737    "execution_count": 11,
738    "metadata": {},
739    "outputs": [],
740    "source": [
741     "define('find-result [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec')"
742    ]
743   },
744   {
745    "cell_type": "code",
746    "execution_count": 12,
747    "metadata": {},
748    "outputs": [
749     {
750      "name": "stdout",
751      "output_type": "stream",
752      "text": [
753       "3.0\n"
754      ]
755     }
756    ],
757    "source": [
758     "J('[11 9 8 7 3 2] 0 tuck find-result')"
759    ]
760   },
761   {
762    "cell_type": "markdown",
763    "metadata": {},
764    "source": [
765     "In order to get the thing started, we need to `sort` the list in descending order, then prime the `find-result` function with a dummy candidate value and zero (\"continue\") flag."
766    ]
767   },
768   {
769    "cell_type": "code",
770    "execution_count": 13,
771    "metadata": {},
772    "outputs": [],
773    "source": [
774     "define('prep-row sort reverse 0 tuck')"
775    ]
776   },
777   {
778    "cell_type": "markdown",
779    "metadata": {},
780    "source": [
781     "Now we can define our program."
782    ]
783   },
784   {
785    "cell_type": "code",
786    "execution_count": 14,
787    "metadata": {},
788    "outputs": [],
789    "source": [
790     "define('AoC20017.2.extra [prep-row find-result +] step_zero')"
791    ]
792   },
793   {
794    "cell_type": "code",
795    "execution_count": 15,
796    "metadata": {},
797    "outputs": [
798     {
799      "name": "stdout",
800      "output_type": "stream",
801      "text": [
802       "9.0\n"
803      ]
804     }
805    ],
806    "source": [
807     "J('''\n",
808     "\n",
809     "[[5 9 2 8]\n",
810     " [9 4 7 3]\n",
811     " [3 8 6 5]] AoC20017.2.extra\n",
812     "\n",
813     "''')"
814    ]
815   }
816  ],
817  "metadata": {
818   "kernelspec": {
819    "display_name": "Joypy",
820    "language": "",
821    "name": "thun"
822   },
823   "language_info": {
824    "file_extension": ".joy",
825    "mimetype": "text/plain",
826    "name": "Joy"
827   }
828  },
829  "nbformat": 4,
830  "nbformat_minor": 2
831 }