{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Advent of Code 2017\n",
    "\n",
    "## December 2nd\n",
    "\n",
    "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",
    "\n",
    "For example, given the following spreadsheet:\n",
    "\n",
    "    5 1 9 5\n",
    "    7 5 3\n",
    "    2 4 6 8\n",
    "\n",
    "* The first row's largest and smallest values are 9 and 1, and their difference is 8.\n",
    "* The second row's largest and smallest values are 7 and 3, and their difference is 4.\n",
    "* The third row's difference is 6.\n",
    "\n",
    "In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18.\n",
    "\n",
    "I'll assume the input is a Joy sequence of sequences of integers.\n",
    "\n",
    "    [[5 1 9 5]\n",
    "     [7 5 3]\n",
    "     [2 4 6 8]]\n",
    "\n",
    "So, obviously, the initial form will be a `step` function:\n",
    "\n",
    "    AoC2017.2 == 0 swap [F +] step\n",
    "\n",
    "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:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": []
    }
   ],
   "source": [
    "[maxmin [max] [min] cleave] inscribe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 1"
     ]
    }
   ],
   "source": [
    "[1 2 3] maxmin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then `F` just does that then subtracts the min from the max:\n",
    "\n",
    "    F == maxmin -\n",
    "\n",
    "So:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 1"
     ]
    }
   ],
   "source": [
    "[AoC2017.2 [maxmin - +] step_zero] inscribe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18"
     ]
    }
   ],
   "source": [
    "clear\n",
    "\n",
    "[[5 1 9 5]\n",
    " [7 5 3]\n",
    " [2 4 6 8]] AoC2017.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "...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",
    "\n",
    "For example, given the following spreadsheet:\n",
    "\n",
    "    5 9 2 8\n",
    "    9 4 7 3\n",
    "    3 8 6 5\n",
    "\n",
    "*    In the first row, the only two numbers that evenly divide are 8 and 2; the result of this division is 4.\n",
    "*    In the second row, the two numbers are 9 and 3; the result is 3.\n",
    "*    In the third row, the result is 2.\n",
    "\n",
    "In this example, the sum of the results would be 4 + 3 + 2 = 9.\n",
    "\n",
    "What is the sum of each row's result in your puzzle input?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": []
    }
   ],
   "source": [
    "clear"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2 5 8 9]"
     ]
    }
   ],
   "source": [
    "[5 9 2 8] sort"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5 8 9] [2 mod not]"
     ]
    }
   ],
   "source": [
    "uncons swap [mod not] cons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[false true false]"
     ]
    }
   ],
   "source": [
    "map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false true false"
     ]
    }
   ],
   "source": [
    "step"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "false true false"
     ]
    }
   ],
   "source": [
    "[P 2 mod not] inscribe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4 5 6 7]"
     ]
    }
   ],
   "source": [
    "clear\n",
    "[4 5 6 7]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[true false true false]"
     ]
    }
   ],
   "source": [
    "[P] map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[] [4 5 6 7]"
     ]
    }
   ],
   "source": [
    "[] swap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[] 4"
     ]
    }
   ],
   "source": [
    "first"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4]"
     ]
    }
   ],
   "source": [
    "[P][swons][pop]ifte"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4] 5"
     ]
    }
   ],
   "source": [
    "5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4]"
     ]
    }
   ],
   "source": [
    "[P][swons][pop]ifte"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4 5 6 7]"
     ]
    }
   ],
   "source": [
    "clear\n",
    "[4 5 6 7]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6 4]"
     ]
    }
   ],
   "source": [
    "[] swap [[P][swons][pop]ifte] step"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "           [...] [P] filter\n",
    "    -----------------------------------------\n",
    "       [] [...] [[P][swons][pop]ifte] step\n",
    "\n",
    "But that `[]` could get in the way of `P`, no?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8 5 2] [9 divmod] [8 5 2]"
     ]
    }
   ],
   "source": [
    "uncons [swap [divmod] cons] dupdip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "    [9 8 5 2] uncons [swap [divmod] cons F] dupdip G\n",
    "      [8 5 2]            [9 divmod]      F [8 5 2] G\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                      • [8 5 2] [9 divmod] [uncons swap] dip dup [i not] dip\n",
      "                              [8 5 2] • [9 divmod] [uncons swap] dip dup [i not] dip\n",
      "                   [8 5 2] [9 divmod] • [uncons swap] dip dup [i not] dip\n",
      "     [8 5 2] [9 divmod] [uncons swap] • dip dup [i not] dip\n",
      "                              [8 5 2] • uncons swap [9 divmod] dup [i not] dip\n",
      "                              8 [5 2] • swap [9 divmod] dup [i not] dip\n",
      "                              [5 2] 8 • [9 divmod] dup [i not] dip\n",
      "                   [5 2] 8 [9 divmod] • dup [i not] dip\n",
      "        [5 2] 8 [9 divmod] [9 divmod] • [i not] dip\n",
      "[5 2] 8 [9 divmod] [9 divmod] [i not] • dip\n",
      "                   [5 2] 8 [9 divmod] • i not [9 divmod]\n",
      "                              [5 2] 8 • 9 divmod not [9 divmod]\n",
      "                            [5 2] 8 9 • divmod not [9 divmod]\n",
      "                            [5 2] 1 1 • not [9 divmod]\n",
      "                        [5 2] 1 False • [9 divmod]\n",
      "             [5 2] 1 False [9 divmod] • \n"
     ]
    }
   ],
   "source": [
    "V('[8 5 2] [9 divmod] [uncons swap] dip dup [i not] dip')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tricky\n",
    "\n",
    "Let's think.\n",
    "\n",
    "Given a *sorted* sequence (from highest to lowest) we want to \n",
    "* for head, tail in sequence\n",
    "    * for term in tail:\n",
    "        * check if the head % term == 0\n",
    "            * if so compute head / term and terminate loop\n",
    "            * else continue"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### So we want a `loop` I think\n",
    "\n",
    "    [a b c d] True [Q] loop\n",
    "    [a b c d] Q    [Q] loop\n",
    "\n",
    "`Q` should either leave the result and False, or the `rest` and True.\n",
    "\n",
    "       [a b c d] Q\n",
    "    -----------------\n",
    "        result 0\n",
    "\n",
    "       [a b c d] Q\n",
    "    -----------------\n",
    "        [b c d] 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This suggests that `Q` should start with:\n",
    "\n",
    "    [a b c d] uncons dup roll<\n",
    "    [b c d] [b c d] a\n",
    "\n",
    "Now we just have to `pop` it if we don't need it.\n",
    "\n",
    "    [b c d] [b c d] a [P] [T] [cons] app2 popdd [E] primrec\n",
    "    [b c d] [b c d] [a P] [a T]                 [E] primrec\n",
    "\n",
    "-------------------\n",
    "\n",
    "    w/ Q == [% not] [T] [F] primrec\n",
    "\n",
    "            [a b c d] uncons\n",
    "            a [b c d] tuck\n",
    "    [b c d] a [b c d] uncons\n",
    "    [b c d] a b [c d] roll>\n",
    "    [b c d] [c d] a b Q\n",
    "    [b c d] [c d] a b [% not] [T] [F] primrec\n",
    "\n",
    "    [b c d] [c d] a b T\n",
    "    [b c d] [c d] a b / roll> popop 0\n",
    "\n",
    "    [b c d] [c d] a b F                   Q\n",
    "    [b c d] [c d] a b pop swap uncons ... Q\n",
    "    [b c d] [c d] a       swap uncons ... Q\n",
    "    [b c d] a [c d]            uncons ... Q\n",
    "    [b c d] a c [d]                   roll> Q\n",
    "    [b c d] [d] a c Q\n",
    "\n",
    "    Q == [% not] [/ roll> popop 0] [pop swap uncons roll>] primrec\n",
    "    \n",
    "    uncons tuck uncons roll> Q"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8 5 3 2] [9 swap] [9 % not]\n"
     ]
    }
   ],
   "source": [
    "J('[8 5 3 2] 9 [swap] [% not] [cons] app2 popdd')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "-------------------\n",
    "\n",
    "            [a b c d] uncons\n",
    "            a [b c d] tuck\n",
    "    [b c d] a [b c d] [not] [popop 1] [Q] ifte\n",
    "\n",
    "    [b c d] a [] popop 1\n",
    "    [b c d] 1\n",
    "\n",
    "    [b c d] a [b c d] Q \n",
    "\n",
    "\n",
    "       a [...] Q\n",
    "    ---------------\n",
    "       result 0\n",
    "\n",
    "       a [...] Q\n",
    "    ---------------\n",
    "           1\n",
    "\n",
    "\n",
    "    w/ Q == [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
    "\n",
    "\n",
    "\n",
    "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
    "    a [b c d]  first % not\n",
    "    a b % not\n",
    "    a%b not\n",
    "    bool(a%b)\n",
    "\n",
    "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
    "    a [b c d]                first / 0\n",
    "    a b / 0\n",
    "    a/b 0\n",
    "\n",
    "    a [b c d] [first % not] [first / 0] [rest [not] [popop 1]]   [ifte]\n",
    "    a [b c d]                            rest [not] [popop 1] [Q] ifte\n",
    "    a [c d]                                   [not] [popop 1] [Q] ifte\n",
    "    a [c d]                                   [not] [popop 1] [Q] ifte\n",
    "\n",
    "    a [c d] [not] [popop 1] [Q] ifte\n",
    "    a [c d]  not\n",
    "\n",
    "    a [] popop 1\n",
    "    1\n",
    "\n",
    "    a [c d] Q\n",
    "\n",
    "\n",
    "    uncons tuck [first % not] [first / 0] [rest [not] [popop 1]] [ifte]\n",
    "    \n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### I finally sat down with a piece of paper and blocked it out.\n",
    "\n",
    "First, I made a function `G` that expects a number and a sequence of candidates and return the result or zero:\n",
    "\n",
    "       n [...] G\n",
    "    ---------------\n",
    "        result\n",
    "\n",
    "       n [...] G\n",
    "    ---------------\n",
    "           0\n",
    "\n",
    "It's a recursive function that conditionally executes the recursive part of its recursive branch\n",
    "\n",
    "    [Pg] [E] [R1 [Pi] [T]] [ifte] genrec\n",
    "\n",
    "The recursive branch is the else-part of the inner `ifte`:\n",
    "\n",
    "    G == [Pg] [E] [R1 [Pi] [T]]   [ifte] genrec\n",
    "      == [Pg] [E] [R1 [Pi] [T] [G] ifte] ifte\n",
    "\n",
    "But this is in hindsight.  Going forward I derived:\n",
    "\n",
    "    G == [first % not]\n",
    "         [first /]\n",
    "         [rest [not] [popop 0]]\n",
    "         [ifte] genrec\n",
    "\n",
    "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",
    "\n",
    "    n [m ...] rest [not] [popop 0] [G] ifte\n",
    "    n [...]        [not] [popop 0] [G] ifte\n",
    "\n",
    "This `ifte` guards against empty sequences and returns zero in that case, otherwise it executes `G`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "define('G [first % not] [first /] [rest [not] [popop 0]] [ifte] genrec')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "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",
    "\n",
    "       n [...] p find-result\n",
    "    ---------------------------\n",
    "              result\n",
    "\n",
    "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",
    "\n",
    "    find-result == [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec\n",
    "\n",
    "    n [...] p [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec\n",
    "\n",
    "The base-case is trivial, return the (non-zero) result.  The recursive branch...\n",
    "\n",
    "    n [...] p roll< popop uncons [G] nullary find-result\n",
    "    [...] p n       popop uncons [G] nullary find-result\n",
    "    [...]                 uncons [G] nullary find-result\n",
    "    m [..]                       [G] nullary find-result\n",
    "    m [..] p                                 find-result\n",
    "\n",
    "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`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "define('find-result [0 >] [roll> popop] [roll< popop uncons [G] nullary] tailrec')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.0\n"
     ]
    }
   ],
   "source": [
    "J('[11 9 8 7 3 2] 0 tuck find-result')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "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."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "define('prep-row sort reverse 0 tuck')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can define our program."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "define('AoC20017.2.extra [prep-row find-result +] step_zero')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.0\n"
     ]
    }
   ],
   "source": [
    "J('''\n",
    "\n",
    "[[5 9 2 8]\n",
    " [9 4 7 3]\n",
    " [3 8 6 5]] AoC20017.2.extra\n",
    "\n",
    "''')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Joypy",
   "language": "",
   "name": "thun"
  },
  "language_info": {
   "file_extension": ".joy",
   "mimetype": "text/plain",
   "name": "Joy"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
