Rebuild docs
This commit is contained in:
@@ -13,11 +13,11 @@ example, the first few squares are allocated like this:
|
||||
|
||||
::
|
||||
|
||||
17 16 15 14 13
|
||||
18 5 4 3 12
|
||||
19 6 1 2 11
|
||||
20 7 8 9 10
|
||||
21 22 23---> ...
|
||||
17 16 15 14 13
|
||||
18 5 4 3 12
|
||||
19 6 1 2 11
|
||||
20 7 8 9 10
|
||||
21 22 23---> ...
|
||||
|
||||
While this is very space-efficient (no squares are skipped), requested
|
||||
data must be carried back to square 1 (the location of the only access
|
||||
@@ -27,7 +27,7 @@ Distance between the location of the data and square 1.
|
||||
|
||||
For example:
|
||||
|
||||
- Data from square 1 is carried 0 steps, since it's at the access port.
|
||||
- Data from square 1 is carried 0 steps, since it’s at the access port.
|
||||
- Data from square 12 is carried 3 steps, such as: down, left, left.
|
||||
- Data from square 23 is carried only 2 steps: up twice.
|
||||
- Data from square 1024 must be carried 31 steps.
|
||||
@@ -39,8 +39,8 @@ Analysis
|
||||
~~~~~~~~
|
||||
|
||||
I freely admit that I worked out the program I wanted to write using
|
||||
graph paper and some Python doodles. There's no point in trying to write
|
||||
a Joy program until I'm sure I understand the problem well enough.
|
||||
graph paper and some Python doodles. There’s no point in trying to write
|
||||
a Joy program until I’m sure I understand the problem well enough.
|
||||
|
||||
The first thing I did was to write a column of numbers from 1 to n (32
|
||||
as it happens) and next to them the desired output number, to look for
|
||||
@@ -48,61 +48,61 @@ patterns directly:
|
||||
|
||||
::
|
||||
|
||||
1 0
|
||||
2 1
|
||||
3 2
|
||||
4 1
|
||||
5 2
|
||||
6 1
|
||||
7 2
|
||||
8 1
|
||||
9 2
|
||||
10 3
|
||||
11 2
|
||||
12 3
|
||||
13 4
|
||||
14 3
|
||||
15 2
|
||||
16 3
|
||||
17 4
|
||||
18 3
|
||||
19 2
|
||||
20 3
|
||||
21 4
|
||||
22 3
|
||||
23 2
|
||||
24 3
|
||||
25 4
|
||||
26 5
|
||||
27 4
|
||||
28 3
|
||||
29 4
|
||||
30 5
|
||||
31 6
|
||||
32 5
|
||||
1 0
|
||||
2 1
|
||||
3 2
|
||||
4 1
|
||||
5 2
|
||||
6 1
|
||||
7 2
|
||||
8 1
|
||||
9 2
|
||||
10 3
|
||||
11 2
|
||||
12 3
|
||||
13 4
|
||||
14 3
|
||||
15 2
|
||||
16 3
|
||||
17 4
|
||||
18 3
|
||||
19 2
|
||||
20 3
|
||||
21 4
|
||||
22 3
|
||||
23 2
|
||||
24 3
|
||||
25 4
|
||||
26 5
|
||||
27 4
|
||||
28 3
|
||||
29 4
|
||||
30 5
|
||||
31 6
|
||||
32 5
|
||||
|
||||
There are four groups repeating for a given "rank", then the pattern
|
||||
There are four groups repeating for a given “rank”, then the pattern
|
||||
enlarges and four groups repeat again, etc.
|
||||
|
||||
::
|
||||
|
||||
1 2
|
||||
3 2 3 4
|
||||
5 4 3 4 5 6
|
||||
7 6 5 4 5 6 7 8
|
||||
9 8 7 6 5 6 7 8 9 10
|
||||
1 2
|
||||
3 2 3 4
|
||||
5 4 3 4 5 6
|
||||
7 6 5 4 5 6 7 8
|
||||
9 8 7 6 5 6 7 8 9 10
|
||||
|
||||
Four of this pyramid interlock to tile the plane extending from the
|
||||
initial "1" square.
|
||||
initial “1” square.
|
||||
|
||||
::
|
||||
|
||||
2 3 | 4 5 | 6 7 | 8 9
|
||||
10 11 12 13|14 15 16 17|18 19 20 21|22 23 24 25
|
||||
2 3 | 4 5 | 6 7 | 8 9
|
||||
10 11 12 13|14 15 16 17|18 19 20 21|22 23 24 25
|
||||
|
||||
And so on.
|
||||
|
||||
We can figure out the pattern for a row of the pyramid at a given "rank"
|
||||
We can figure out the pattern for a row of the pyramid at a given “rank”
|
||||
:math:`k`:
|
||||
|
||||
:math:`2k - 1, 2k - 2, ..., k, k + 1, k + 2, ..., 2k`
|
||||
@@ -115,15 +115,15 @@ This shows that the series consists at each place of :math:`k` plus some
|
||||
number that begins at :math:`k - 1`, decreases to zero, then increases
|
||||
to :math:`k`. Each row has :math:`2k` members.
|
||||
|
||||
Let's figure out how, given an index into a row, we can calculate the
|
||||
Let’s figure out how, given an index into a row, we can calculate the
|
||||
value there. The index will be from 0 to :math:`k - 1`.
|
||||
|
||||
Let's look at an example, with :math:`k = 4`:
|
||||
Let’s look at an example, with :math:`k = 4`:
|
||||
|
||||
::
|
||||
|
||||
0 1 2 3 4 5 6 7
|
||||
7 6 5 4 5 6 7 8
|
||||
0 1 2 3 4 5 6 7
|
||||
7 6 5 4 5 6 7 8
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -156,7 +156,7 @@ value:
|
||||
3 2 1 0 1 2 3 4
|
||||
|
||||
|
||||
Great, now add :math:`k`...
|
||||
Great, now add :math:`k`\ …
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -190,7 +190,7 @@ index:
|
||||
9 8 7 6 5 6 7 8 9 10
|
||||
|
||||
|
||||
(I'm leaving out details of how I figured this all out and just giving
|
||||
(I’m leaving out details of how I figured this all out and just giving
|
||||
the relevent bits. It took a little while to zero in of the aspects of
|
||||
the pattern that were important for the task.)
|
||||
|
||||
@@ -209,8 +209,8 @@ initial square we have:
|
||||
|
||||
:math:`corner_k = 1 + \sum_{n=1}^k 8n`
|
||||
|
||||
I'm not mathematically sophisticated enough to turn this directly into a
|
||||
formula (but Sympy is, see below.) I'm going to write a simple Python
|
||||
I’m not mathematically sophisticated enough to turn this directly into a
|
||||
formula (but Sympy is, see below.) I’m going to write a simple Python
|
||||
function to iterate and search:
|
||||
|
||||
.. code:: ipython2
|
||||
@@ -420,7 +420,7 @@ Sympy to the Rescue
|
||||
Find the rank for large numbers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Using e.g. Sympy we can find the rank directly by solving for the roots
|
||||
Using e.g. Sympy we can find the rank directly by solving for the roots
|
||||
of an equation. For large numbers this will (eventually) be faster than
|
||||
iterating as ``rank_and_offset()`` does.
|
||||
|
||||
@@ -459,7 +459,7 @@ We want:
|
||||
|
||||
|
||||
|
||||
We can write a function to solve for :math:`k` given some :math:`n`...
|
||||
We can write a function to solve for :math:`k` given some :math:`n`\ …
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -472,7 +472,7 @@ about the larger one we use ``max()`` to select it. It will generally
|
||||
not be a nice integer (unless :math:`n` is the number of an end-corner
|
||||
of a rank) so we take the ``floor()`` and add 1 to get the integer rank
|
||||
of :math:`n`. (Taking the ``ceiling()`` gives off-by-one errors on the
|
||||
rank boundaries. I don't know why. I'm basically like a monkey doing
|
||||
rank boundaries. I don’t know why. I’m basically like a monkey doing
|
||||
math here.) =-D
|
||||
|
||||
It gives correct answers:
|
||||
@@ -534,7 +534,7 @@ And it runs much faster (at least for large numbers):
|
||||
|
||||
|
||||
After finding the rank you would still have to find the actual value of
|
||||
the rank's first corner and subtract it (plus 2) from the number and
|
||||
the rank’s first corner and subtract it (plus 2) from the number and
|
||||
compute the offset as above and then the final output, but this overhead
|
||||
is partially shared by the other method, and overshadowed by the time it
|
||||
(the other iterative method) would take for really big inputs.
|
||||
@@ -542,8 +542,8 @@ is partially shared by the other method, and overshadowed by the time it
|
||||
The fun thing to do here would be to graph the actual runtime of both
|
||||
methods against each other to find the trade-off point.
|
||||
|
||||
It took me a second to realize I could do this...
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
It took me a second to realize I could do this…
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sympy is a *symbolic* math library, and it supports symbolic
|
||||
manipulation of equations. I can put in :math:`y` (instead of a value)
|
||||
@@ -558,7 +558,7 @@ and ask it to solve for :math:`k`.
|
||||
g, f = solve(E - y, k)
|
||||
|
||||
The equation is quadratic so there are two roots, we are interested in
|
||||
the greater one...
|
||||
the greater one…
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -622,7 +622,7 @@ to get a Python function that calculates the rank directly.
|
||||
50 4
|
||||
|
||||
|
||||
It's pretty fast.
|
||||
It’s pretty fast.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -685,7 +685,7 @@ compute the offset into a pyramid row.
|
||||
|
||||
(Note the sneaky way the sign changes from :math:`k(k + 1)` to
|
||||
:math:`k(k - 1)`. This is because we want to subract the
|
||||
:math:`(k - 1)`\ th rank's total places (its own and those of lesser
|
||||
:math:`(k - 1)`\ th rank’s total places (its own and those of lesser
|
||||
rank) from our :math:`n` of rank :math:`k`. Substituting :math:`k - 1`
|
||||
for :math:`k` in :math:`k(k + 1)` gives :math:`(k - 1)(k - 1 + 1)`,
|
||||
which of course simplifies to :math:`k(k - 1)`.)
|
||||
@@ -797,17 +797,17 @@ this code in Joy. ;-)
|
||||
|
||||
::
|
||||
|
||||
n rank_of
|
||||
---------------
|
||||
k
|
||||
n rank_of
|
||||
---------------
|
||||
k
|
||||
|
||||
The translation is straightforward.
|
||||
|
||||
::
|
||||
|
||||
int(floor(sqrt(n - 1) / 2 - 0.5) + 1)
|
||||
int(floor(sqrt(n - 1) / 2 - 0.5) + 1)
|
||||
|
||||
rank_of == -- sqrt 2 / 0.5 - floor ++
|
||||
rank_of == -- sqrt 2 / 0.5 - floor ++
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -818,36 +818,36 @@ The translation is straightforward.
|
||||
|
||||
::
|
||||
|
||||
n k offset_of
|
||||
-------------------
|
||||
i
|
||||
n k offset_of
|
||||
-------------------
|
||||
i
|
||||
|
||||
(n - 2 + 4 * k * (k - 1)) % (2 * k)
|
||||
(n - 2 + 4 * k * (k - 1)) % (2 * k)
|
||||
|
||||
A little tricky...
|
||||
A little tricky…
|
||||
|
||||
::
|
||||
|
||||
n k dup 2 *
|
||||
n k k 2 *
|
||||
n k k*2 [Q] dip %
|
||||
n k Q k*2 %
|
||||
n k dup 2 *
|
||||
n k k 2 *
|
||||
n k k*2 [Q] dip %
|
||||
n k Q k*2 %
|
||||
|
||||
n k dup --
|
||||
n k k --
|
||||
n k k-1 4 * * 2 + -
|
||||
n k*k-1*4 2 + -
|
||||
n k*k-1*4+2 -
|
||||
n-k*k-1*4+2
|
||||
n k dup --
|
||||
n k k --
|
||||
n k k-1 4 * * 2 + -
|
||||
n k*k-1*4 2 + -
|
||||
n k*k-1*4+2 -
|
||||
n-k*k-1*4+2
|
||||
|
||||
n-k*k-1*4+2 k*2 %
|
||||
n-k*k-1*4+2%k*2
|
||||
n-k*k-1*4+2 k*2 %
|
||||
n-k*k-1*4+2%k*2
|
||||
|
||||
Ergo:
|
||||
|
||||
::
|
||||
|
||||
offset_of == dup 2 * [dup -- 4 * * 2 + -] dip %
|
||||
offset_of == dup 2 * [dup -- 4 * * 2 + -] dip %
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -858,18 +858,18 @@ Ergo:
|
||||
|
||||
::
|
||||
|
||||
k i row_value
|
||||
-------------------
|
||||
n
|
||||
k i row_value
|
||||
-------------------
|
||||
n
|
||||
|
||||
abs(i - (k - 1)) + k
|
||||
abs(i - (k - 1)) + k
|
||||
|
||||
k i over -- - abs +
|
||||
k i k -- - abs +
|
||||
k i k-1 - abs +
|
||||
k i-k-1 abs +
|
||||
k |i-k-1| +
|
||||
k+|i-k-1|
|
||||
k i over -- - abs +
|
||||
k i k -- - abs +
|
||||
k i k-1 - abs +
|
||||
k i-k-1 abs +
|
||||
k |i-k-1| +
|
||||
k+|i-k-1|
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -880,16 +880,16 @@ Ergo:
|
||||
|
||||
::
|
||||
|
||||
n aoc2017.3
|
||||
-----------------
|
||||
m
|
||||
n aoc2017.3
|
||||
-----------------
|
||||
m
|
||||
|
||||
n dup rank_of
|
||||
n k [offset_of] dupdip
|
||||
n k offset_of k
|
||||
i k swap row_value
|
||||
k i row_value
|
||||
m
|
||||
n dup rank_of
|
||||
n k [offset_of] dupdip
|
||||
n k offset_of k
|
||||
i k swap row_value
|
||||
k i row_value
|
||||
m
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
@@ -965,8 +965,8 @@ Ergo:
|
||||
|
||||
::
|
||||
|
||||
rank_of == -- sqrt 2 / 0.5 - floor ++
|
||||
offset_of == dup 2 * [dup -- 4 * * 2 + -] dip %
|
||||
row_value == over -- - abs +
|
||||
rank_of == -- sqrt 2 / 0.5 - floor ++
|
||||
offset_of == dup 2 * [dup -- 4 * * 2 + -] dip %
|
||||
row_value == over -- - abs +
|
||||
|
||||
aoc2017.3 == dup rank_of [offset_of] dupdip swap row_value
|
||||
aoc2017.3 == dup rank_of [offset_of] dupdip swap row_value
|
||||
|
||||
Reference in New Issue
Block a user