Added more tour shape images
authorNeil Smith <neil.git@njae.me.uk>
Mon, 26 Jun 2017 19:30:41 +0000 (20:30 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 26 Jun 2017 19:30:41 +0000 (20:30 +0100)
39 files changed:
06-tour-shapes/mistake-tour-000-s0018-m002-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-001-s0008-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-002-s0024-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-003-s0020-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-004-s0020-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-005-s0010-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-006-s0012-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-007-s0008-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-008-s0012-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-009-s0024-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-010-s0008-m002-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-011-s0022-m002-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-012-s0022-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-013-s0008-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-014-s0014-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-015-s0010-m002-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-016-s0012-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-017-s0022-m002-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-018-s0014-m001-walk.png [new file with mode: 0644]
06-tour-shapes/mistake-tour-019-s0010-m000-walk.png [new file with mode: 0644]
06-tour-shapes/mistakes.txt [new file with mode: 0644]
06-tour-shapes/open-loop.png [new file with mode: 0644]
06-tour-shapes/sample-tour-000-s0016-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-001-s0010-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-002-s0012-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-003-s0012-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-004-s0010-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-005-s0012-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-006-s0014-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-007-s0010-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-008-s0020-m000-walk.png [new file with mode: 0644]
06-tour-shapes/sample-tour-009-s0012-m000-walk.png [new file with mode: 0644]
06-tour-shapes/samples.txt [new file with mode: 0644]
06-tour-shapes/split-leg-1.png [new file with mode: 0644]
06-tour-shapes/split-leg-2.png [new file with mode: 0644]
06-tour-shapes/split-leg-combined.png [new file with mode: 0644]
06-tour-shapes/tour-shape-plots.py
06-tour-shapes/tour-shapes-sample-tours.ipynb [new file with mode: 0644]
06-tour-shapes/tour-shapes-solution.ipynb

diff --git a/06-tour-shapes/mistake-tour-000-s0018-m002-walk.png b/06-tour-shapes/mistake-tour-000-s0018-m002-walk.png
new file mode 100644 (file)
index 0000000..8028858
Binary files /dev/null and b/06-tour-shapes/mistake-tour-000-s0018-m002-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-001-s0008-m000-walk.png b/06-tour-shapes/mistake-tour-001-s0008-m000-walk.png
new file mode 100644 (file)
index 0000000..88b9364
Binary files /dev/null and b/06-tour-shapes/mistake-tour-001-s0008-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-002-s0024-m001-walk.png b/06-tour-shapes/mistake-tour-002-s0024-m001-walk.png
new file mode 100644 (file)
index 0000000..2a5ba68
Binary files /dev/null and b/06-tour-shapes/mistake-tour-002-s0024-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-003-s0020-m001-walk.png b/06-tour-shapes/mistake-tour-003-s0020-m001-walk.png
new file mode 100644 (file)
index 0000000..81b418f
Binary files /dev/null and b/06-tour-shapes/mistake-tour-003-s0020-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-004-s0020-m000-walk.png b/06-tour-shapes/mistake-tour-004-s0020-m000-walk.png
new file mode 100644 (file)
index 0000000..d1ae713
Binary files /dev/null and b/06-tour-shapes/mistake-tour-004-s0020-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-005-s0010-m001-walk.png b/06-tour-shapes/mistake-tour-005-s0010-m001-walk.png
new file mode 100644 (file)
index 0000000..e64f8a7
Binary files /dev/null and b/06-tour-shapes/mistake-tour-005-s0010-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-006-s0012-m001-walk.png b/06-tour-shapes/mistake-tour-006-s0012-m001-walk.png
new file mode 100644 (file)
index 0000000..8b66c2b
Binary files /dev/null and b/06-tour-shapes/mistake-tour-006-s0012-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-007-s0008-m000-walk.png b/06-tour-shapes/mistake-tour-007-s0008-m000-walk.png
new file mode 100644 (file)
index 0000000..89085a5
Binary files /dev/null and b/06-tour-shapes/mistake-tour-007-s0008-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-008-s0012-m000-walk.png b/06-tour-shapes/mistake-tour-008-s0012-m000-walk.png
new file mode 100644 (file)
index 0000000..903bf15
Binary files /dev/null and b/06-tour-shapes/mistake-tour-008-s0012-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-009-s0024-m000-walk.png b/06-tour-shapes/mistake-tour-009-s0024-m000-walk.png
new file mode 100644 (file)
index 0000000..5a822d0
Binary files /dev/null and b/06-tour-shapes/mistake-tour-009-s0024-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-010-s0008-m002-walk.png b/06-tour-shapes/mistake-tour-010-s0008-m002-walk.png
new file mode 100644 (file)
index 0000000..5926b00
Binary files /dev/null and b/06-tour-shapes/mistake-tour-010-s0008-m002-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-011-s0022-m002-walk.png b/06-tour-shapes/mistake-tour-011-s0022-m002-walk.png
new file mode 100644 (file)
index 0000000..c8bf5ad
Binary files /dev/null and b/06-tour-shapes/mistake-tour-011-s0022-m002-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-012-s0022-m001-walk.png b/06-tour-shapes/mistake-tour-012-s0022-m001-walk.png
new file mode 100644 (file)
index 0000000..e5640d9
Binary files /dev/null and b/06-tour-shapes/mistake-tour-012-s0022-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-013-s0008-m000-walk.png b/06-tour-shapes/mistake-tour-013-s0008-m000-walk.png
new file mode 100644 (file)
index 0000000..1be0c99
Binary files /dev/null and b/06-tour-shapes/mistake-tour-013-s0008-m000-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-014-s0014-m001-walk.png b/06-tour-shapes/mistake-tour-014-s0014-m001-walk.png
new file mode 100644 (file)
index 0000000..3ef544f
Binary files /dev/null and b/06-tour-shapes/mistake-tour-014-s0014-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-015-s0010-m002-walk.png b/06-tour-shapes/mistake-tour-015-s0010-m002-walk.png
new file mode 100644 (file)
index 0000000..a12b257
Binary files /dev/null and b/06-tour-shapes/mistake-tour-015-s0010-m002-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-016-s0012-m001-walk.png b/06-tour-shapes/mistake-tour-016-s0012-m001-walk.png
new file mode 100644 (file)
index 0000000..b326f71
Binary files /dev/null and b/06-tour-shapes/mistake-tour-016-s0012-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-017-s0022-m002-walk.png b/06-tour-shapes/mistake-tour-017-s0022-m002-walk.png
new file mode 100644 (file)
index 0000000..200b020
Binary files /dev/null and b/06-tour-shapes/mistake-tour-017-s0022-m002-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-018-s0014-m001-walk.png b/06-tour-shapes/mistake-tour-018-s0014-m001-walk.png
new file mode 100644 (file)
index 0000000..40aacb9
Binary files /dev/null and b/06-tour-shapes/mistake-tour-018-s0014-m001-walk.png differ
diff --git a/06-tour-shapes/mistake-tour-019-s0010-m000-walk.png b/06-tour-shapes/mistake-tour-019-s0010-m000-walk.png
new file mode 100644 (file)
index 0000000..cab848e
Binary files /dev/null and b/06-tour-shapes/mistake-tour-019-s0010-m000-walk.png differ
diff --git a/06-tour-shapes/mistakes.txt b/06-tour-shapes/mistakes.txt
new file mode 100644 (file)
index 0000000..d0400ad
--- /dev/null
@@ -0,0 +1,20 @@
+LFLLFFFFLLLFFRFRFF
+LFFLLFFL
+FRFFRRFFFFFFLLRLRLRLLFFF
+RFFRRRFLFFFFLFLFRLLF
+LFFRFRFFFFFRFFRLRFRF
+LFFRFRFRFL
+FLFFLLFFRLLL
+FLLFFLLF
+FFLLRLRLLFLR
+FRRLLFLFFFFLFFFLLFFRRFLL
+FRFRRFFF
+FFFRFRRFFFFFFLFLFFFLRR
+FFRRRFFLRLFRLFLFLFRFLF
+RFFRRFFR
+LFFFFRRRFLFFFL
+FFLLLRRLLL
+FFRFFRFRFRLL
+RFLFFFFRRFFFFFRFFLLLLR
+RRLLRRFFRFRFLR
+FFRFRFFRFR
\ No newline at end of file
diff --git a/06-tour-shapes/open-loop.png b/06-tour-shapes/open-loop.png
new file mode 100644 (file)
index 0000000..2a5293b
Binary files /dev/null and b/06-tour-shapes/open-loop.png differ
diff --git a/06-tour-shapes/sample-tour-000-s0016-m000-walk.png b/06-tour-shapes/sample-tour-000-s0016-m000-walk.png
new file mode 100644 (file)
index 0000000..493db5a
Binary files /dev/null and b/06-tour-shapes/sample-tour-000-s0016-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-001-s0010-m000-walk.png b/06-tour-shapes/sample-tour-001-s0010-m000-walk.png
new file mode 100644 (file)
index 0000000..dc127b3
Binary files /dev/null and b/06-tour-shapes/sample-tour-001-s0010-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-002-s0012-m000-walk.png b/06-tour-shapes/sample-tour-002-s0012-m000-walk.png
new file mode 100644 (file)
index 0000000..f911c10
Binary files /dev/null and b/06-tour-shapes/sample-tour-002-s0012-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-003-s0012-m000-walk.png b/06-tour-shapes/sample-tour-003-s0012-m000-walk.png
new file mode 100644 (file)
index 0000000..303112f
Binary files /dev/null and b/06-tour-shapes/sample-tour-003-s0012-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-004-s0010-m000-walk.png b/06-tour-shapes/sample-tour-004-s0010-m000-walk.png
new file mode 100644 (file)
index 0000000..b7d4ce8
Binary files /dev/null and b/06-tour-shapes/sample-tour-004-s0010-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-005-s0012-m000-walk.png b/06-tour-shapes/sample-tour-005-s0012-m000-walk.png
new file mode 100644 (file)
index 0000000..08545e7
Binary files /dev/null and b/06-tour-shapes/sample-tour-005-s0012-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-006-s0014-m000-walk.png b/06-tour-shapes/sample-tour-006-s0014-m000-walk.png
new file mode 100644 (file)
index 0000000..19295a0
Binary files /dev/null and b/06-tour-shapes/sample-tour-006-s0014-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-007-s0010-m000-walk.png b/06-tour-shapes/sample-tour-007-s0010-m000-walk.png
new file mode 100644 (file)
index 0000000..80a99bc
Binary files /dev/null and b/06-tour-shapes/sample-tour-007-s0010-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-008-s0020-m000-walk.png b/06-tour-shapes/sample-tour-008-s0020-m000-walk.png
new file mode 100644 (file)
index 0000000..52770fc
Binary files /dev/null and b/06-tour-shapes/sample-tour-008-s0020-m000-walk.png differ
diff --git a/06-tour-shapes/sample-tour-009-s0012-m000-walk.png b/06-tour-shapes/sample-tour-009-s0012-m000-walk.png
new file mode 100644 (file)
index 0000000..cec0569
Binary files /dev/null and b/06-tour-shapes/sample-tour-009-s0012-m000-walk.png differ
diff --git a/06-tour-shapes/samples.txt b/06-tour-shapes/samples.txt
new file mode 100644 (file)
index 0000000..4cb0b69
--- /dev/null
@@ -0,0 +1,10 @@
+FLRFRFFFRFFFRFFR
+FFFRFRFRLR
+FFFFRFRFRLFR
+FFFLFFLFFLFF
+FFRRFLRRFR
+RLRFFRFRFFFR
+LFRFLLFFFLFFLF
+RLFFLFLFLR
+RFFFLLRFFFLLRRLLFFFF
+FLFFLFFLFLRL
\ No newline at end of file
diff --git a/06-tour-shapes/split-leg-1.png b/06-tour-shapes/split-leg-1.png
new file mode 100644 (file)
index 0000000..78c143c
Binary files /dev/null and b/06-tour-shapes/split-leg-1.png differ
diff --git a/06-tour-shapes/split-leg-2.png b/06-tour-shapes/split-leg-2.png
new file mode 100644 (file)
index 0000000..9d47e1f
Binary files /dev/null and b/06-tour-shapes/split-leg-2.png differ
diff --git a/06-tour-shapes/split-leg-combined.png b/06-tour-shapes/split-leg-combined.png
new file mode 100644 (file)
index 0000000..86a02a6
Binary files /dev/null and b/06-tour-shapes/split-leg-combined.png differ
index af9e3564113f635008007f6f67177f8a8847f0af..4bb47e0b47aa45fbe064c7c7784dd224fb39eb5c 100644 (file)
@@ -507,10 +507,11 @@ def heart_tour_func(): return heart_tour
 #         meta.add_text('Description', tour)
 #         im.save(filename, 'PNG', pnginfo=meta)
 
-with open('tours-random-walk.txt') as f:
+# with open('tours-random-walk.txt') as f:
+with open('samples.txt') as f:
     for i, tour_s in enumerate(f.readlines()):
         tour = tour_s.strip()
-        filename = 'tour-{:03}-s{:04}-m{:03}-walk.png'.format(i, len(tour), len(mistake_positions(trace_tour(tour))))
+        filename = 'sample-tour-{:03}-s{:04}-m{:03}-walk.png'.format(i, len(tour), len(mistake_positions(trace_tour(tour))))
         plot_trace(trace_tour(tour), filename=filename)
         im = Image.open(filename)
         meta = PngImagePlugin.PngInfo()
diff --git a/06-tour-shapes/tour-shapes-sample-tours.ipynb b/06-tour-shapes/tour-shapes-sample-tours.ipynb
new file mode 100644 (file)
index 0000000..3fa22ff
--- /dev/null
@@ -0,0 +1,1143 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Given a sequence of {F|L|R}, each of which is \"move forward one step\", \"turn left, then move forward one step\", \"turn right, then move forward one step\":\n",
+    "1. which tours are closed?\n",
+    "2. what is the area enclosed by the tour?"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import collections\n",
+    "import enum\n",
+    "import random\n",
+    "import os\n",
+    "\n",
+    "import matplotlib.pyplot as plt\n",
+    "%matplotlib inline\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "class Direction(enum.Enum):\n",
+    "    UP = 1\n",
+    "    RIGHT = 2\n",
+    "    DOWN = 3\n",
+    "    LEFT = 4\n",
+    "    \n",
+    "turn_lefts = {Direction.UP: Direction.LEFT, Direction.LEFT: Direction.DOWN,\n",
+    "              Direction.DOWN: Direction.RIGHT, Direction.RIGHT: Direction.UP}\n",
+    "\n",
+    "turn_rights = {Direction.UP: Direction.RIGHT, Direction.RIGHT: Direction.DOWN,\n",
+    "               Direction.DOWN: Direction.LEFT, Direction.LEFT: Direction.UP}\n",
+    "\n",
+    "def turn_left(d):\n",
+    "    return turn_lefts[d]\n",
+    "\n",
+    "def turn_right(d):\n",
+    "    return turn_rights[d]\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "Step = collections.namedtuple('Step', ['x', 'y', 'dir'])\n",
+    "Mistake = collections.namedtuple('Mistake', ['i', 'step'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def advance(step, d):\n",
+    "    if d == Direction.UP:\n",
+    "        return Step(step.x, step.y+1, d)\n",
+    "    elif d == Direction.DOWN:\n",
+    "        return Step(step.x, step.y-1, d)\n",
+    "    elif d == Direction.LEFT:\n",
+    "        return Step(step.x-1, step.y, d)\n",
+    "    elif d == Direction.RIGHT:\n",
+    "        return Step(step.x+1, step.y, d)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def step(s, current):\n",
+    "    if s == 'F':\n",
+    "        return advance(current, current.dir)\n",
+    "    elif s == 'L':\n",
+    "        return advance(current, turn_left(current.dir))\n",
+    "    elif s == 'R':\n",
+    "        return advance(current, turn_right(current.dir))\n",
+    "    else:\n",
+    "        raise ValueError"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def trace_tour(tour, startx=0, starty=0, startdir=Direction.RIGHT):\n",
+    "    current = Step(startx, starty, startdir)\n",
+    "    trace = [current]\n",
+    "    for s in tour:\n",
+    "        current = step(s, current)\n",
+    "        trace += [current]\n",
+    "    return trace    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def positions(trace):\n",
+    "    return [(s.x, s.y) for s in trace]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def valid(trace):\n",
+    "    return (trace[-1].x == 0 \n",
+    "            and trace[-1].y == 0 \n",
+    "            and len(set(positions(trace))) + 1 == len(trace))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def valid_prefix(tour):\n",
+    "    current = Step(0, 0, Direction.RIGHT)\n",
+    "    prefix = []\n",
+    "    posns = []\n",
+    "    for s in tour:\n",
+    "        current = step(s, current)\n",
+    "        prefix += [s]\n",
+    "        if (current.x, current.y) in posns:\n",
+    "            return ''\n",
+    "        elif current.x == 0 and current.y == 0: \n",
+    "            return ''.join(prefix)\n",
+    "        posns += [(current.x, current.y)]\n",
+    "    if current.x == 0 and current.y == 0:\n",
+    "        return ''.join(prefix)\n",
+    "    else:\n",
+    "        return ''"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def mistake_positions(trace, debug=False):\n",
+    "    mistakes = []\n",
+    "    current = trace[0]\n",
+    "    posns = [(0, 0)]\n",
+    "    for i, current in enumerate(trace[1:]):\n",
+    "        if (current.x, current.y) in posns:\n",
+    "            if debug: print(i, current)\n",
+    "            mistakes += [Mistake(i+1, current)]\n",
+    "        posns += [(current.x, current.y)]\n",
+    "    if (current.x, current.y) == (0, 0):\n",
+    "        return mistakes[:-1]\n",
+    "    else:\n",
+    "        return mistakes + [Mistake(len(trace)+1, current)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def returns_to_origin(mistake_positions):\n",
+    "    return [i for i, m in mistake_positions\n",
+    "           if (m.x, m.y) == (0, 0)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "sample_tours = ['FFLRLLFLRL', 'FLLFFLFFFLFFLFLLRRFR', 'FFRLLFRLLFFFRFLLRLLRRLLRLL']"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def random_walk(steps=1000):\n",
+    "    return ''.join(random.choice('FFLR') for _ in range(steps))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def bounds(trace):\n",
+    "    return (max(s.x for s in trace),\n",
+    "            max(s.y for s in trace),\n",
+    "            min(s.x for s in trace),\n",
+    "            min(s.y for s in trace))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "plot_wh = {Direction.UP: (0, 1), Direction.LEFT: (-1, 0),\n",
+    "           Direction.DOWN: (0, -1), Direction.RIGHT: (1, 0)}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def chunks(items, n=2):\n",
+    "    return [items[i:i+n] for i in range(len(items) - n + 1)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def plot_trace(trace, colour='k', xybounds=None, fig=None, subplot_details=None, filename=None, show_axis=False):\n",
+    "    if show_axis:\n",
+    "        plt.axis('on')\n",
+    "    else:\n",
+    "        plt.axis('off')\n",
+    "    plt.axes().set_aspect('equal')\n",
+    "    for s, t in chunks(trace, 2):\n",
+    "        w, h = plot_wh[t.dir]\n",
+    "        plt.arrow(s.x, s.y, w, h, head_width=0.1, head_length=0.1, fc=colour, ec=colour, length_includes_head=True)\n",
+    "    xh, yh, xl, yl = bounds(trace)\n",
+    "    if xybounds is not None:    \n",
+    "        bxh, byh, bxl, byl = xybounds\n",
+    "        plt.xlim([min(xl, bxl)-1, max(xh, bxh)+1])\n",
+    "        plt.ylim([min(yl, byl)-1, max(yh, byh)+1])\n",
+    "    else:\n",
+    "        plt.xlim([xl-1, xh+1])\n",
+    "        plt.ylim([yl-1, yh+1])\n",
+    "    if filename:\n",
+    "        plt.savefig(filename)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def trim_loop(tour, random_mistake=False):\n",
+    "    trace = trace_tour(tour)\n",
+    "    mistakes = mistake_positions(trace)\n",
+    "    if random_mistake:\n",
+    "        end_mistake_index = random.randrange(len(mistakes))\n",
+    "    else:\n",
+    "        end_mistake_index = 0\n",
+    "#     print('end_mistake_index {} pointing to trace position {}; {} mistakes and {} in trace; {}'.format(end_mistake_index, mistakes[end_mistake_index].i, len(mistakes), len(trace), mistakes))\n",
+    "    # while this mistake extends to the next step in the trace...\n",
+    "    while (mistakes[end_mistake_index].i + 1 < len(trace) and \n",
+    "           end_mistake_index + 1 < len(mistakes) and\n",
+    "           mistakes[end_mistake_index].i + 1 == \n",
+    "           mistakes[end_mistake_index + 1].i):\n",
+    "#         print('end_mistake_index {} pointing to trace position {}; {} mistakes and {} in trace'.format(end_mistake_index, mistakes[end_mistake_index].i, len(mistakes), len(trace), mistakes))\n",
+    "        # push this mistake finish point later\n",
+    "        end_mistake_index += 1\n",
+    "    mistake = mistakes[end_mistake_index]\n",
+    "    \n",
+    "    # find the first location that mentions where this mistake ends (which the point where the loop starts)\n",
+    "    mistake_loop_start = max(i for i, loc in enumerate(trace[:mistake.i])\n",
+    "                             if (loc.x, loc.y) == (mistake.step.x, mistake.step.y))\n",
+    "#     print('Dealing with mistake from', mistake_loop_start, 'to', mistake.i, ', trace has len', len(trace))\n",
+    "    \n",
+    "    # direction before entering the loop\n",
+    "    direction_before = trace[mistake_loop_start].dir\n",
+    "    \n",
+    "    # find the new instruction to turn from heading before the loop to heading after the loop\n",
+    "    new_instruction = 'F'\n",
+    "    if (mistake.i + 1) < len(trace):\n",
+    "        if turn_left(direction_before) == trace[mistake.i + 1].dir:\n",
+    "            new_instruction = 'L'\n",
+    "        if turn_right(direction_before) == trace[mistake.i + 1].dir:\n",
+    "            new_instruction = 'R'\n",
+    "#     if (mistake.i + 1) < len(trace):\n",
+    "#         print('turning from', direction_before, 'to', trace[mistake.i + 1].dir, 'with', new_instruction )\n",
+    "#     else:\n",
+    "#         print('turning from', direction_before, 'to BEYOND END', 'with', new_instruction )\n",
+    "    return tour[:mistake_loop_start] + new_instruction + tour[mistake.i+1:]\n",
+    "#     return mistake, mistake_loop_start, trace[mistake_loop_start-2:mistake_loop_start+8]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def trim_all_loops(tour, mistake_reduction_attempt_limit=10):\n",
+    "    trace = trace_tour(tour)\n",
+    "    mistake_limit = 1\n",
+    "    if trace[-1].x == 0 and trace[-1].y == 0:\n",
+    "        mistake_limit = 0\n",
+    "    mistakes = mistake_positions(trace)\n",
+    "    \n",
+    "    old_mistake_count = len(mistakes)\n",
+    "    mistake_reduction_tries = 0\n",
+    "    \n",
+    "    while len(mistakes) > mistake_limit and mistake_reduction_tries < mistake_reduction_attempt_limit:\n",
+    "        tour = trim_loop(tour)\n",
+    "        trace = trace_tour(tour)\n",
+    "        mistakes = mistake_positions(trace)\n",
+    "        if len(mistakes) < old_mistake_count:\n",
+    "            old_mistake_count = len(mistakes)\n",
+    "            mistake_reduction_tries = 0\n",
+    "        else:\n",
+    "            mistake_reduction_tries += 1\n",
+    "    if mistake_reduction_tries >= mistake_reduction_attempt_limit:\n",
+    "        return ''\n",
+    "    else:\n",
+    "        return tour"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def reverse_tour(tour):\n",
+    "    def swap(tour_step):\n",
+    "        if tour_step == 'R':\n",
+    "            return 'L'\n",
+    "        elif tour_step == 'L':\n",
+    "            return 'R'\n",
+    "        else:\n",
+    "            return tour_step\n",
+    "        \n",
+    "    return ''.join(swap(s) for s in reversed(tour))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def wander_near(locus, current, limit=10):\n",
+    "    valid_proposal = False\n",
+    "    while not valid_proposal:\n",
+    "        s = random.choice('FFFRL')\n",
+    "        if s == 'F':\n",
+    "            proposed = advance(current, current.dir)\n",
+    "        elif s == 'L':\n",
+    "            proposed = advance(current, turn_left(current.dir))\n",
+    "        elif s == 'R':\n",
+    "            proposed = advance(current, turn_right(current.dir))\n",
+    "        if abs(proposed.x - locus.x) < limit and abs(proposed.y - locus.y) < limit:\n",
+    "            valid_proposal = True\n",
+    "#     print('At {} going to {} by step {} to {}'.format(current, locus, s, proposed))\n",
+    "    return s, proposed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def seek(goal, current):\n",
+    "    dx = current.x - goal.x\n",
+    "    dy = current.y - goal.y\n",
+    "\n",
+    "    if dx < 0 and abs(dx) > abs(dy): # to the left\n",
+    "        side = 'left'\n",
+    "        if current.dir == Direction.RIGHT:\n",
+    "            s = 'F'\n",
+    "        elif current.dir == Direction.UP:\n",
+    "            s = 'R'\n",
+    "        else:\n",
+    "            s = 'L'\n",
+    "    elif dx > 0 and abs(dx) > abs(dy): # to the right\n",
+    "        side = 'right'\n",
+    "        if current.dir == Direction.LEFT:\n",
+    "            s = 'F'\n",
+    "        elif current.dir == Direction.UP:\n",
+    "            s = 'L'\n",
+    "        else:\n",
+    "            s = 'R'\n",
+    "    elif dy > 0 and abs(dx) <= abs(dy): # above\n",
+    "        side = 'above'\n",
+    "        if current.dir == Direction.DOWN:\n",
+    "            s = 'F'\n",
+    "        elif current.dir == Direction.RIGHT:\n",
+    "            s = 'R'\n",
+    "        else:\n",
+    "            s = 'L'\n",
+    "    else: # below\n",
+    "        side = 'below'\n",
+    "        if current.dir == Direction.UP:\n",
+    "            s = 'F'\n",
+    "        elif current.dir == Direction.LEFT:\n",
+    "            s = 'R'\n",
+    "        else:\n",
+    "            s = 'L'\n",
+    "    if s == 'F':\n",
+    "        proposed = advance(current, current.dir)\n",
+    "    elif s == 'L':\n",
+    "        proposed = advance(current, turn_left(current.dir))\n",
+    "    elif s == 'R':\n",
+    "        proposed = advance(current, turn_right(current.dir))\n",
+    "        \n",
+    "#     print('At {} going to {}, currently {},  by step {} to {}'.format(current, goal, side, s, proposed))\n",
+    "\n",
+    "    return s, proposed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def guided_walk(loci, locus_limit=5, wander_limit=10, seek_step_limit=20, return_anyway=False):\n",
+    "    trail = ''\n",
+    "    current = Step(0, 0, Direction.RIGHT)    \n",
+    "    l = 0\n",
+    "    finished = False\n",
+    "    while not finished:\n",
+    "        if abs(current.x - loci[l].x) < locus_limit and abs(current.y - loci[l].y) < locus_limit:\n",
+    "            l += 1\n",
+    "            if l == len(loci) - 1:\n",
+    "                finished = True\n",
+    "        s, proposed = wander_near(loci[l], current, limit=wander_limit)\n",
+    "        trail += s\n",
+    "        current = proposed\n",
+    "#     print('!! Finished loci')\n",
+    "    seek_steps = 0\n",
+    "    while not (current.x == loci[l].x and current.y == loci[l].y) and seek_steps < seek_step_limit:\n",
+    "#         error = max(abs(current.x - loci[l].x), abs(current.y - loci[l].y))\n",
+    "#         s, proposed = wander_near(loci[l], current, limit=error+1)\n",
+    "        s, proposed = seek(loci[l], current)\n",
+    "        trail += s\n",
+    "        current = proposed\n",
+    "        seek_steps += 1\n",
+    "    if seek_steps >= seek_step_limit and not return_anyway:\n",
+    "        return ''\n",
+    "    else:\n",
+    "        return trail"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\nhMqGoYtNhANGByBP3bLhxWPIPI4M8pSuE9AJQL7SdQJzGCAcgDybqBOQGIQ8dUcHJAahC3UCMLi6\nQ4TKhqGLTYQDyoYhz6rE4KpxxWMt6gT+uNvt7kXEXyLio4i4GRHPIuL9iPgiIn4ZEXfb8l9FxO2I\n+Doi7kXENxHxoP3sb2353Yj4Z/v5fyPivYi4FRF/j4iHbb1PI+JncdlLXrT1P23r34+Ix22/1yPi\neWvL56199yPiUUR83Lb9tO3zq4j4eXvvX9u23o+IJ60tT9u+b7W2PmzrfR4RH0TED21/tyPik7b+\nvdbuX8TlyTyLiDuLtj5obfkoLs/bs8Xv/2Fb/9Hecbvfvn/QtvV4r633I+L79v61x+1aRLxo2/+s\nHav94/Zt2+eX7fdbnuM77Xje3zvHjw8ctxdx+Tez39ZP2vmIuLzt9vK43W/n6MNXnOP57/Hjtt3/\n7J3j5XG7036HBxHxXdvO3Jb57/GzdtxetvN4q7Vvbuuhc/yPxXGb23qz7eNu/P9n41Hb1qHPxsNY\nY5qm9K+4/EP5U1z+QU3tQE97X98tXv/rwPKLxesnB5ZPr1h+fmD5l4vX3x9Y/s3i9b8PLH++eP3V\nEW059PXF4vUPB5Yvt//tgeVPrzhuZyvbcuhredyeH1j+9RXn+NkRx+2qtiyXv7yirc8OLL/qHL94\nxbbWnOMnr9juofP29MDyYz4bfzj287kz1R/GZnQABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEY\nnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMHpBGBwOgEYnE4ABqcTgMH9D868\nJ7EMO+IfAAAAAElFTkSuQmCC\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea71b8cc0>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "def square_tour(a=80):\n",
+    "    \"a is width of square\"\n",
+    "    return ('F' * a + 'L') * 4\n",
+    "\n",
+    "plot_trace(trace_tour(square_tour()))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea71dde10>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "def cross_tour(a=50, b=40):\n",
+    "    \"a is width of cross arm, b is length of cross arm\"\n",
+    "    return ('F' *  a + 'L' + 'F' * b + 'R' + 'F' * b + 'L') * 4\n",
+    "\n",
+    "plot_trace(trace_tour(cross_tour()))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\ndwO41XcnEvOQAd2izoOgzsuuu3sOPO27E4k5xfLxGrmnwHbfnUjM49gCjhi07DaBT/vuRGKuYfn4\nQUtp+wzVVZz5WBUtH5/SjuepRJ3rpLsDwrRoTVg+fuBcJ90dYfKxKlo+PqURg7UH6lwn3T3A0m5V\nt4C7bQukFBhS6ksqXCfdXcPp9lUbhDxDo5ROJfx0rDPH0J3l4+teYfn4QTPH0N0bLB9fZfn4gTMw\ndPch5hiqLB8/cAbL7lLax1NxA8vHa+S2McdQdUgo79YopWjqsLnOEUN3K6T1AZiCQyL3lUgpMDhi\nqPNrtu7uA5/03YnE3GdAU6ItH19nsOzuHa7HqkGVj/c7+zpPr7rbxlvUVe0xoKsrPZ/WRbiG5eOr\njgnXkDRKKTCozu3T3V0sH181qPLxKZ3WpMLy8d0dE7nEeIQyIsdbSgejB0FdSoF7qCwfX7dD5NhP\naccz0aaLsEEYOmsiJ5LTSykwqM5g2d0NTD5WPSJy/UhKpxKbWZatEL62LCPaKuE76Kz498uEU47y\ngMmmll3h/UhYtlW+9tLU801tvy2ey6b+nQtoe2Xq+ayhbfAr3Hk4Ap5lWfaQ5vXdtm1XeX+fnN4H\nc8K2L5+fbqtt2/6xbTP1+mzq75z395v8jLan98mcyKl7SoHhD313IEHec7G73wJ/CvzUd0cS829t\nT2Z57vQBSe8zxyCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnG\nwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnGwCCpxsAgqcbAIKnm/wGyPjyrfbBoQAAAAABJRU5ErkJg\ngg==\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6f8a160>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "def quincunx_tour(a=60, b=30, c=50):\n",
+    "    \"a is length of indent, b is indent/outdent distance, c is outdent outer length\"\n",
+    "    return ('F' * a + 'R' + 'F' * b + 'L' + 'F' * c + 'L' + 'F' * c + 'L' + 'F' * b + 'R') * 4\n",
+    "plot_trace(trace_tour(quincunx_tour()))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n1sd/Aw+RJa+eq45oAAAAAElFTkSuQmCC\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6d354e0>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "heart_points = [Step(60, 50, Direction.UP), Step(50, 90, Direction.UP),\n",
+    "                Step(20, 70, Direction.UP), \n",
+    "                Step(-40, 90, Direction.UP), Step(-60, 80, Direction.UP), \n",
+    "                Step(0, 0, Direction.RIGHT)]\n",
+    "\n",
+    "heart_tour = ''\n",
+    "current = Step(0, 0, Direction.RIGHT)\n",
+    "\n",
+    "for hp in heart_points:\n",
+    "    while not (current.x == hp.x and current.y == hp.y):\n",
+    "        s, proposed = seek(hp, current)\n",
+    "        heart_tour += s\n",
+    "        current = proposed\n",
+    "\n",
+    "plot_trace(trace_tour(heart_tour))\n",
+    "\n",
+    "def heart_tour_func(): return heart_tour"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def trim_some_mistakes(tour, mistake_limit):\n",
+    "    trimmed_tour = rw\n",
+    "    mistake_count = len(mistake_positions(trace_tour(trimmed_tour)))\n",
+    "    while len(mistake_positions(trace_tour(trimmed_tour))) > mistake_limit:\n",
+    "        trimmed_tour = trim_loop(trimmed_tour, random_mistake=True)\n",
+    "    return trimmed_tour"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 68,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "10"
+      ]
+     },
+     "execution_count": 68,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\nJogA7b/FLob4OhrHyQAAAABJRU5ErkJggg==\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6b5b1d0>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[0]))\n",
+    "len(sample_tours[0])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\nAElFTkSuQmCC\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6ff01d0>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[1]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAASMAAAEACAYAAAD4GBC1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAACyxJREFUeJzt3W2spHdZx/Hvr552d8v2KV2FtkELGGwgkKLUB4Lb8sKm\nGB8SFXVfaGJB1FKrCUrarRVNoUDTghqr2GAjwRgxohKDDzFRUw3gAxXUhCUNqAlSoK1uS93ubrvn\n8sV9L6jJdncbz/2/zsz3k0w607S5rplz5nv+M2/uVBWSNNoZoxeQJDBGkpowRpJaMEaSWjBGklow\nRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBG\nklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGklowRpJaMEaS\nWjBGklowRpJaMEaSWjBGklowRpJaMEaSWjBGC0qyO8nrklw0ehepm43RC6yDJLuBG4AbgV3AlyW5\ne8EVjlXVEwvOk05bqmr0DisvyYPAnvlhARmwxtdW1T8MmCudEj+mLWMP8H7gILAJXFdVWeIG7J9n\n3jbw+UsnZYyWcy9wMfBa4H1LDJw/Ht7E9HO+MsmLl5grPR3GaEFV9XhV3VNVn19o5JXAM+b7O4B9\nC82VTpsxWm1/DFw+378WePPAXaSnZIxWWFVtVtU/zQ8PVNVjQxeSnoIxktSCMZLUgjGS1IIxktSC\nMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIx\nktSCMZLUgjGS1IIxktSCMdpCSc5I8h3zw71Jnjt0IamxjdELrLgXAe+f738bcAT4vnHrSH2t1cko\nyZ4ktyW5YqGR/wgcv4jiEeAdC82Vtp21OBkleSbwU8B1wE7g8iR3LDT+PcBbgfuq6sMLzZS2nbWI\nEXAfcPH/ePzK+bak/QvPAyDJhcAhYM+I+dKpWpePaRcD9wIfAwp4W1Vl4dtfDXrub2A6Df7MoPnS\nKVmXGAE8CLwEuAq4fewqy5hPRdcz/ZxfnOTlg1eSTmidYkRN7q2q/xi9y0K+Dtg13z8b+JaBu0hP\naV2+M1pXfwZcABwErgb+Yuw60omt1clo3cwnwUfmh49W1ZNDF5KegjGS1IIxktSCMZLUgjGS1IIx\nktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS1IIxktSCMZLUgjGS\n1IIxktSCMZLUgjGS1MJKxyiTV88Pr0myd+hCkk5opWMEXAjcDWwyXVn1bWPXkXQiKx2jqnoI+C2m\nGD0OvHGp2UneneR1SXYsNfNkklyV5A+SPGfA7CT5ziS/n+TCAfM3kvxAkt8Z8TNJsjPJDUnuWXr2\ndpGqGr3DlprfePcDDwJ3LTj6VuAQcBi4raruXHD2/5KkgAPAs4GdwJ8CH1pwhcPAa4GLgN3AbwCf\nXHD+E8ANwLnz/NuBLyw4/0zgx4EdwNnALQvOBri7qj6/8MzTtvIxAkjyLuDVJ/0Pt8ZR4Czg+6vq\nvSMWSPIR4HLGnYT/EzgH2Bg0/2GmEJ05aP5jTL8DZw2a/1ngkqraHDT/lKz0x7Tjquo1VZUlb8AR\npjfhG+Y1Lhn3CvBS4Grgo/PjVy78WuwBvhf41Dz/hQvPfxbwI0xvygLOX3j+VwA3AgeBQwvPPQSc\nB3zXMr9qT19qDU5GIyR5LvCZqjo8f0x6fVW9ffBOAS4DDtSAH3ySM4DnV9WBpWfP8zeA51TV/YPm\n7wKeVVX/stC8twPXMX08/FfgedX4dDTq2LzyqupTJ/+vljUH6OMD528yfXc1av6TTN8fjpr/OLBI\niGYvYAoRTB+Tz2U6nbW0Fh/TpHVUVdcAH5jv76mqtiECYySpCWMkqQVjJKkFYySpBWMkqQVjJKkF\nYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVjJKkFYySpBWMkqQVj\nJKkFYySpBWMkqQVjtIWSnD1f1RPg+iRXD11IaswYba1nAz85378U2DduFam3tYpRkquSfDjJq5aY\nV1WfYLqi5yZwBPj5JeZqvSXZl+SDSfaO3uV0ZLr8+mpL8grgDuBrgGfM//pPFhq/G3g58J6q+sGF\nZqqJJGcBtzP97i3lmvmf/wU8AZxfVVlw/tOyLjEq4BjwJLBjwAoHga+vqvsHzNZASd4E3Dxo/BEg\nwJuq6tZBO5yydfqY9kfArwBHgZurKgveLjBE6yfJucBPMP3O3bbU7xvT1wFHgV8GLtkOIYL1Ohm9\nr6q+J8l5wKO1Dk9cQyW5helUtAM4DFxUVQcXmHsGcE5VPbLVs/4/rdPJCICqesQQaSG7+NLXAp/h\nS99Xbqmq2txuIQLYGL2AtKqqan+SR4G3VNXzRu/T3dqdjCT1ZIwktWCMJLVgjCS1YIwktWCMJLVg\njCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCM\nJLVgjCS1YIwktbDSMUqyI8l754ffneSnhy4k6YRWOkbATuDb5/sFfPNSg5NkqVkdjX7+o+fr9K10\njOZL/N7BdJ3zw8BNC47/eJLfS3LZgjNbSHIp8ECSO5PsGTD/CuCzSW5Ocs7S8/X0ZNUvO5/kfOAB\nIMDRBUefAxybZ34Q+NaqWnL+FyV5I/D6BUceD8BhYBP4a+CbBsw/xPQz+IWq+tkF539Rkv3Am6vK\nk9pJrHyMAJJcC/z6gNHF9IbcBVxfVXctvUCSlwD3LT13dpQpRh8DvmHA/MNMf4R2jIpBkl8Cfgz4\nyqp6YMQO28VKf0w7rqruqaoseQM+DfwlsHdeY8egp387UxQfYn5TLvDcvxr4AvCbwPOr6hsXfu1f\nBjwG3AW8atDrTpIvB17D9PrfMmqP7WJj9AIr7NKqOgYw6rvU+VT0CqbTwbnAtcA7t3puVX0yyQXH\nn//SqupDSc6vqmNJ9p78/9gyNwFnMr3PfjjJrZ6OTmwtTkYjjHoj/h+HgL+d7/870+loEaOf/+j5\ns39j+kMA0/eGQ74z3C48Ga2wqvoE8LIkBeyrqr8ZvdM6qapfTLILeEtVXTl6n+48GUlqwRhJasEY\nSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYSWrBGElqwRhJ\nasEYSWrBGElqwRhJasEYSWrBGElqwRhJasEYbaEkFyf56PzwziQ3Dl1ozST5IeB35/v/nOSFg1fS\nUzBGW+sY8IL5/lFg51KDkyw2q7ENpst6A1zG9PNYhK//6TNGW6iqPsd0bfsn5ts7lpib5Dzg4SR/\nnuSlS8xs6t3AI0ABf1hVB5YYmmQfcDDJncDZS8xcBamq0TustCTPBD7NmEuJF3CE6UR2RVX9/YAd\nhkryo8CvDhi9yXQa3gA2qioDdthWRrxB1kpVfW7+S/lzC47dDXwVU4g2gV8DPrLg/E7eBbwIWPJa\n98e/m3oSeBjYv+DsbcuT0QpKshv4O+ADwFur6qHBK62VJFcDdzH9Afrtqlrsu6rtzBhJasEvsCW1\nYIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVg\njCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCM\nJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktWCMJLVgjCS1YIwk\ntWCMJLVgjCS1YIwktWCMJLVgjCS1YIwktfDfe+gKnnXxV4YAAAAASUVORK5CYII=\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea700c4e0>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(sample_tours[2]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['FLRFRFFFRFFFRFFR',\n",
+       " 'FFFRFRFRLR',\n",
+       " 'FFFFRFRFRLFR',\n",
+       " 'FFFLFFLFFLFF',\n",
+       " 'FFRRFLRRFR',\n",
+       " 'RLRFFRFRFFFR',\n",
+       " 'LFRFLLFFFLFFLF',\n",
+       " 'RLFFLFLFLR',\n",
+       " 'RFFFLLRFFFLLRRLLFFFF',\n",
+       " 'FLFFLFFLFLRL']"
+      ]
+     },
+     "execution_count": 40,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "samples = []\n",
+    "while len(samples) < 10:\n",
+    "    t = valid_prefix(random_walk())\n",
+    "    if len(t) > 8 and len(t) < 25:\n",
+    "        samples += [t]\n",
+    "samples"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6ba2c50>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(samples[2]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1"
+      ]
+     },
+     "execution_count": 44,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mistakes = [t.strip() for t in open('tours-random-walk.txt').readlines()\n",
+    "           if len(t) > 8\n",
+    "           if len(t) < 26]\n",
+    "len(mistakes)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQMAAAEACAYAAAC3RRNlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAABydJREFUeJzt3U+o9XldwPH3x+axNEpwEBSdCO0PghCG6MI/S5HAoF0h\n1CJIIm2VtHCgbBPSQkGFESxQN6H1UC4E2wRFCv2hmCisQCnJzGxIcWaceXS+Le43Eheiz7nnnLnn\neb3gcM/Z3M/nHu593/P7bb6z1grgGedeAHh6EAOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOg\nEgNgEwOgEgNgEwOgEgNgEwOgEoMbY2aeOzM/eu49uFyz1jr3DjfezDyj44f1o9VPV7ert6+1/vnI\n87jHiME1mJn3Vr9yonFPVat62Vrr0yeayT3AZcL1+NXq1pEff9RVCG5X31O5ZOBa3XfuBS7BWuup\nrv5Qj2ZmfrG6f631LzPj4xzXTgxuiLXWI9Uj596Dy+UyAajEANjEAKjEANjEAKjEANjEAKjEANjE\nAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjE4EaZmefMzL/ulx+bmdefdSEu\nihhco5l53sy8fmbmSCMe7eoAlaonq38/0hzuQc5NuAYz8/zq16s3V8+qXjszjx9p3EPVO6pPrLX+\n4UgzuAc5a/EazMxXq+8/8difWGs9fOKZXDAxuAb7uLOPVq+sXlT9wFrrWJ8M4CjcM7g+/1i9uPoh\nIeAmcs/gGu0DWD9/7j3gbvhkAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRi\nAGxiAFRiAGxiAFRiAGxiAFRiAGxiAFRicJCZuTUzX9wvf2Nm3nLWheAAFx2DmXlgZt48M7eO8f3X\nWneqT1ereqz6y2PMgVO4yHMTZubF1YPVz1XfVz0wM5870ri/qF5T/fVaSwy4sS7yeLWZ+VJ1f1f/\nsY91IvK3evVa65MnmgXX7lJjsKo/q56oXle9ZK3l+HL4Ni7yMmH7ylrrjTPz7LXWY+deBp7uLvoG\nYpUQwHfm4mMAfGfEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjEANjEAKjE\nANjEAKjEANjEAKguMAYz84P76XNm5nvPugzcIBcXg+rh/fW11TvPuQjcJJcYg49XT1aPVh871pCZ\necXMvP2bPonAjXZxJyrNzAuqf6v+p7p9xFG/UN3q6sDV91dvW5f2ZnJPubgYVM3M71S/dqJxX+vq\ncNdfXms9dKKZcO0u8TKhtdbb1lpzzEf11uo/q7fssc8/308Mh7vIGJzCWuu91QvWWr977l3gOojB\nAdwj4JKIAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJAbCJAVCJ\nAbCJAVCJAbCJwYFm5iX76Y/MzLPPugwcQAwOMDO3+v+zHd/U1VkKcCOJwQHWWneqP66+3tXJSh85\n70Zw98TgcA929T7eXmt99tzLwN0SgwOttT7T1fv4T+feBQ4hBtfHe8mN5hcYqMQA2MQAqMQA2MQA\nqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MQAqMQA2MTgQDPz\nqv30VTPz3LMuAwcQgwPssxb/dL98Q/VLZ1wHDiIGB9hnLX6wulM9vp/DjSQGh/utaqoPr7X+49zL\nwN0SgwPtANxXCQE3mhgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgA\nlRgAmxgAlRgAmxgAlRgAmxgAlRgAmxgAlRgcbGbeuJ/+1My88KzLwAHE4AD7rMXf3y9fUb3pjOvA\nQcTgAPusxfdUT1aPVR841qyZeXBmPjUzrznWjG+Z976Z+ZOZefmJ5t2emT+YmR870bw/n5nfm5kH\nTjDrmTPz8My8a2aed+x5d2vWWufe4Ubbx7B/obp1opGPV5+rTvJHUz1RfaZ66QlmPVV9vfps9eMn\nmHenWtXnqx8+wbwn9tefX2t95ATzviv3nXuBm26t9cjM/Ez1jq4OYD2Wn6y+0dUv799VXz3irP+b\nd2c//rarCB173pPV16q/qR49wbw7Xb2Pf1U9csRZz6xetuf9d1cxf9rxyeCGmJmfrV5Z/fZa679O\nMO+t1f3Vu9ZaXz7BvN+svlw9tNY6dniamXdXf199aF/uHXPWfdVD1SeqP1xrPXXMeXdLDIDKDURg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOg\nEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNgEwOgEgNg\nEwOgEgNgEwOgEgNgEwOgEgNgEwOgqv8F9Hl5y6i1C9AAAAAASUVORK5CYII=\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea7040b70>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(mistakes[0]))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(212,\n",
+       " 94,\n",
+       " 'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL')"
+      ]
+     },
+     "execution_count": 48,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\ngg==\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea7095780>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "lc = trace_tour(square_tour(a=10))\n",
+    "rw = guided_walk(lc, wander_limit=4, locus_limit=2)\n",
+    "rw_trimmed = trim_all_loops(rw)\n",
+    "plot_trace(trace_tour(rw_trimmed))\n",
+    "len(rw), len(rw_trimmed), rw_trimmed"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['LFLLFFFFLLLFFRFRFF',\n",
+       " 'LFFLLFFL',\n",
+       " 'FRFFRRFFFFFFLLRLRLRLLFFF',\n",
+       " 'RFFRRRFLFFFFLFLFRLLF',\n",
+       " 'LFFRFRFFFFFRFFRLRFRF',\n",
+       " 'LFFRFRFRFL',\n",
+       " 'FLFFLLFFRLLL',\n",
+       " 'FLLFFLLF',\n",
+       " 'FFLLRLRLLFLR',\n",
+       " 'FRRLLFLFFFFLFFFLLFFRRFLL',\n",
+       " 'FRFRRFFF',\n",
+       " 'FFFRFRRFFFFFFLFLFFFLRR',\n",
+       " 'FFRRRFFLRLFRLFLFLFRFLF',\n",
+       " 'RFFRRFFR',\n",
+       " 'LFFFFRRRFLFFFL',\n",
+       " 'FFLLLRRLLL',\n",
+       " 'FFRFFRFRFRLL',\n",
+       " 'RFLFFFFRRFFFFFRFFLLLLR',\n",
+       " 'RRLLRRFFRFRFLR',\n",
+       " 'FFRFRFFRFR']"
+      ]
+     },
+     "execution_count": 66,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mistakes = []\n",
+    "while len(mistakes) < 20:\n",
+    "    lc = trace_tour(square_tour(a=8))\n",
+    "    rw = guided_walk(lc, wander_limit=4, locus_limit=2)\n",
+    "    rw_trimmed = trim_some_mistakes(rw, 2)\n",
+    "    if len(rw_trimmed) > 6 and len(rw_trimmed) < 25:\n",
+    "        mistakes += [rw_trimmed]\n",
+    "mistakes"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 67,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "317"
+      ]
+     },
+     "execution_count": 67,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open('mistakes.txt', 'w').write('\\n'.join(mistakes))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 69,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "137"
+      ]
+     },
+     "execution_count": 69,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "open('samples.txt', 'w').write('\\n'.join(samples))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 71,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('FFRRFLRRFR', 10)"
+      ]
+     },
+     "execution_count": 71,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "samples[4], len(samples[4])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('RRLLRRFFRFRFLR', 14)"
+      ]
+     },
+     "execution_count": 83,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mistakes[18], len(mistakes[18])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 74,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'RRFFLLFFFFLF'"
+      ]
+     },
+     "execution_count": 74,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6e5cac8>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "t = trim_all_loops(random_walk(20))\n",
+    "plot_trace(trace_tour(t))\n",
+    "t"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 76,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "t2 = 'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL'\n",
+    "t2a = t2[:51]\n",
+    "t2b = t2[51:]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFF'"
+      ]
+     },
+     "execution_count": 80,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\nAElFTkSuQmCC\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6fc12e8>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(t2a))\n",
+    "t2a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 81,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'FLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL'"
+      ]
+     },
+     "execution_count": 81,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6c4e550>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(t2b))\n",
+    "t2b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 84,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "(94,\n",
+       " 'FFRFLLFFFRLRRFFFLFLRRFLLFFFFFRFLFFFFFRLLFRFRLLFFFFFFLRFFRLLFRFFFLFFLFFRFRRLLFFRLFFFFFLLFFRFRFL')"
+      ]
+     },
+     "execution_count": 84,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAP4AAAEACAYAAACTecuMAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADo5JREFUeJzt3X/sZFV5x/HPs1+oLt0VDVn4sgILSlfMgkqVttjY9Mcq\nglJJV9GUosTaKAbLP7VNSZo0TYox9o/WNqXxRzSm2taGYkzRYktUSNhKu1JpgSylZYGybEAbYXdl\nF9h9+sec0cGuzDmzc+acO8/7lXxzL8k5c57Lnc/Mnc0595q7C0Asa1oXAGDxCD4QEMEHAiL4QEAE\nHwiI4AMBEXwgIIIPBETwgYAIPhAQwQcCIvhAQAQfCIjgAwERfCAggg8ERPCBgAg+EBDBBwIi+EBA\nBB8IiOBXYmZrzMxa13G0zGylsH3xcc8wRlH7RYwxtPNN8CswszdIOiTpsJl5xt9hM/u91nX/MDP7\nc0nPZB6Dm9kulR/3rYVj7Chs/7iZ3V/Y5+sLOO6m55vg13FDYXuT9AdmtqVGMUfhytYFLKnm5/uY\nVgMvueMk7ZG00TOeWGJmn5b0LklPV65rFqe4+8O5jc1sjSTPOe6JPivufqhW+0WMUXLcPZxvvvEr\nKnjzX5/a31uxnFkdLmns7odLQp/6FIW4tP0ixig87ubnm+ADARF8ICCCDwRE8IGACD4QEMEHAiL4\nQEAEv57V1gUcDTN7Ydod9HHgyJi5N2dm9ryJfSucwfY5SX8q6amM5sdK+lVJd0i6M+flJZ0j6TxJ\nn8xo/5a0vTSNgR/BzI6R9MrM5i+V9OsVy8lihZOskMHM7pC0293flNn+dEl3S1pbsaxZbXT3R1oX\n0TMzu1nSLxZ22+XuZ9SoJwfBr8DMXNIedz+5oM8GST8r6YvuPnWabJobfrGk7e7+aOYYmzUK8tdy\n68JzS1d4B9J/rpl2hWdmx0vaqtF5bjZXn+BXMEvwMVzpfB9y98H8dOYf94D5eKx1ASUIPhAQwQcC\nIvhAQAQfCIjgAwERfCAggg8E1F3w04MJTi/sc1qaL53bfq2ZFU2uMbOs6ZUTc/VXh/SABcTS1Uyj\ntCLs3yWdMktmSvsUtH9U0omFr7+99G6zGKwHJD3YuogSXQVf0usknZL2Pytpf0afvZIuk/S4pK9n\njrNW0uWSPpbZ/tuSrpH0VUn/mdH+CUm/n/naGLB0hbdJ0qbS1ZgtdTVX38wu1mjxApfIGIT0c+6w\nJA3pfdvdb3xgSCa+4fc0LaQQwQcCIvhAQAQfCIjgAwERfCAggg8ERPCBgHoL/vmSZGYntC4EWGa9\nTdkdT9fdIumWloUAhV5kZvsl/WVm+yck/Zbyp6b/l6Q/yrn1eo7epuxeIukGZdyfHOiFmX1A0kcL\nu+1R+ePJPuTu1xT2OaLegs9cfQxSeiDKAXffm9l+jaRT3f2BjLZnarQ47IC7z+VpS71d6gOD5O5F\n99VPl+xTQ5/a3peWhH94htKOqLd/3AOwAAQfCIjgAwERfCAggg8ERPCBgAg+EFBvwV8nff8GhgAq\n6S3470vbrU2rADpiZhfO+zV7m7l3naRzJd3WuhCgFjN7haRvzdD1m/Oqobfg75e03t1zVisBQ/Wh\ntL1K0j9ntL9a0t+4+43zKqC34AMR3CTpIkmfcPeDGe3fOe8CevuND0RwvyRlhr4Kgg8ERPCBgAg+\nEBDBBwIi+EBABB8IiOADAfUW/G2SZGabcxqb2UrpAKV9ZhkD6F1vwd+dtjvNzKf9SXrGzHaY2cGc\n9hN97i5s/1esGMQcNZ8x21vwr5X05dZFHME7VP7wA+BHOU+SzGxLqwKaf/JMcvd9Gs1hzmJmK+5+\nqGSM0j7pUv+ZkjGAKTam7dOtCujtG79Iaehn6TPLGMAU10uSu9/bqoBBBx/AbAg+EBDBBwIi+EBA\nBB8IiOADARF8ICCCP4WZvTDtMnMPS6OrmXuzMLNVSddIukPSnZnd7nL3A5ltt6XtpWkMYPDM3VvX\ncFTM7AlJ6wu73SXpHM84eDNbJ2mvpLPcfecMJQLPYmbvkPQxSRvTNPWFW4ZL/fWS/lrSSe5u0/5S\nny2SNuS8+MSJeaJC7YjpSo3et+e3KmAZgi9JO9390cy22yWpoD0wb3+Rtv/UqoBlCX6J77QuAOHt\nk6Scn5q1RAw+EB7BBwIi+EBABB8IiOADARF8ICCCDwQ06OCb2Zlp93dm6HtyZrtfSbu/UToG0Kuh\nL9LZI+mQpD8r6LMrbXcXPiNje0lj4DmsSJKZWatJPIMOvrvvS/e9/15Bt9/WaJ70uzRaKJHja2o4\nvRJLZ3wV+TpJt7QoYNDBn5D9qenuT0q6Iv0BLfxP2t7VqoBB/8YHBmq8UKzZuhGCDwRE8IGACD4Q\nEMEHAiL4QEAEHwiI4AMBDTr4ZrY27f5C00KAgRl08CWdmrbHNa0CGJhBB9/d7027X2haCFDmVCl/\nhWgNgw7+hGNbFwAUGC/SOb1VAcsSfGBI/kSS3L3ZUm+CDwRE8IGACD4QEMEHAiL4QEAEHwiI4AMB\nLUvwj29dADAk3QXfzDaY2SVmNrU2Mzs77b63clnAUunq9tpmdrqkuyWtTf+d2/X9dSoCqhg/UOMY\nd3+mRQFdBV/SORqF/nMaPR3nqYw++9x9Z9WqgPkaP47tlyTd1KKA3oIvSXL3y1rXAFR0k6SLNHpC\nUxPd/cYHArhfktz9YKsCCD4QEMEHAiL4QEAEHwiI4AMBEXwgIIIPBNRb8LdJkpltbl0IkMPM1ljB\n3PKkee56m7m3O225XTaaSCH+qKSrCrrtNbMDkjbUqWr+mn/y/JB/kSR3v6t1IQhrq8pCL0k+wzh/\nOEOfuentG7/JSiVgwv60fY+7f3Ja47R83N09O/xmtuLuh2YtcB56Cz7QlLvfln6yfymz/eEZxmga\neqm/S30AC0DwgYAIPhAQwQcCIvhAQAQfCIjgAwH1FvwzJMnMnte6EGCZ9TaB54K0/Xk1uu0wfsDM\nViW9OLP52zRaa3Gduz9dryrMQ2/B/7hGtx2+uXUh0ZnZyZJ2Sfqxwq6vkvTuuRe0IOm4D2j0gfdI\n43Kq6e1S/5AktXq6CJ7ljRqF/iPubtP+JP1U6ndhu5Ln4o2Sni/p0taF1GQFawuqM7OLJX0xvZHQ\nkJkdq9GTjF7i7vdn9nFJe9z95KrFVTTLcQ9Rb9/46MTE7/QDTQtZsCjHTfCBgAg+EBDBBwIi+EBA\nBB8IiOADARF8IKDegn+1JJnZ+TVe3Myeb2YbC/ucMcMDEwbPzM4obD9eWLUa8f/X0PQW/L9L2125\nHczsU2bmOX+SnpT0cG771Oe/Jd1jZqVz1rtiZltnOG4p/5bnT0l6SNLtJbea7o2ZjdevDPp8T9Pb\nIp2HJMndsxZHmNnLJF0h6TFJN2R0+WVJ35X0FY3mY0+zmvq8TNIJGvaijS+k7Wc0fVba+Ljf7+6P\n5by4u7uZnSqp+HbTnXlr2l4m6dqWhdTUW/BLPZi297j7ezPa57T5f9I34NAdl7bvrnxf96HfS+Eb\nafvNplVU1tulfhF3fzLtfrVpIcNwo9THwxx6NrEw51tNC6ls0MEHMBuCDwRE8IGACD4QEMEHAiL4\nQEAEHwiot+CfL0lmdkLrQsYm5qy/smkhnZuYn7/atBBk6S34p6TtlsJ+NReF/Eza/mTFMRah9lTa\n789tZ5FO/3oL/niRzq05jc1snUb34j9uWtuj8Ldp+9mKYyzC05L2TixCmSt3PyjpAUm3DnyRztlp\n91VNC6mst+CPH6iR+8ZZlbQi6apaBU083OOpWmMsyDZJ6yUdX3GMTZJ+ouLrL8LmtD2vaRWV9Rb8\nIu5+X9r9cNNChuHvJcndv9O6kJ65+/iq8+NNC6ls0MEHMBuCDwRE8IGACD4QEMEHAiL4QEAEHwio\nt+Cvk/qa8mlmx6bdnLvyQtrQugBM11vw35e2W5tW8Wy/lrZX5jQ2s/PM7NzcFzez483srRMfMDl9\nLky3su7GxAM1Vnr54DazTWZ2QS/19KS322tfJ+lcSbflNE4n9HuS9les6R80mq77QTP7YG6nWd5r\nhX0Om9lPu/u/ZrZ/SNLDxUVlcveDZrZD0iO15uqn8327pNcUdr1R0pszx1iXdl+gYT9H4Tn1Fvz9\nkta7e26Qz9Fogc4HJH2kRkHu/oiZbZL04swub9MoYN9QWnswxUskvV7SpyUdzBzjakmXa/Rmzg3+\nlZJkZie6+6OZfUq9WtKeSq8tjc73a9IYOUF+raTflPSmgjHenrZXSPrdkuKGpLfgl/qPtN1ecxB3\n36P8N/SOwpffoR+sAMz1TjO7vLDPg5JOqxj6RRif71vcPef/8w4ze4OkMwvGuF7SJyR9vrS4Ient\nN34Rdx+vMb+naSHDcGfrAo7WIs63u3837da8cmlu0MEHMBuCDwRE8IGACD4QEMEHAiL4QEAEHwio\nt+BvkyQz2zytYWq3UrecPpnZSWm3dBJPNRO37V7NnRtfev5mPN9vTn1/fIa+S6u3mXu703Zn4bz1\n3Kmuy2L8gV0yS/BAjUKOwDVaR5DV2My2Kz1BqUDJ+f43Fdwjf+JDq7cvxbnq7eCulfTlwj63S/rj\nCrV0y93Hi0fuLuh2plTvmy89f2CrpG/XeP0Jpef7PkkqWP8xXhl6QUlRQ9PVN76775N0UW57M1tx\n95yFMFjAk2Hc/WZJJ+a2Lz1/M57v0vsojD8glnopb2/f+EUIfZHxAzVqLmEuUnr+FnG+3X28JPxL\ntcdqadDBBzAbgg8ERPCBgAg+EBDBBwIi+EBABB8IiOAPkJmNz9vLmxYyDK9oXUCPupq5h2xnp+3P\nmdmrM9q/VtJZFevp2WmSZGavl/S/U9q+QNJ7qlfUAav07ANUdDQPlnD3rAdLLAszu0LSpwq77Zd0\nUk+zHOeN4AeQHghylqSv1HrKzTJIS4svkfSP7v5463pqIvhAQPzjHhAQwQcCIvhAQAQfCIjgAwER\nfCAggg8ERPCBgAg+EBDBBwIi+EBABB8IiOADARF8ICCCDwRE8IGACD4QEMEHAiL4QEAEHwiI4AMB\nEXwgIIIPBETwgYAIPhAQwQcCIvhAQAQfCIjgAwERfCAggg8E9H9g3ys8YjIz8gAAAABJRU5ErkJg\ngg==\n",
+      "text/plain": [
+       "<matplotlib.figure.Figure at 0x7fdea6e6ca20>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "plot_trace(trace_tour(t2a + t2b))\n",
+    "len(t2a + t2b), t2a + t2b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.5.2+"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
index 9a0a4e14f53a311727a5fe383d50b41bc552d6fe..11bba605beee992edd10b613a5b619cb4f44ee78 100644 (file)
@@ -11,7 +11,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 2,
    "metadata": {
     "collapsed": true
    },
@@ -28,7 +28,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 3,
    "metadata": {
     "collapsed": true
    },
@@ -55,7 +55,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "metadata": {
     "collapsed": true
    },
@@ -67,7 +67,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "metadata": {
     "collapsed": true
    },
@@ -86,7 +86,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 8,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 9,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 10,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 11,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 12,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 13,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 14,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 15,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 16,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 17,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 18,
    "metadata": {},
    "outputs": [
     {
        "226"
       ]
      },
-     "execution_count": 23,
+     "execution_count": 18,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 19,
    "metadata": {},
    "outputs": [
     {
        "61762"
       ]
      },
-     "execution_count": 24,
+     "execution_count": 19,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 45,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "1 loop, best of 3: 209 ms per loop\n"
-     ]
+     "data": {
+      "text/plain": [
+       "100"
+      ]
+     },
+     "execution_count": 31,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
-    "%%timeit\n",
-    "sum(len(t) for t in tours if valid(trace_tour(t)))"
+    "sum(1 for t in tours if valid(trace_tour(t)))"
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": 20,
    "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "123845"
