Advent of Code 2017

December 6th

[0 2 7 0] dup max
In [1]:
from notebook_preamble import D, J, V, define
In [2]:
J('[0 2 7 0] dup max')
[0 2 7 0] 7
In [3]:
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
In [4]:
J('[0 2 7 0] 7 index_of')
2
In [5]:
J('[0 2 7 0] 23 index_of')
-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...

In [6]:
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
In [7]:
J('[0 2 7 0] dup max [index_of] nullary distribute')
[2 4 1 2]
In [8]:
J('[2 4 1 2] dup max [index_of] nullary distribute')
[3 1 2 3]
In [9]:
J('[3 1 2 3] dup max [index_of] nullary distribute')
[0 2 3 4]
In [10]:
J('[0 2 3 4] dup max [index_of] nullary distribute')
[1 3 4 1]
In [11]:
J('[1 3 4 1] dup max [index_of] nullary distribute')
[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
In [12]:
define('direco dip rest cons')
In [13]:
define('G [direco] cons [swap] swoncat cons')
In [14]:
define('make_distributor [dup dup max [index_of] nullary distribute] G')
In [15]:
J('[0 2 7 0] make_distributor 6 [x] times pop')
[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
In [16]:
define('count_states [] swap x [pop index_of 0 >=] [popop size] [[swons] dip x] tailrec')
In [17]:
define('AoC2017.6 make_distributor count_states')
In [18]:
J('[0 2 7 0] AoC2017.6')
5
In [19]:
J('[1 1 1] AoC2017.6')
4
In [20]:
J('[8 0 0 0 0 0] AoC2017.6')
15