Advent of Code 2017
===================

December 6th
------------

::

    [0 2 7 0] dup max

.. code:: ipython3

    from notebook_preamble import D, J, V, define

.. code:: ipython3

    J('[0 2 7 0] dup max')


.. parsed-literal::

    [0 2 7 0] 7


.. code:: ipython3

    from joy.library import SimpleFunctionWrapper
    from joy.utils.stack import list_to_stack
    
    
    @SimpleFunctionWrapper
    def index_of(stack):
        '''Given a sequence and a item, return the index of the item, or -1 if not found.
    
        E.g.:
    
           [a b c] a index_of
        ------------------------
                   0
    
           [a b c] d index_of
        ------------------------
                -1
    
        '''
        item, (sequence, stack) = stack
        i = 0
        while sequence:
            term, sequence = sequence
            if term == item:
                break
            i += 1
        else:
            i = -1
        return i, stack
    
    
    D['index_of'] = index_of

.. code:: ipython3

    J('[0 2 7 0] 7 index_of')


.. parsed-literal::

    2


.. code:: ipython3

    J('[0 2 7 0] 23 index_of')


.. parsed-literal::

    -1


Starting at ``index`` distribute ``count`` "blocks" to the "banks" in
the sequence.

::

    [...] count index distribute
    ----------------------------
               [...]

This seems like it would be a PITA to implement in Joypy...

.. code:: ipython3

    from joy.utils.stack import iter_stack, list_to_stack
    
    
    @SimpleFunctionWrapper
    def distribute(stack):
        '''Starting at index+1 distribute count "blocks" to the "banks" in the sequence.
    
        [...] count index distribute
        ----------------------------
                   [...]
    
        '''
        index, (count, (sequence, stack)) = stack
        assert count >= 0
        cheat = list(iter_stack(sequence))
        n = len(cheat)
        assert index < n
        cheat[index] = 0
        while count:
            index += 1
            index %= n
            cheat[index] += 1
            count -= 1
        return list_to_stack(cheat), stack
    
    
    D['distribute'] = distribute

.. code:: ipython3

    J('[0 2 7 0] dup max [index_of] nullary distribute')


.. parsed-literal::

    [2 4 1 2]


.. code:: ipython3

    J('[2 4 1 2] dup max [index_of] nullary distribute')


.. parsed-literal::

    [3 1 2 3]


.. code:: ipython3

    J('[3 1 2 3] dup max [index_of] nullary distribute')


.. parsed-literal::

    [0 2 3 4]


.. code:: ipython3

    J('[0 2 3 4] dup max [index_of] nullary distribute')


.. parsed-literal::

    [1 3 4 1]


.. code:: ipython3

    J('[1 3 4 1] dup max [index_of] nullary distribute')


.. parsed-literal::

    [2 4 1 2]


Recalling "Generator Programs"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

    [a F] x
    [a F] a F 

    [a F] a swap [C] dip rest cons
    a   [a F]    [C] dip rest cons
    a C [a F]            rest cons
    a C   [F]                 cons

    w/ C == dup G

    a dup G [F] cons
    a a   G [F] cons

    w/ G == dup max [index_of] nullary distribute

.. code:: ipython3

    define('direco dip rest cons')

.. code:: ipython3

    define('G [direco] cons [swap] swoncat cons')

.. code:: ipython3

    define('make_distributor [dup dup max [index_of] nullary distribute] G')

.. code:: ipython3

    J('[0 2 7 0] make_distributor 6 [x] times pop')


.. parsed-literal::

    [0 2 7 0] [2 4 1 2] [3 1 2 3] [0 2 3 4] [1 3 4 1] [2 4 1 2]


A function to drive a generator and count how many states before a repeat.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First draft:

::

    [] [GEN] x [pop index_of 0 >=] [pop size --] [[swons] dip x] tailrec

(?)

::

    []       [GEN] x [pop index_of 0 >=] [pop size --] [[swons] dip x] tailrec
    [] [...] [GEN]   [pop index_of 0 >=] [pop size --] [[swons] dip x] tailrec
    [] [...] [GEN]    pop index_of 0 >=
    [] [...]              index_of 0 >=
                                -1 0 >=
                                 False

Base case

::

    [] [...] [GEN] [pop index_of 0 >=] [pop size --] [[swons] dip x] tailrec
    [] [...] [GEN]                      pop size --
    [] [...]                                size --
    [] [...]                                size --

A mistake, ``popop`` and no need for ``--``

::

    [] [...] [GEN] popop size
    []                   size
    n

Recursive case

::

    [] [...] [GEN] [pop index_of 0 >=] [popop size] [[swons] dip x] tailrec
    [] [...] [GEN]                                   [swons] dip x  F
    [] [...] swons [GEN]                                         x  F
    [[...]]        [GEN]                                         x  F
    [[...]] [...]  [GEN]                                            F

    [[...]] [...] [GEN] F

What have we learned?

::

    F == [pop index_of 0 >=] [popop size] [[swons] dip x] tailrec

.. code:: ipython3

    define('count_states [] swap x [pop index_of 0 >=] [popop size] [[swons] dip x] tailrec')

.. code:: ipython3

    define('AoC2017.6 make_distributor count_states')

.. code:: ipython3

    J('[0 2 7 0] AoC2017.6')


.. parsed-literal::

    5


.. code:: ipython3

    J('[1 1 1] AoC2017.6')


.. parsed-literal::

    4


.. code:: ipython3

    J('[8 0 0 0 0 0] AoC2017.6')


.. parsed-literal::

    15