+      ]
+     },
+     "execution_count": 20,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
-    "# Part 2"
+    "sum(len(t) for t in tours)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 25,
+   "execution_count": 21,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 1min 29s per loop\n"
+      "1 loop, best of 3: 211 ms per loop\n"
      ]
     }
    ],
    "source": [
     "%%timeit\n",
-    "[(i, j) \n",
-    " for i, pi in enumerate(tours) \n",
-    " for j, pj in enumerate(tours)\n",
-    " if i != j\n",
-    " if not valid(trace_tour(pi))\n",
-    " if not valid(trace_tour(pj))\n",
-    " if valid(trace_tour(pi + pj))]"
+    "sum(len(t) for t in tours if valid(trace_tour(t)))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Part 2"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 31,
+   "execution_count": 23,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "[(16, 125),\n",
-       " (70, 48),\n",
-       " (91, 128),\n",
-       " (110, 134),\n",
-       " (116, 194),\n",
-       " (123, 51),\n",
-       " (136, 9),\n",
-       " (142, 193),\n",
-       " (152, 63),\n",
-       " (168, 150),\n",
-       " (201, 83),\n",
-       " (208, 204),\n",
-       " (212, 113)]"
-      ]
-     },
-     "execution_count": 31,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
-    "[(i, j) \n",
-    " for i, pi in enumerate(tours) \n",
-    " for j, pj in enumerate(tours)\n",
-    " if i != j\n",
-    " if not valid(trace_tour(pi))\n",
-    " if not valid(trace_tour(pj))\n",
-    " if valid(trace_tour(pi + pj))]"
+    "# %%timeit\n",
+    "# [(i, j) \n",
+    "#  for i, pi in enumerate(tours) \n",
+    "#  for j, pj in enumerate(tours)\n",
+    "#  if i != j\n",
+    "#  if not valid(trace_tour(pi))\n",
+    "#  if not valid(trace_tour(pj))\n",
+    "#  if valid(trace_tour(pi + pj))]"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 42,
+   "execution_count": null,
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "80622"
-      ]
-     },
-     "execution_count": 42,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
+   "outputs": [],
    "source": [
-    "(sum(len(t) for t in tours if valid(trace_tour(t)))\n",
-    "    +\n",
-    "    sum(len(pi + pj) \n",
-    "     for i, pi in enumerate(tours) \n",
-    "     for j, pj in enumerate(tours)\n",
-    "     if i != j\n",
-    "     if not valid(trace_tour(pi))\n",
-    "     if not valid(trace_tour(pj))\n",
-    "     if valid(trace_tour(pi + pj)))\n",
-    ")"
+    "# [(i, j) \n",
+    "#  for i, pi in enumerate(tours) \n",
+    "#  for j, pj in enumerate(tours)\n",
+    "#  if i != j\n",
+    "#  if not valid(trace_tour(pi))\n",
+    "#  if not valid(trace_tour(pj))\n",
+    "#  if valid(trace_tour(pi + pj))]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# (sum(len(t) for t in tours if valid(trace_tour(t)))\n",
+    "#     +\n",
+    "#     sum(len(pi + pj) \n",
+    "#      for i, pi in enumerate(tours) \n",
+    "#      for j, pj in enumerate(tours)\n",
+    "#      if i != j\n",
+    "#      if not valid(trace_tour(pi))\n",
+    "#      if not valid(trace_tour(pj))\n",
+    "#      if valid(trace_tour(pi + pj)))\n",
+    "# )"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 24,
    "metadata": {},
    "outputs": [
     {
   },
   {
    "cell_type": "code",
-   "execution_count": 30,
+   "execution_count": 25,
    "metadata": {},
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "[(0, 124),\n",
-       " (1, 1),\n",
+       "[(1, 1),\n",
        " (2, 1),\n",
        " (3, 4),\n",
        " (4, 5),\n",
        " (19, 1)]"
       ]
      },
-     "execution_count": 30,
+     "execution_count": 25,
      "metadata": {},
      "output_type": "execute_result"
     }
    "cell_type": "code",
    "execution_count": 27,
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "1 loop, best of 3: 1min 28s per loop\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
-    "%%timeit\n",
-    "(sum(len(t) for t in tours if valid(trace_tour(t)))\n",
-    "    +\n",
-    "    sum(len(pi + pj) \n",
-    "     for i, pi in enumerate(tours) \n",
-    "     for j, pj in enumerate(tours)\n",
-    "     if i != j\n",
-    "     if not valid(trace_tour(pi))\n",
-    "     if not valid(trace_tour(pj))\n",
-    "     if valid(trace_tour(pi + pj)))\n",
-    ")"
+    "%%timeit\n",
+    "(sum(len(t) for t in tours if valid(trace_tour(t)))\n",
+    "    +\n",
+    "    sum(len(pi + pj) \n",
+    "     for i, pi in enumerate(tours) \n",
+    "     for j, pj in enumerate(tours)\n",
+    "     if i != j\n",
+    "     if not valid(trace_tour(pi))\n",
+    "     if not valid(trace_tour(pj))\n",
+    "     if valid(trace_tour(pi + pj)))\n",
+    ")"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 50,
+   "execution_count": 28,
    "metadata": {
     "collapsed": true
    },
   },
   {
    "cell_type": "code",
-   "execution_count": 51,
+   "execution_count": 29,
    "metadata": {},
    "outputs": [
     {
        "80622"
       ]
      },
-     "execution_count": 51,
+     "execution_count": 29,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 52,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "1 loop, best of 3: 1.16 s per loop\n"
+      "1 loop, best of 3: 1.27 s per loop\n"
      ]
     }
    ],
     ")"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "13"
+      ]
+     },
+     "execution_count": 33,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "len(goods)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(16, 125),\n",
+       " (70, 48),\n",
+       " (91, 128),\n",
+       " (110, 134),\n",
+       " (116, 194),\n",
+       " (123, 51),\n",
+       " (136, 9),\n",
+       " (142, 193),\n",
+       " (152, 63),\n",
+       " (168, 150),\n",
+       " (201, 83),\n",
+       " (208, 204),\n",
+       " (212, 113)]"
+      ]
+     },
+     "execution_count": 37,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted(good_is)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[(136, 9),\n",
+       " (70, 48),\n",
+       " (123, 51),\n",
+       " (152, 63),\n",
+       " (201, 83),\n",
+       " (212, 113),\n",
+       " (16, 125),\n",
+       " (91, 128),\n",
+       " (110, 134),\n",
+       " (168, 150),\n",
+       " (142, 193),\n",
+       " (116, 194),\n",
+       " (208, 204)]"
+      ]
+     },
+     "execution_count": 38,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "sorted(good_is, key=lambda p: p[1])"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,