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] primrec

(?)

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

Base case

[] [...] [GEN] [pop index_of 0 >=] [pop size --] [[swons] dip x] primrec
[] [...] [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] primrec
[] [...] [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] primrec

In [16]:
define('count_states == [] swap x [pop index_of 0 >=] [popop size] [[swons] dip x] primrec')

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