Removing files from data analysis directory
[ou-summer-of-code-2017.git] / 06-tour-shapes / tour-shapes-build-problem-set.ipynb
1 {
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "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",
8 "1. which tours are closed?\n",
9 "2. what is the area enclosed by the tour?"
10 ]
11 },
12 {
13 "cell_type": "code",
14 "execution_count": 4,
15 "metadata": {
16 "collapsed": true
17 },
18 "outputs": [],
19 "source": [
20 "import collections\n",
21 "import enum\n",
22 "import random\n",
23 "import os\n",
24 "\n",
25 "import matplotlib.pyplot as plt\n",
26 "%matplotlib inline\n"
27 ]
28 },
29 {
30 "cell_type": "code",
31 "execution_count": 5,
32 "metadata": {
33 "collapsed": true
34 },
35 "outputs": [],
36 "source": [
37 "class Direction(enum.Enum):\n",
38 " UP = 1\n",
39 " RIGHT = 2\n",
40 " DOWN = 3\n",
41 " LEFT = 4\n",
42 " \n",
43 "turn_lefts = {Direction.UP: Direction.LEFT, Direction.LEFT: Direction.DOWN,\n",
44 " Direction.DOWN: Direction.RIGHT, Direction.RIGHT: Direction.UP}\n",
45 "\n",
46 "turn_rights = {Direction.UP: Direction.RIGHT, Direction.RIGHT: Direction.DOWN,\n",
47 " Direction.DOWN: Direction.LEFT, Direction.LEFT: Direction.UP}\n",
48 "\n",
49 "def turn_left(d):\n",
50 " return turn_lefts[d]\n",
51 "\n",
52 "def turn_right(d):\n",
53 " return turn_rights[d]\n"
54 ]
55 },
56 {
57 "cell_type": "code",
58 "execution_count": 6,
59 "metadata": {
60 "collapsed": true
61 },
62 "outputs": [],
63 "source": [
64 "Step = collections.namedtuple('Step', ['x', 'y', 'dir'])\n",
65 "Mistake = collections.namedtuple('Mistake', ['i', 'step'])"
66 ]
67 },
68 {
69 "cell_type": "code",
70 "execution_count": 7,
71 "metadata": {
72 "collapsed": true
73 },
74 "outputs": [],
75 "source": [
76 "def advance(step, d):\n",
77 " if d == Direction.UP:\n",
78 " return Step(step.x, step.y+1, d)\n",
79 " elif d == Direction.DOWN:\n",
80 " return Step(step.x, step.y-1, d)\n",
81 " elif d == Direction.LEFT:\n",
82 " return Step(step.x-1, step.y, d)\n",
83 " elif d == Direction.RIGHT:\n",
84 " return Step(step.x+1, step.y, d)"
85 ]
86 },
87 {
88 "cell_type": "code",
89 "execution_count": 8,
90 "metadata": {
91 "collapsed": true
92 },
93 "outputs": [],
94 "source": [
95 "def step(s, current):\n",
96 " if s == 'F':\n",
97 " return advance(current, current.dir)\n",
98 " elif s == 'L':\n",
99 " return advance(current, turn_left(current.dir))\n",
100 " elif s == 'R':\n",
101 " return advance(current, turn_right(current.dir))\n",
102 " else:\n",
103 " raise ValueError"
104 ]
105 },
106 {
107 "cell_type": "code",
108 "execution_count": 9,
109 "metadata": {
110 "collapsed": true
111 },
112 "outputs": [],
113 "source": [
114 "def trace_tour(tour, startx=0, starty=0, startdir=Direction.RIGHT):\n",
115 " current = Step(startx, starty, startdir)\n",
116 " trace = [current]\n",
117 " for s in tour:\n",
118 " current = step(s, current)\n",
119 " trace += [current]\n",
120 " return trace "
121 ]
122 },
123 {
124 "cell_type": "code",
125 "execution_count": 10,
126 "metadata": {
127 "collapsed": true
128 },
129 "outputs": [],
130 "source": [
131 "def positions(trace):\n",
132 " return [(s.x, s.y) for s in trace]"
133 ]
134 },
135 {
136 "cell_type": "code",
137 "execution_count": 11,
138 "metadata": {
139 "collapsed": true
140 },
141 "outputs": [],
142 "source": [
143 "def valid(trace):\n",
144 " return (trace[-1].x == 0 \n",
145 " and trace[-1].y == 0 \n",
146 " and len(set(positions(trace))) + 1 == len(trace))"
147 ]
148 },
149 {
150 "cell_type": "code",
151 "execution_count": 12,
152 "metadata": {
153 "collapsed": true
154 },
155 "outputs": [],
156 "source": [
157 "def valid_prefix(tour):\n",
158 " current = Step(0, 0, Direction.RIGHT)\n",
159 " prefix = []\n",
160 " posns = []\n",
161 " for s in tour:\n",
162 " current = step(s, current)\n",
163 " prefix += [s]\n",
164 " if (current.x, current.y) in posns:\n",
165 " return ''\n",
166 " elif current.x == 0 and current.y == 0: \n",
167 " return ''.join(prefix)\n",
168 " posns += [(current.x, current.y)]\n",
169 " if current.x == 0 and current.y == 0:\n",
170 " return ''.join(prefix)\n",
171 " else:\n",
172 " return ''"
173 ]
174 },
175 {
176 "cell_type": "code",
177 "execution_count": 13,
178 "metadata": {
179 "collapsed": true
180 },
181 "outputs": [],
182 "source": [
183 "def mistake_positions(trace, debug=False):\n",
184 " mistakes = []\n",
185 " current = trace[0]\n",
186 " posns = [(0, 0)]\n",
187 " for i, current in enumerate(trace[1:]):\n",
188 " if (current.x, current.y) in posns:\n",
189 " if debug: print(i, current)\n",
190 " mistakes += [Mistake(i+1, current)]\n",
191 " posns += [(current.x, current.y)]\n",
192 " if (current.x, current.y) == (0, 0):\n",
193 " return mistakes[:-1]\n",
194 " else:\n",
195 " return mistakes + [Mistake(len(trace)+1, current)]"
196 ]
197 },
198 {
199 "cell_type": "code",
200 "execution_count": 14,
201 "metadata": {
202 "collapsed": true
203 },
204 "outputs": [],
205 "source": [
206 "def returns_to_origin(mistake_positions):\n",
207 " return [i for i, m in mistake_positions\n",
208 " if (m.x, m.y) == (0, 0)]"
209 ]
210 },
211 {
212 "cell_type": "code",
213 "execution_count": 15,
214 "metadata": {
215 "collapsed": true
216 },
217 "outputs": [],
218 "source": [
219 "sample_tours = ['FFLRLLFLRL', 'FLLFFLFFFLFFLFLLRRFR', 'FFRLLFRLLFFFRFLLRLLRRLLRLL']"
220 ]
221 },
222 {
223 "cell_type": "code",
224 "execution_count": 16,
225 "metadata": {
226 "collapsed": true
227 },
228 "outputs": [],
229 "source": [
230 "def random_walk(steps=1000):\n",
231 " return ''.join(random.choice('FFLR') for _ in range(steps))"
232 ]
233 },
234 {
235 "cell_type": "code",
236 "execution_count": 17,
237 "metadata": {
238 "collapsed": true
239 },
240 "outputs": [],
241 "source": [
242 "def bounds(trace):\n",
243 " return (max(s.x for s in trace),\n",
244 " max(s.y for s in trace),\n",
245 " min(s.x for s in trace),\n",
246 " min(s.y for s in trace))"
247 ]
248 },
249 {
250 "cell_type": "code",
251 "execution_count": 18,
252 "metadata": {
253 "collapsed": true
254 },
255 "outputs": [],
256 "source": [
257 "plot_wh = {Direction.UP: (0, 1), Direction.LEFT: (-1, 0),\n",
258 " Direction.DOWN: (0, -1), Direction.RIGHT: (1, 0)}"
259 ]
260 },
261 {
262 "cell_type": "code",
263 "execution_count": 27,
264 "metadata": {
265 "collapsed": true
266 },
267 "outputs": [],
268 "source": [
269 "def chunks(items, n=2):\n",
270 " return [items[i:i+n] for i in range(len(items) - n + 1)]"
271 ]
272 },
273 {
274 "cell_type": "code",
275 "execution_count": 19,
276 "metadata": {
277 "collapsed": true
278 },
279 "outputs": [],
280 "source": [
281 "def plot_trace(trace, colour='k', highlight_start=True,\n",
282 " xybounds=None, fig=None, subplot_details=None, filename=None):\n",
283 " plt.axis('on')\n",
284 " plt.axes().set_aspect('equal')\n",
285 " \n",
286 " if highlight_start:\n",
287 " plt.axes().add_patch(plt.Circle((trace[0].x, trace[0].y), 0.2, color=colour))\n",
288 " \n",
289 " for s, t in chunks(trace, 2):\n",
290 " w, h = plot_wh[t.dir]\n",
291 " 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",
292 " xh, yh, xl, yl = bounds(trace)\n",
293 " if xybounds is not None: \n",
294 " bxh, byh, bxl, byl = xybounds\n",
295 " plt.xlim([min(xl, bxl)-1, max(xh, bxh)+1])\n",
296 " plt.ylim([min(yl, byl)-1, max(yh, byh)+1])\n",
297 " else:\n",
298 " plt.xlim([xl-1, xh+1])\n",
299 " plt.ylim([yl-1, yh+1])\n",
300 " if filename:\n",
301 " plt.savefig(filename)"
302 ]
303 },
304 {
305 "cell_type": "code",
306 "execution_count": 20,
307 "metadata": {
308 "collapsed": true
309 },
310 "outputs": [],
311 "source": [
312 "def trim_loop(tour, random_mistake=False):\n",
313 " trace = trace_tour(tour)\n",
314 " mistakes = mistake_positions(trace)\n",
315 " if random_mistake:\n",
316 " end_mistake_index = random.randrange(len(mistakes))\n",
317 " else:\n",
318 " end_mistake_index = 0\n",
319 "# 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",
320 " # while this mistake extends to the next step in the trace...\n",
321 " while (mistakes[end_mistake_index].i + 1 < len(trace) and \n",
322 " end_mistake_index + 1 < len(mistakes) and\n",
323 " mistakes[end_mistake_index].i + 1 == \n",
324 " mistakes[end_mistake_index + 1].i):\n",
325 "# 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",
326 " # push this mistake finish point later\n",
327 " end_mistake_index += 1\n",
328 " mistake = mistakes[end_mistake_index]\n",
329 " \n",
330 " # find the first location that mentions where this mistake ends (which the point where the loop starts)\n",
331 " mistake_loop_start = max(i for i, loc in enumerate(trace[:mistake.i])\n",
332 " if (loc.x, loc.y) == (mistake.step.x, mistake.step.y))\n",
333 "# print('Dealing with mistake from', mistake_loop_start, 'to', mistake.i, ', trace has len', len(trace))\n",
334 " \n",
335 " # direction before entering the loop\n",
336 " direction_before = trace[mistake_loop_start].dir\n",
337 " \n",
338 " # find the new instruction to turn from heading before the loop to heading after the loop\n",
339 " new_instruction = 'F'\n",
340 " if (mistake.i + 1) < len(trace):\n",
341 " if turn_left(direction_before) == trace[mistake.i + 1].dir:\n",
342 " new_instruction = 'L'\n",
343 " if turn_right(direction_before) == trace[mistake.i + 1].dir:\n",
344 " new_instruction = 'R'\n",
345 "# if (mistake.i + 1) < len(trace):\n",
346 "# print('turning from', direction_before, 'to', trace[mistake.i + 1].dir, 'with', new_instruction )\n",
347 "# else:\n",
348 "# print('turning from', direction_before, 'to BEYOND END', 'with', new_instruction )\n",
349 " return tour[:mistake_loop_start] + new_instruction + tour[mistake.i+1:]\n",
350 "# return mistake, mistake_loop_start, trace[mistake_loop_start-2:mistake_loop_start+8]"
351 ]
352 },
353 {
354 "cell_type": "code",
355 "execution_count": 21,
356 "metadata": {
357 "collapsed": true
358 },
359 "outputs": [],
360 "source": [
361 "def trim_all_loops(tour, mistake_reduction_attempt_limit=10):\n",
362 " trace = trace_tour(tour)\n",
363 " mistake_limit = 1\n",
364 " if trace[-1].x == 0 and trace[-1].y == 0:\n",
365 " mistake_limit = 0\n",
366 " mistakes = mistake_positions(trace)\n",
367 " \n",
368 " old_mistake_count = len(mistakes)\n",
369 " mistake_reduction_tries = 0\n",
370 " \n",
371 " while len(mistakes) > mistake_limit and mistake_reduction_tries < mistake_reduction_attempt_limit:\n",
372 " tour = trim_loop(tour)\n",
373 " trace = trace_tour(tour)\n",
374 " mistakes = mistake_positions(trace)\n",
375 " if len(mistakes) < old_mistake_count:\n",
376 " old_mistake_count = len(mistakes)\n",
377 " mistake_reduction_tries = 0\n",
378 " else:\n",
379 " mistake_reduction_tries += 1\n",
380 " if mistake_reduction_tries >= mistake_reduction_attempt_limit:\n",
381 " return ''\n",
382 " else:\n",
383 " return tour"
384 ]
385 },
386 {
387 "cell_type": "code",
388 "execution_count": 22,
389 "metadata": {
390 "collapsed": true
391 },
392 "outputs": [],
393 "source": [
394 "def reverse_tour(tour):\n",
395 " def swap(tour_step):\n",
396 " if tour_step == 'R':\n",
397 " return 'L'\n",
398 " elif tour_step == 'L':\n",
399 " return 'R'\n",
400 " else:\n",
401 " return tour_step\n",
402 " \n",
403 " return ''.join(swap(s) for s in reversed(tour))"
404 ]
405 },
406 {
407 "cell_type": "code",
408 "execution_count": 23,
409 "metadata": {
410 "collapsed": true
411 },
412 "outputs": [],
413 "source": [
414 "def wander_near(locus, current, limit=10):\n",
415 " valid_proposal = False\n",
416 " while not valid_proposal:\n",
417 " s = random.choice('FFFRL')\n",
418 " if s == 'F':\n",
419 " proposed = advance(current, current.dir)\n",
420 " elif s == 'L':\n",
421 " proposed = advance(current, turn_left(current.dir))\n",
422 " elif s == 'R':\n",
423 " proposed = advance(current, turn_right(current.dir))\n",
424 " if abs(proposed.x - locus.x) < limit and abs(proposed.y - locus.y) < limit:\n",
425 " valid_proposal = True\n",
426 "# print('At {} going to {} by step {} to {}'.format(current, locus, s, proposed))\n",
427 " return s, proposed"
428 ]
429 },
430 {
431 "cell_type": "code",
432 "execution_count": 24,
433 "metadata": {
434 "collapsed": true
435 },
436 "outputs": [],
437 "source": [
438 "def seek(goal, current):\n",
439 " dx = current.x - goal.x\n",
440 " dy = current.y - goal.y\n",
441 "\n",
442 " if dx < 0 and abs(dx) > abs(dy): # to the left\n",
443 " side = 'left'\n",
444 " if current.dir == Direction.RIGHT:\n",
445 " s = 'F'\n",
446 " elif current.dir == Direction.UP:\n",
447 " s = 'R'\n",
448 " else:\n",
449 " s = 'L'\n",
450 " elif dx > 0 and abs(dx) > abs(dy): # to the right\n",
451 " side = 'right'\n",
452 " if current.dir == Direction.LEFT:\n",
453 " s = 'F'\n",
454 " elif current.dir == Direction.UP:\n",
455 " s = 'L'\n",
456 " else:\n",
457 " s = 'R'\n",
458 " elif dy > 0 and abs(dx) <= abs(dy): # above\n",
459 " side = 'above'\n",
460 " if current.dir == Direction.DOWN:\n",
461 " s = 'F'\n",
462 " elif current.dir == Direction.RIGHT:\n",
463 " s = 'R'\n",
464 " else:\n",
465 " s = 'L'\n",
466 " else: # below\n",
467 " side = 'below'\n",
468 " if current.dir == Direction.UP:\n",
469 " s = 'F'\n",
470 " elif current.dir == Direction.LEFT:\n",
471 " s = 'R'\n",
472 " else:\n",
473 " s = 'L'\n",
474 " if s == 'F':\n",
475 " proposed = advance(current, current.dir)\n",
476 " elif s == 'L':\n",
477 " proposed = advance(current, turn_left(current.dir))\n",
478 " elif s == 'R':\n",
479 " proposed = advance(current, turn_right(current.dir))\n",
480 " \n",
481 "# print('At {} going to {}, currently {}, by step {} to {}'.format(current, goal, side, s, proposed))\n",
482 "\n",
483 " return s, proposed"
484 ]
485 },
486 {
487 "cell_type": "code",
488 "execution_count": 25,
489 "metadata": {
490 "collapsed": true
491 },
492 "outputs": [],
493 "source": [
494 "def guided_walk(loci, locus_limit=5, wander_limit=10, seek_step_limit=20, return_anyway=False):\n",
495 " trail = ''\n",
496 " current = Step(0, 0, Direction.RIGHT) \n",
497 " l = 0\n",
498 " finished = False\n",
499 " while not finished:\n",
500 " if abs(current.x - loci[l].x) < locus_limit and abs(current.y - loci[l].y) < locus_limit:\n",
501 " l += 1\n",
502 " if l == len(loci) - 1:\n",
503 " finished = True\n",
504 " s, proposed = wander_near(loci[l], current, limit=wander_limit)\n",
505 " trail += s\n",
506 " current = proposed\n",
507 "# print('!! Finished loci')\n",
508 " seek_steps = 0\n",
509 " while not (current.x == loci[l].x and current.y == loci[l].y) and seek_steps < seek_step_limit:\n",
510 "# error = max(abs(current.x - loci[l].x), abs(current.y - loci[l].y))\n",
511 "# s, proposed = wander_near(loci[l], current, limit=error+1)\n",
512 " s, proposed = seek(loci[l], current)\n",
513 " trail += s\n",
514 " current = proposed\n",
515 " seek_steps += 1\n",
516 " if seek_steps >= seek_step_limit and not return_anyway:\n",
517 " return ''\n",
518 " else:\n",
519 " return trail"
520 ]
521 },
522 {
523 "cell_type": "code",
524 "execution_count": 28,
525 "metadata": {},
526 "outputs": [
527 {
528 "data": {
529 "image/png": "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\nVLpP4CKFIBNJl6SFQEV+muMwZFu3buWGG25QGDKRAEKHIVsFPOHufxk9LykEWfRehSETqYDQYcgs\n+ouVHIIMNIFIpBKC3V7MzB4E/g+4xMyOmdmtwF3A9WZ2mFwUorvOt424Y1ARiETCSdrxXkoYsn8o\n8lJJIcjyJb2EISLh6H4CItNEqucO6H4CIuGleiqxiISX6pqAhg2LpJdmEYpUuYreWUgdgyLhDAwM\nJFqvIoVA3FbROAGRcLLZbKL1KloIaJyASPqoY1Bkmkj11QF1DIqEp3ECIlUu1TUBDRsWCS/VhYCG\nDYuEl+pbjseZUzgykXBSPU4gPvmTdlyIyPhSPU4gHiSk5oBI+qhjUKTKqWNQZJq4IOMEzOxGM3vV\nzI6Y2e2T2ZaITE7SuTmJCwEzywD/Si5E2Z8DnzSzSwu9V8OGRdJrMjWBK4Hfufsf3H0A+Am58GRj\naNiwSHpN5qxcDryZ9/w4uYJhjPgS4bXXXktHRwdz584FoL+/n9mzZ9Pd3c1FF13E6dOn6ezsZO3a\ntbS2ttLT08PChQvp7Oxk3rx5dHR00NPTw6pVq2htbaWzs5MlS5bQ0dHBzJkz6e/vp6+vj4svvpiW\nlhY6OjpoaGg4p0+it7eX5cuX09raSnt7O2vWrOHtt99mcHCQ+vp6enp6aGpq4u2336a9vZ1169Zx\n8uRJ+vr6mDt3Lt3d3SxcuJCzZ8/S1dXFmjVraG1tpauri2w2S21tLXPmzKGrq4ve3l5Wrlw5ktdl\ny5bR1tZGNptleHiY3t5eVqxYQWtrKx0dHaxcuZIzZ84wPDxMNpult7eXZcuWcfLkSdra2li3bh2n\nTp1iYGCAgYEB6urqRvLa0dHBunXrRvbbggUL6OzspLGxkfb2drq7u1m9evVIXpuamujo6KC+vp6+\nvr4x+23FihW0tbVhZnR0dDBjxoyRvLS3t7N69WpOnz7N0NAQM2fOpKenh6VLl468Hu+3/v5+5syZ\nQ3d3N4sWLeLMmTPnHON4eXyMjx8/Tl1dHatXr6alpYXOzk6WLl1Ke3s7dXV1DA4OjslrvN/cnWw2\nS09PT9Fj3NDQQHd3N01NTRw9epRMJsPatWs5efIkvb29zJ8/n66uLhYsWEBbW9s5+y3+nra3tzNr\n1ix6enrGHOPly5dz9uzZke9cX18fM2fOZGhoiI6ODlatWsXp06cZHh6mrq6Onp6ec/br2rVrOXXq\nVNFzY926dbS0tBQ8N06cOJHsTHb3RH/Ax4H78p5/CrinwPt8y5YtvmzZMgcc8Lq6upHH8V9DQ8PI\n4wULFox5Pf9v8eLFk3p94cKFI4/r6+vHvD5v3ryRx/Pnzx/z+owZMwpua7J5zWazY17P3xezZ88e\n83r+ssbGxjGv19TUjDxetGjRpPKav/7MmTPHvJ6/r+bOnTvm9fx9Xc5jnP8ZCx2X/O9WofwVOsb5\nx2Kyxzj/cxf67ucftzlz5ox5fSLnxvz58725udmbm5sd8JLO5UkUAlcDT+U9vwO4vVAhMFpzc/OY\nZaEoLaV1odO6UJ+p1EJgMn0CvwH+xMxWmVkd8PfkwpOJyBRSUkDSoiub3QjcQ66D8X53HxOOzMyS\nJyAik+IlBCSdVCEgIlOfbioiUuVUCIhUuYoXAiGHGpvZ/WbWYmb78pY1mtkzZnbYzJ42s3llSGeF\nmT1rZgfNbL+Z3RYwrRlm9isz2xOl1RwtX21mL0RpPWRmZRuJZWYZM3vJzB4PmZaZ/d7MXo4+26+j\nZWXfh9F255nZdjM7ZGYHzOyqQMfrkujzvBT9bzOz2wJ+ri+b2Stmts/MfmxmdRM+XqVcQijXH7lC\n5zVgFZAF9gKXlnH7fwtcBuzLW3Y38LXo8e3AXWVIZwlwWfR4NnAYuDREWtG2GqL/NcALwFXAw8Dm\naPm9wD+VcT9+Gfhv4PHoeZC0gKNA46hlofbhfwK3Ro9rgXmh0spLMwO8BVwc6Hu4LNqHdXnH6ZaJ\nHq+yfeASM301sDvvecGxBZNMY9WoQuBVoCl6vAR4NcDnegxYHzotoAF4kdzIzFYgk7dfnypTGiuA\nnwPX5RUCJwOl9QawcNSysu9DYA7weoHloY/XDcD/BPxcy4A/AI1RwfY4cP1EvxuVbg4UGmq8PHCa\nF7l7C4C7nwAWl3PjZraaXO3jBXIHuexpRdXzPcAJcifo68BZd4/njh4n94Uoh+8BXyU3Ag0zWwic\nCZSWA0+b2W/M7PPRshD7cC1wysweiKrp95lZQ6C08n0CeDB6XPa03P0t4LvAMeCPQBvwEhP8blS6\nECh0zXLKXqM0s9nADuBL7t5JoM/i7sPufjm5X+krgXcVettk0zGzjUCLu+/lnWNljD1u5fqc73X3\nvwY2AF80s/eVcdv5aoErgB+6+xVAF7laaLDvnpllgZuB7dGisqdlZvPJTdpbRe5EnwXcVOCt5027\n0oXAcWBl3vMV5NpMIbWYWROAmS0hV1WatKizZQfwX+6+M2RaMXdvB54nV8WbH03nhvLtx2uAm83s\nKPAQ8AHg+8C8AGnFv4i4+0lyTaorCbMPjwNvuvuL0fNHyBUKIY/XTcBv3f1U9DxEWuuBo+5+2t2H\ngEeB9zLB70alC4FKDDUe/cv1OPCZ6PEtwM7RKyT0I+Cgu98TMi0zWxT3JJtZPbkDfxB4DthczrTc\n/RvuvtLd15I7Ns+6+6dCpGVmDVFNCjObRa79vJ8A+zCqhr9pZpdEiz4IHAiRVp5PkitIYyHSOgZc\nbWYzzcx453NN7HiVsyOkxM6MG8n1pv8OuKPM236QXKnXF+2gW8l1mvwiSvPnwPwypHMNMETu6sYe\ncu2wG4EFAdL6i2j7e4F9wL9Ey9cAvwKOkOsNzpZ5X17LOx2DZU8r2ma8//bH34UQ+zDa7rvJ/Qjt\nBX5G7upAqLTqyXWmzslbFiqtZuBQ9N3YRu6q24SOl4YNi1Q5jRgUqXIqBESqnAoBkSqnQkCkyqkQ\nEKlyKgREqpwKAZEqp0JApMr9P8nYgJi0MFyGAAAAAElFTkSuQmCC\n",
530 "text/plain": [
531 "<matplotlib.figure.Figure at 0x7ffba4edcf60>"
532 ]
533 },
534 "metadata": {},
535 "output_type": "display_data"
536 }
537 ],
538 "source": [
539 "def square_tour(a=80):\n",
540 " \"a is width of square\"\n",
541 " return ('F' * a + 'L') * 4\n",
542 "\n",
543 "plot_trace(trace_tour(square_tour()))"
544 ]
545 },
546 {
547 "cell_type": "code",
548 "execution_count": 29,
549 "metadata": {},
550 "outputs": [
551 {
552 "data": {
553 "image/png": "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\nybOEYIzJ+/+3mLJIMXCXRQAAAABJRU5ErkJggg==\n",
554 "text/plain": [
555 "<matplotlib.figure.Figure at 0x7ffba4b355c0>"
556 ]
557 },
558 "metadata": {},
559 "output_type": "display_data"
560 }
561 ],
562 "source": [
563 "def cross_tour(a=50, b=40):\n",
564 " \"a is width of cross arm, b is length of cross arm\"\n",
565 " return ('F' * a + 'L' + 'F' * b + 'R' + 'F' * b + 'L') * 4\n",
566 "\n",
567 "plot_trace(trace_tour(cross_tour()))"
568 ]
569 },
570 {
571 "cell_type": "code",
572 "execution_count": 30,
573 "metadata": {},
574 "outputs": [
575 {
576 "data": {
577 "image/png": "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\n",
578 "text/plain": [
579 "<matplotlib.figure.Figure at 0x7ffba4bf1278>"
580 ]
581 },
582 "metadata": {},
583 "output_type": "display_data"
584 }
585 ],
586 "source": [
587 "def quincunx_tour(a=60, b=30, c=50):\n",
588 " \"a is length of indent, b is indent/outdent distance, c is outdent outer length\"\n",
589 " return ('F' * a + 'R' + 'F' * b + 'L' + 'F' * c + 'L' + 'F' * c + 'L' + 'F' * b + 'R') * 4\n",
590 "plot_trace(trace_tour(quincunx_tour()))"
591 ]
592 },
593 {
594 "cell_type": "code",
595 "execution_count": 31,
596 "metadata": {},
597 "outputs": [
598 {
599 "data": {
600 "image/png": "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\nKEqpEBbSo95XcuDAAe677z6uu+46PvjgA9txlFIhLGTPo6zK1VdfzUsvvcSwYcMAePjhh5k7d67l\nVEqpUFTTFqVXC/fWhogYX+zjs88+Y9CgQZ7r69at8xRPpZTyxsaNG0lOTq72wr1B36J0GzhwYIUB\nntOnT1tOpJSqK0KmUF5q4sSJiAi333677ShKqTAXkoXyyJEjvP/++3To0IG3337bdhylVJgLyULZ\nunVrRo0aRUREBAAdOnRg+vTpllMppYLV5s2b6dOnDxMnTqzR40NmMKcy69atY+zYsZw7dw6Aixcv\nUq9ePb/sSykVusqfFvSTn/yENWvWeG73ZjAnpAvlJfvhwoULREREEBkZWePzpZRS4cM9ABwREUGL\nFi3Iy8ur8POwG/W+EveqxTExMdSrV4/f/OY3lhMppWwzxuBwODyH6Grzqa9h06Istz86dOjAt99+\nG7B9KqWCk4hQUFBAo0aNEJF/6WnWqRblpQ4ePIiIkJqaajuKUirANmzYQGxsrKcoiggOh6NWh+PC\nrlBu3LiRvn370qpVK9auXWs7jlIqwB544AHOnz9P586dmTZtGo0bN671NiN9kCuo/PjHP2b79u2s\nXbuW1NRU3nvvPerXr09qaqoO8CgVxo4cOcL27ds9n7/19ddf+2zbYVco3a6++moAxo4dC8B//dd/\ncc8999iMpJTyozZt2ngujxs3zqfbDruut1vHjh0rzA3fvXu35URKKX978803Mcbwzjvv+HS7YVso\nL7Vo0SJd/FepMLNjx44Ko9nNmzf3y37Ctutd3jfffMOiRYtYu3atLv6rVBhZsWIFAI8++ihxcXGM\nHDnSL/sJu/Mor+See+7hlVde4e6776Zly5b8/ve/tx1JKVUDBw4cYMGCBXz22Wfs2rWr5gvy1rUp\njN7YunUrQ4YM8VzftGkT119/vcVESqmauNzc7Zpsp86ecH45gwcPrjDAc/bsWcuJlFI1NWXKFIwx\nNS6S1VGnCuWlRo8ejYgwefJk21GUUlXIy8urMHDTr1+/gO27TnW9yzt27Bj79u1j+vTpHDlypMbH\nOJRSgbF9+3b69+/PunXrqFevHoMHD8bhqF1bT49Reqlt27Z89913xMfHM3z4cNLT021HUkqVs2nT\nJn79619z+PBhzpw549NGjRZKL61bt44JEyZw5swZoOYfZ6mU8o/yAzcjR47kww8/9Om2tVBWQ2lp\nKZGRkZw7dw5jDA0bNtS54UpZVFRURHFxMbGxsTRq1Mgvg6866l1N7sV/3S/KY489ZjmRUnWXMYb6\n9esTGxsLwNSpU63m8bpFKSIOYDtw2BgzRkQ6AulAHPAFcIcxpqSSx4VEi7I8EaF79+7s27fPdhSl\n6iwR4ejRo7Rs2dJz3R/78HWL8mFgb7nr84EFxphuQAFwV/UiBrcvv/xSF/9VKsA2bNhAgwYNPEXR\nveCu7cNgXhVKEWkLjAaWlLt5OLDCdXkZMN630ezZvHkzgwcPpl27drr4r1IB9Nhjj3HhwgWuvfZa\n7rzzTlq0aGE7EuD9ohj/DjwONAEQkWbAaWNMmevnh4EE38ezY8iQIWzZsoWVK1cyfvx4/vKXvxAd\nHe1Z21Ip5VvfffcdmzZt8nz0dLAti1hloRSRm4E8Y0yWiKS4b3Z9lXfZA5FpaWmeyykpKaSkpFzu\nrkHlmmuuAZxTpQCWLl3KjBkzLCZSKjy1bdvWc9mfDZKMjAwyMjKq/bgqB3NE5P8A04ESIAZoBKwE\nUoFWxpgyERkEPGOMGVXJ40NuMKcyIsKjjz7Kn/70J9tRlAo7IsKSJUu4667ADnX4bDDHGPOkMaa9\nMaYTMAVYZ4yZDqwHJrnudifwbm0Ch4IFCxYgItxyyy22oygV8nbu3FlhoMY9uh2MarNw7ywgXUT+\nAOwEXvVNpOD0j3/8g1dffZX33nuP1atX246jVMhzv49mz55NkyZNgroBojNzqulnP/sZb7zxBtOm\nTaNt27bMmzfPdiSlQsq+ffuYN28eO3fuZM+ePVanDesURj/ZtGkTN9xwg+f6tm3b6N+/v8VESoUW\nXy2666ssOoXRD3784x9XWPz3/PnzlhMpFXrGjRsXsEV3fUELZS0NGzYMEWHatGm2oygVtPLz8ysM\n3AwcONByourRrnctnDhxgm+++YZbb72VkydP6hJtSl1GdnY2PXv2ZOvWrURFRdG7d+9aL7rrC3qM\nMoDi4+M5efIksbGxjBo1irfeest2JKWCwsaNG/nlL39Jbm4uFy5cCLrGhBbKAFq/fj2TJk0iPz8f\n0MV/lXLz56K7vqCF0oJz587RqFEjTpw4AUCzZs2sr3qilA0XLlzg/PnzxMfHExkZSXFxse1IldJR\nbwsiI53n78fHxxMfH8/vfvc7y4mUCjxjDA0aNCA+Ph6AO+64w3Ki2tMWpZ+ICElJSezcudN2FKUC\nTkTIycmhY8eOnuvBSFuUQSArK0sX/1V1RmZmJvXr1/cUxYiIiKBYdNcXtFD6yaeffkpKSgqJiYm6\n+K+qE2bPnk1RUREDBgzgrrvuon379rYj+Yx2vf0sPT2dqVOnsnTpUmJiYpg8ebLtSEr51OHDh/n4\n44/505/+RHZ2dkid9eFt17s2qwcpL/Tu3RuAn//85wAUFxczffp0m5GU8ql27dp5Lt98880Wk/iP\ndr39rFu3bhXmhu/fv99yIqV8b+HChRhjWLVqle0ofqGFMsDmzp2ri/+qkOceqHQP1JT/KIdwpF3v\nAPr222958803eeutt3TxXxXS1q1bBzj/8Tdq1Ijx48PmQ1grpYM5Ftx2222sWLGCiRMn0qFDBxYs\nWGA7klJe2bNnD3PnzmXv3r38/e9/D6mBm8roFMYglpmZydChQz3Xs7Ky6NWrl8VESnknmBbd9QU9\n4TyIJScnVxjgKSwstJxIKe+NHDkypBbd9QUtlEFg0KBBuvivClqnT5+uMHBz/fXXW04UeNr1tiw/\nP5/Dhw+TnJzM2bNnQ/6Yjwo/OTk5dO7cmaysLCIjI+nRo0dQLLrrC9r1DhHNmjWjV69engIZERHB\nxIkTLadSynksPTExkS5dugDQq1cvrrnmmrApktWhLcogsX79eqZOnUpeXh6gi/8q+6KioigpKQGc\nM27C8WRyHfUOUSdOnKBFixYcOnQIh8NBQkJCWKy+okLH999/T0FBAYmJiZSWlob1P23teoeoBg0a\nANC+fXvatm3Lv/3bv1lOpOqaxo0b0759e0pLS/nZz35mO05Q0BZlEBMRhgwZwubNm21HUXWIiJCd\nnU2PHj0818OVtijDxJYtWxARRo4caTuKCmOZmZlERUV5iqL7cjgXyerQud5BbNu2bTz99NPk5OTU\nqZN7VeA9++yzlJSUkJKSQrdu3bj66qttRwoq2vUOAa+99hp33XUXixYtokGDBtx55522I6kwkZub\ny6pVq3j55ZfZs2dPWA/cVEYX7g0jAwYMAOC+++4DICYmhttvv91mJBUmyn9cQ7guuusLeowyBPTs\n2bPC3PCvv/7aciIVTp5//vmwXnTXF7RQhqCnnnoKEWHMmDG2o6gQlJ2dXWGgxv2RsurytOsdYg4e\nPMiKFStYunQpf/vb32zHUSFo48aNALzwwgs0bNiQSZMmWU4U/HQwJ0SNHj2aDz74gNGjR9O5c2cW\nLlxoO5IKcrt27eKZZ57hwIED7Nu3r84N3FRGpzCGuczMTFJSUjx/7Pv27aN79+6WU6lgVv6cyBEj\nRvDxxx9bTBMcdNQ7zCUnJ1NWVgY4X+yioiLLiVQoSE5OZsOGDbZjhBwdzAkTvXr1QkSYMWOG7Sgq\niJw7d67CwE1ycrLlRKFJu95hoKCggOPHj3PttddSVFSkx56Ux9GjR0lISGD//v1ERESQmJhYJ9eT\nvByd612HNG3alK5du3paDSLCuHHjLKdSNmVmZtKuXTsSEhIA6Nq1K507d9YiWUNV/tZEpK2IrBOR\nvSKyR0Qect0eJyJrRGS/iHwkIk38H1ddyQcffOD5IPp3333Xchpl06hRozh8+DAAt9xyi+U0oa/K\nrreItAJaGWOyRCQW2AGMBX4O5BtjnheRmUCcMWZWJY/XrneA5ebm0r59e+1u1UHuwzB9+vTh/Pnz\nehimCj7rehtjjhljslyXzwH7gLY4i+Uy192WAdrXCxJNmjgb9926daNLly784Q9/sJxIBUpcXBzd\nunXj/Pnz/PSnP7UdJ2xU6/QgEekIJAGfAi2NMXngLKYiEu/zdKpGGjdu7GlJiAiZmZmWE6lA2r59\nO3379rUdI6x43R9zdbuXAw+7Wpbapg8R69atQ0RITU21HUX5wcaNG4mIiPAM5tWvX99yovDjVYtS\nRCJxFsk3jDHuUYI8EWlpjMlzHcc8frnHp6WleS6npKSQkpJS48Cqer744gvmzJnD/v37Wbt2re04\nyg8WLFhAWVkZo0ePplOnTvTs2dN2pKCVkZFBRkZGtR/n1XmUIvI6cNIY89tyt80HThlj5utgTvB7\n8cUXefDBB3nhhReIjY3lV7/6le1IqpZyc3NZvnw5y5YtY9euXTpwUwM+m+stItcDmcAenN1tAzwJ\nbAPeAtoBh4BJxpiCSh6vhTII7Nq1i6SkJM/1FStWMGHCBIuJVG2Vn7s9evRoVq9ebTFNaPLZXG9j\nzGYg4jI/vrG6wZQdvXr1qjDAc/DgQcuJlC/MmTNHP9I4APTkujrqt7/9rS7+G4K+/PLLCnO3u3Tp\nYjlR3aCrB9VBBw8eZPXq1bz00ku6+G+I2bZtG4Dng+b0XMnA0EUx6rDhw4ezfv16UlJS6NGjB4sW\nLbIdSV3G9u3bmT17Nv/4xz84cOCADtz4iC7cq6q0YcMGRowYQWlpKQA5OTkkJiZaTqUqU37g5sYb\nb9RTvXxEF+5VVRo6dCglJSWA8w+mpKSkwoCPCi79+/f3dL1VYOlgjvLo2rUrDoeDu+66y3YUBVy4\ncKHCwM35Wnu2AAALJUlEQVTw4cMtJ6q7tOutAPj+++8pKCigffv2AHoMLAgUFBQQFxfHoUOHcDgc\nJCQkaEvfx3ThXlUtjRo1ol27dp7rIsKtt95qMVHdlZmZSatWrYiLiwOgXbt2tGnTRoukRVooVQXr\n16+nY8eOOBwOVq1aZTtOnTRu3Djy8vJwOBy6Un2Q0K63qtT+/fvp3r07WVlZREZG0qNHD13818/y\n8/M5fPgww4cP59SpU3r4IwC0661qpXnz5gAkJSXRs2dP5s2bZzlR+GvevDlJSUmcOnWKqVOn2o6j\nytHTg1SlmjVrVuFUoS1btlhOVDds2rSJ66+/3nYMdQltUSqvrF69GhFh1KhRtqOElU2bNlU4BSgm\nJsZyIlUZbVGqKu3atYtnn32W7OxsPvzwQ9txwspLL70EwMSJE2nXrh19+vSxnEhVRgdzlNeef/55\nZs6cydy5c2ncuDEPPvig7Ugh69ChQ7zxxhssX76crKwsHbixRKcwKp+78Ubn8qOzZ88GoGPHjnqu\nZQ116NDBc/mmm26ymER5Q49RKq/16dMHY4yn9fPdd99ZThTaZs2ahTGGDz74wHYUVQUtlKrG7r33\nXkRET4r20ldffVVh4KZbt26WEylvaddb1cihQ4f45JNPmD9/Pu+++27VD1Ds2rULgKVLlxIdHc2U\nKVMsJ1Le0sEcVSuDBg3is88+Y8CAAVx33XUsXrzYdqSgs23bNmbNmsXBgwfJycnRgZsgogv3qoDI\nyMggNTWV4uJiwHncMiEhwXKq4FJ+MYvhw4fzySefWEyjytNCqQJORDh06BBt27b1XFfO30PPnj3Z\ns2eP7SjqEjrXWwWU+59h+/btcTgc3H333ZYT2VVUVFRh4CY1NdVyIlUb2qJUPnPhwgXOnz9PfHw8\n0dHRXLhwwXYkay5evEh0dDQnTpwAnHPntYUdfLRFqQIuJibGs+pQYWEhIsLo0aMtpwqsDRs20Lx5\nc6KjowHnikDNmzfXIhnitFAqn8vIyODqq68mOjq6zp1MPWXKFPLz84mNjeW2226zHUf5iHa9ld/s\n2rWLpKQktm7dSlRUFL179w7bxX9PnDjBN998w/jx4zl27JieAhQidK63sq5169YADB48GHAuqvH4\n44/bjOQ3LVq08FyeNGmSxSTKH7RQKr9p0aJFhcV/w/0zqdesWcNPfvIT2zGUH4RnP0gFpeXLlyMi\nYbNaztatWyucAhQbG2s5kfIXbVGqgMjOzmbevHns3LmTjz76yHYcn3BP15w2bRpt2rTxHGJQ4UcH\nc1RApaWlMWfOHGbPnk3Tpk159NFHbUeqtoMHD7JkyRJWrVqli+6GOJ3CqILSjh076Nevn+f6+++/\nH3Kfw1P+nMhRo0bx/vvvW0yjakNPOFdBqW/fvhUW/z1+/LjlRDXz8MMPY4zRIllHaKFUVs2YMQMR\nYfz48bajXFFOTk6FgZuePXtaTqQCSQdzlDW5ubls3ryZp59+mpUrV9qOc0X79u0DID09nejoaMaM\nGWM5kQokPUaprEtKSmLXrl307NmTfv36sXTpUtuRPLZu3cpjjz1Gbm4uubm5OnATZnQwR4WM9evX\nM3r0aAoLCwHIz8/nqquuspzKqfzAzY033sjatWstplG+poVShSQR4eTJk55CaXvVHRGhc+fOfP31\n11ZzKP/QUW8Vctz/UJs3b47D4eD++++3kqO0tLTCwM3NN99sJYcKHrVqUYrITcCfcRbcV40x8yu5\nj7YoldeKioooLi4mNjaWuLg4Tp06ZSWHiHD27FlEhIYNG1pv2Sr/8HuLUkQcwIvASOAaYKqIdK/p\n9pQCqFevHg0bNgTg9OnTAV38NyMjg7i4OE9RbNiwIbGxsVokVa263gOAr4wxB40xxUA6MNY3sVRd\nt2HDBn70ox/RpEmTgC3+O2PGDAoKCoiPj2fy5Mlhu3amqr7anEfZBsgtd/0wzuJZqYyMDFJSUmqx\nO/tC/TmEUv7k5GSys7P59NNPGTx4MOvXr8cYQ1ZWFr179/6X+zscDoqKioiMjHR3p3A4HFy8eJGo\nqCjPbeWXfXNz/6ysrAzw72yhUHoNLifUn0NN8temUFbWH6n0YGRaWponnPsrFNXFPxDb2rVrBzg/\nDzsQJk6c6Nfth+JrcKlQfg4ZGRmkpaVVO39t+haHgfblrrcFjlR2R3ewmgRUdVubNm08LUFjDM88\n80yF677+Wr58ue2nrPzI3VBLS0sjLS3N68fVplB+DnQRkQ4iUg+YArxXi+0ppVRQ8sXpQf/BP08P\nmlfJffTcIKVU0AqKmTlKKRXq9PwHpZSqghZKpZSqQkAKpYg8KCJfisgeEZlX7vbfichXIrJPRFID\nkaWmROQxESkTkavK3bbQlT9LRJJs5rsSEXne9TvOEpEVItK43M9C4jUQkZtcf0MHRGSm7TzeEJG2\nIrJORPa6/vYfct0eJyJrRGS/iHwkIk1sZ70SEXGIyBci8p7rekcR+dSV//+JSFCvaysiTUTkbdff\neLaIDKz2a+DPUy1cxz9TgDVApOt6c9f3HsBOnOdydgS+xnXMNNi+cJ769CHwD+Aq122jgNWuywOB\nT23nvEL+GwGH6/I84DnX5R+FwmuA8x/610AHIArIArrbzuVF7lZAkutyLLAf6A7MB55w3T4TmGc7\naxXP4xHgTeA91/W/AJNcl18G7rGdsYr8/xf4uetyJNCkuq9BIFqU97pClAAYY066bh8LpBtjSowx\n3wJfcYWZPZb9O/D4JbeNBV4HMMZ8BjQRkZaBDuYNY8zHxpgy19VPcRZ+gDGExmsQktNljTHHjDFZ\nrsvngH04f/djgWWuuy0DxtlJWDURaQuMBpaUu3k4sMJ1eRkQtJ/jISKNgBuMMUsBXH/rZ6jmaxCI\nQtkVSHY11deLSF/X7ZdOgfzOdVtQEZFbgVxjzJ5LfhQS+SvxC8D9iVih8hwqmy4bjDkvS0Q6Akk4\n/1G1NMbkgbOYAvH2klXJ3UgwACLSDDhd7h/vYSDBUjZvdAJOishS1+GDV0SkAdV8DXxybEFE1gLl\nW1OC8xc727WPpsaYQSLSH3jbFd7rKZD+VkX+J4GfVPawSm6zdq7VFZ7DU8aYv7nu8xRQbIz5f+Xu\nc6lgPF8sVHJWSkRigeXAw8aYc6FybrGI3AzkGWOyRCTFfTP/+noE8/OJBPoA9xtjtovIvwOzqGZm\nnxRKY0xlhQQAEfk18FfX/T4XkVLXfyWvp0D62+Xyi0hPnMfudolzFYW2wBciMgBn/nbl7m4tP1z5\nNQAQkTtxdqHKT5oOqudwBUHzt1JdroGO5cAbxph3XTfniUhLY0yeiLQCgvUze68HxojIaCAGaIRz\n/dkmIuJwtSqD/bU4jLNHuN11fQXOQlmt1yAQXe+VwAgAEekK1DPG5OOc7jhZROqJSCLQBdgWgDxe\nM8b83RjTyhjTyRiTiPOX3tsYcxxn/p8BiMggoMDdlA82rhlUTwBjjDEXy/3oPWBKML8GLqE8XfY1\nYK8x5j/K3fYeMMN1+U7g3UsfFAyMMU8aY9obYzrh/J2vM8ZMB9YDk1x3C9r8AK73ZK6r9oCzFmVT\n3dcgACNOUcAbwB5gOzC03M9+h3M0cx+Qant0zIvnkoNr1Nt1/UVX/l1AH9v5rpD7K+Ag8IXra1Go\nvQbATThHjb8CZtnO42Xm64FSnKP0O12/+5uAq4CPXc9nLc5DU9bzVvFchvLPUe9E4DPgAM4R8Cjb\n+arI3gvnP9ssnL3bJtV9DXQKo1JKVUFn5iilVBW0UCqlVBW0UCqlVBW0UCqlVBW0UCqlVBW0UCql\nVBW0UCqlVBW0UCqlVBX+P0VFnoIKajtRAAAAAElFTkSuQmCC\n",
601 "text/plain": [
602 "<matplotlib.figure.Figure at 0x7ffba49b3710>"
603 ]
604 },
605 "metadata": {},
606 "output_type": "display_data"
607 }
608 ],
609 "source": [
610 "heart_points = [Step(60, 50, Direction.UP), Step(50, 90, Direction.UP),\n",
611 " Step(20, 70, Direction.UP), \n",
612 " Step(-40, 90, Direction.UP), Step(-60, 80, Direction.UP), \n",
613 " Step(0, 0, Direction.RIGHT)]\n",
614 "\n",
615 "heart_tour = ''\n",
616 "current = Step(0, 0, Direction.RIGHT)\n",
617 "\n",
618 "for hp in heart_points:\n",
619 " while not (current.x == hp.x and current.y == hp.y):\n",
620 " s, proposed = seek(hp, current)\n",
621 " heart_tour += s\n",
622 " current = proposed\n",
623 "\n",
624 "plot_trace(trace_tour(heart_tour))\n",
625 "\n",
626 "def heart_tour_func(): return heart_tour"
627 ]
628 },
629 {
630 "cell_type": "code",
631 "execution_count": 32,
632 "metadata": {
633 "collapsed": true
634 },
635 "outputs": [],
636 "source": [
637 "def trim_some_mistakes(tour, mistake_limit):\n",
638 " trimmed_tour = rw\n",
639 " mistake_count = len(mistake_positions(trace_tour(trimmed_tour)))\n",
640 " while len(mistake_positions(trace_tour(trimmed_tour))) > mistake_limit:\n",
641 " trimmed_tour = trim_loop(trimmed_tour, random_mistake=True)\n",
642 " return trimmed_tour"
643 ]
644 },
645 {
646 "cell_type": "code",
647 "execution_count": 33,
648 "metadata": {},
649 "outputs": [
650 {
651 "name": "stdout",
652 "output_type": "stream",
653 "text": [
654 "cross.txt\t small-squares.txt\t tours.txt\r\n",
655 "large-squares.txt tours-open.txt\t tours-with-mistakes.txt\r\n",
656 "quincunx.txt\t tours-random-walk.txt\r\n"
657 ]
658 }
659 ],
660 "source": [
661 "!ls *txt"
662 ]
663 },
664 {
665 "cell_type": "code",
666 "execution_count": 46,
667 "metadata": {},
668 "outputs": [
669 {
670 "data": {
671 "text/plain": [
672 "113"
673 ]
674 },
675 "execution_count": 46,
676 "metadata": {},
677 "output_type": "execute_result"
678 }
679 ],
680 "source": [
681 "valid_tours = [t.strip() for t in open('tours.txt').readlines() if valid(trace_tour(t.strip()))]\n",
682 "valid_tours += [t.strip() for t in open('tours-with-mistakes.txt').readlines() if valid(trace_tour(t.strip()))]\n",
683 "valid_tours += [t.strip() for t in open('tours-open.txt').readlines() if valid(trace_tour(t.strip()))]\n",
684 "valid_tours += [t.strip() for t in open('tours-random-walk.txt').readlines() if valid(trace_tour(t.strip()))]\n",
685 "\n",
686 "len(valid_tours)"
687 ]
688 },
689 {
690 "cell_type": "code",
691 "execution_count": 35,
692 "metadata": {},
693 "outputs": [
694 {
695 "data": {
696 "text/plain": [
697 "True"
698 ]
699 },
700 "execution_count": 35,
701 "metadata": {},
702 "output_type": "execute_result"
703 }
704 ],
705 "source": [
706 "all(valid(trace_tour(t)) for t in valid_tours)"
707 ]
708 },
709 {
710 "cell_type": "code",
711 "execution_count": 47,
712 "metadata": {},
713 "outputs": [
714 {
715 "data": {
716 "text/plain": [
717 "(87, 0)"
718 ]
719 },
720 "execution_count": 47,
721 "metadata": {},
722 "output_type": "execute_result"
723 }
724 ],
725 "source": [
726 "tours_with_mistakes = [t.strip() for t in open('tours-with-mistakes.txt').readlines() \n",
727 " if not valid(trace_tour(t.strip()))]\n",
728 "len(tours_with_mistakes)"
729 ]
730 },
731 {
732 "cell_type": "code",
733 "execution_count": 48,
734 "metadata": {},
735 "outputs": [
736 {
737 "data": {
738 "text/plain": [
739 "100"
740 ]
741 },
742 "execution_count": 48,
743 "metadata": {},
744 "output_type": "execute_result"
745 }
746 ],
747 "source": [
748 "tours_open = [t.strip() for t in open('tours-open.txt').readlines() \n",
749 " if not valid(trace_tour(t.strip()))]\n",
750 "len(tours_open)"
751 ]
752 },
753 {
754 "cell_type": "code",
755 "execution_count": 50,
756 "metadata": {},
757 "outputs": [
758 {
759 "data": {
760 "text/plain": [
761 "(84, 116)"
762 ]
763 },
764 "execution_count": 50,
765 "metadata": {},
766 "output_type": "execute_result"
767 }
768 ],
769 "source": [
770 "tours_walks_loops = [t.strip() for t in open('tours-random-walk.txt').readlines() \n",
771 " if len(mistake_positions(trace_tour(t.strip()))) > 1]\n",
772 "tours_walks_unloops = [t.strip() for t in open('tours-random-walk.txt').readlines() \n",
773 " if len(mistake_positions(trace_tour(t.strip()))) == 1]\n",
774 "len(tours_walks_loops), len(tours_walks_unloops)"
775 ]
776 },
777 {
778 "cell_type": "code",
779 "execution_count": 51,
780 "metadata": {},
781 "outputs": [
782 {
783 "data": {
784 "image/png": "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\n",
785 "text/plain": [
786 "<matplotlib.figure.Figure at 0x7ffba4647c18>"
787 ]
788 },
789 "metadata": {},
790 "output_type": "display_data"
791 }
792 ],
793 "source": [
794 "plot_trace(trace_tour(tours_with_mistakes[31]))"
795 ]
796 },
797 {
798 "cell_type": "code",
799 "execution_count": 54,
800 "metadata": {},
801 "outputs": [
802 {
803 "data": {
804 "text/plain": [
805 "65"
806 ]
807 },
808 "execution_count": 54,
809 "metadata": {},
810 "output_type": "execute_result"
811 }
812 ],
813 "source": [
814 "sum(1 for t in valid_tours if len(t) > 100)"
815 ]
816 },
817 {
818 "cell_type": "code",
819 "execution_count": 92,
820 "metadata": {},
821 "outputs": [
822 {
823 "data": {
824 "text/plain": [
825 "48"
826 ]
827 },
828 "execution_count": 92,
829 "metadata": {},
830 "output_type": "execute_result"
831 }
832 ],
833 "source": [
834 "problem_set = [t for t in valid_tours if len(t) <= 100]\n",
835 "len(problem_set)"
836 ]
837 },
838 {
839 "cell_type": "code",
840 "execution_count": 93,
841 "metadata": {},
842 "outputs": [
843 {
844 "data": {
845 "text/plain": [
846 "(48, 65)"
847 ]
848 },
849 "execution_count": 93,
850 "metadata": {},
851 "output_type": "execute_result"
852 }
853 ],
854 "source": [
855 "# problem_set += [t for t in valid_tours if len(t) > 100][0::2]\n",
856 "valids_to_split = [t for t in valid_tours if len(t) > 100]\n",
857 "len(problem_set), len(valids_to_split)"
858 ]
859 },
860 {
861 "cell_type": "code",
862 "execution_count": 94,
863 "metadata": {},
864 "outputs": [
865 {
866 "data": {
867 "text/plain": [
868 "148"
869 ]
870 },
871 "execution_count": 94,
872 "metadata": {},
873 "output_type": "execute_result"
874 }
875 ],
876 "source": [
877 "problem_set += random.sample(tours_with_mistakes + tours_open + tours_walks_loops + tours_walks_unloops, 100)\n",
878 "len(problem_set)"
879 ]
880 },
881 {
882 "cell_type": "code",
883 "execution_count": 95,
884 "metadata": {},
885 "outputs": [
886 {
887 "data": {
888 "text/plain": [
889 "2284"
890 ]
891 },
892 "execution_count": 95,
893 "metadata": {},
894 "output_type": "execute_result"
895 }
896 ],
897 "source": [
898 "max(len(t) for t in valids_to_split)"
899 ]
900 },
901 {
902 "cell_type": "code",
903 "execution_count": 96,
904 "metadata": {},
905 "outputs": [
906 {
907 "data": {
908 "text/plain": [
909 "1680"
910 ]
911 },
912 "execution_count": 96,
913 "metadata": {},
914 "output_type": "execute_result"
915 }
916 ],
917 "source": [
918 "sum(len(t) for t in problem_set if valid(trace_tour(t)))"
919 ]
920 },
921 {
922 "cell_type": "code",
923 "execution_count": 85,
924 "metadata": {},
925 "outputs": [
926 {
927 "data": {
928 "text/plain": [
929 "[]"
930 ]
931 },
932 "execution_count": 85,
933 "metadata": {},
934 "output_type": "execute_result"
935 }
936 ],
937 "source": [
938 "[(i, j) \n",
939 " for i in range(len(problem_set)) \n",
940 " for j in range(len(problem_set))\n",
941 " if i != j\n",
942 " if valid(trace_tour(problem_set[i] + problem_set[j]))]"
943 ]
944 },
945 {
946 "cell_type": "code",
947 "execution_count": 87,
948 "metadata": {
949 "scrolled": true
950 },
951 "outputs": [
952 {
953 "name": "stdout",
954 "output_type": "stream",
955 "text": [
956 "attempting 0\n",
957 "** found split for 0\n",
958 "attempting 1\n",
959 "attempting 2\n",
960 "attempting 3\n",
961 "attempting 4\n",
962 "attempting 5\n",
963 "attempting 6\n",
964 "attempting 7\n",
965 "attempting 8\n",
966 "attempting 9\n",
967 "attempting 10\n",
968 "attempting 11\n",
969 "** found split for 11\n",
970 "attempting 12\n",
971 "attempting 13\n",
972 "attempting 14\n",
973 "attempting 15\n",
974 "attempting 16\n",
975 "attempting 17\n",
976 "** found split for 17\n",
977 "attempting 18\n",
978 "attempting 19\n",
979 "attempting 20\n",
980 "attempting 21\n",
981 "attempting 22\n",
982 "attempting 23\n",
983 "attempting 24\n",
984 "attempting 25\n",
985 "attempting 26\n",
986 "attempting 27\n",
987 "attempting 28\n",
988 "attempting 29\n",
989 "** found split for 29\n",
990 "attempting 30\n",
991 "attempting 31\n",
992 "attempting 32\n",
993 "attempting 33\n",
994 "attempting 34\n",
995 "** found split for 34\n",
996 "attempting 35\n",
997 "attempting 36\n",
998 "attempting 37\n",
999 "attempting 38\n",
1000 "** found split for 38\n",
1001 "attempting 39\n",
1002 "attempting 40\n",
1003 "attempting 41\n",
1004 "** found split for 41\n",
1005 "attempting 42\n",
1006 "attempting 43\n",
1007 "attempting 44\n",
1008 "attempting 45\n",
1009 "attempting 46\n",
1010 "attempting 47\n",
1011 "attempting 48\n",
1012 "** found split for 48\n",
1013 "attempting 49\n",
1014 "** found split for 49\n",
1015 "attempting 50\n",
1016 "** found split for 50\n",
1017 "attempting 51\n",
1018 "attempting 52\n",
1019 "attempting 53\n",
1020 "attempting 54\n",
1021 "attempting 55\n",
1022 "attempting 56\n",
1023 "attempting 57\n",
1024 "** found split for 57\n",
1025 "attempting 58\n",
1026 "attempting 59\n",
1027 "** found split for 59\n",
1028 "attempting 60\n",
1029 "attempting 61\n",
1030 "attempting 62\n",
1031 "** found split for 62\n",
1032 "attempting 63\n",
1033 "attempting 64\n"
1034 ]
1035 }
1036 ],
1037 "source": [
1038 "split_valids = []\n",
1039 "unsplit_valids = []\n",
1040 "i = 0\n",
1041 "for v in valids_to_split:\n",
1042 " can_add = False\n",
1043 " attempts_remaining = 500\n",
1044 " print('attempting', i)\n",
1045 " while not can_add and attempts_remaining > 0:\n",
1046 " # print('splitting', i, 'attempt', attempts_remaining)\n",
1047 " attempts_remaining -= 1\n",
1048 "# split_pos = len(v) // 2 + random.randrange(10)\n",
1049 " split_pos = random.randint(20, len(v) - 40)\n",
1050 " vl = v[:split_pos]\n",
1051 " vr = v[split_pos:]\n",
1052 " can_add = True\n",
1053 " if valid(trace_tour(vr + vl)): can_add = False\n",
1054 " for other in problem_set:\n",
1055 " if can_add and valid(trace_tour(other + vl)): can_add = False\n",
1056 " if can_add and valid(trace_tour(other + vr)): can_add = False\n",
1057 " if can_add and valid(trace_tour(vl + other)): can_add = False\n",
1058 " if can_add and valid(trace_tour(vr + other)): can_add = False\n",
1059 " for other in split_valids:\n",
1060 " if can_add and valid(trace_tour(other + vl)): can_add = False\n",
1061 " if can_add and valid(trace_tour(other + vr)): can_add = False\n",
1062 " if can_add and valid(trace_tour(vl + other)): can_add = False\n",
1063 " if can_add and valid(trace_tour(vr + other)): can_add = False\n",
1064 " if can_add:\n",
1065 " split_valids += [vl, vr]\n",
1066 " print('** found split for', i)\n",
1067 " else:\n",
1068 " unsplit_valids += [v]\n",
1069 " i += 1"
1070 ]
1071 },
1072 {
1073 "cell_type": "code",
1074 "execution_count": 97,
1075 "metadata": {},
1076 "outputs": [
1077 {
1078 "data": {
1079 "text/plain": [
1080 "['RLFLRFRLLFFRRLFFFRFLLFFFLFLRFRFFFRFLLFRFRFFFFRFFLFLFLRRFRFFFFLFFFFFFRLFLFLFRRFFFLFRFFRRFLLFFFRFRFFLRLFFLFRFFFLFFFFLRFFFFFLFFRLFFFFFFFFRFFFFFFRFFFFFFRLFFFLFRFRFLFFFFLFFFFFFLRFFFFLRLFFRFFRFLFFFFFFFLFLRFRLFFFFFFRLRFFLFFRFRLFFFRLFRLFFFLFFRLFLFFLFRRFFFLRFFLFFLRFFRFLRFFFLFFRFFLRFFFFFRFLFRLFRRFLFFFFRRFLRLFLFFFFFFLFFFFFFRFLRLFRLFLFFRFFLFFFFFFRRFFFLLFFRFFLRFFRRLLFRFFFFFFLFFFLFFFLRFFLFRRFLRLRFFFRFLFFFFFRLRFLFLFFRRFLFFFRLLFRLLRRLFLFRFFRFLFFFFRFFFLFFLFRFRFLRFFFFFLRFLFLFFFRFFFLFRRFLFLFFLFFRFFFFFFRRFLFFRFFFLRFLFFFFFFFFLRFFRRLFFFFFLRLFFFFFRLFFFFFFFFFFFLRFFLFRFFFFLRLLFRFRLRFFFLFLFFFRFFFFFRFFRFFLFRLLFRFLRFFFFLFFLFRFFFRLFFRRFLRLFLFFFLRFLRFFFFFFLFFFRFRFFFFFF',\n",
1081 " 'LLRRLFFFFFFFLFFFRFFFFFFFLLRFFRFFFRFFFLLFFRLRFFFLFRFFRFLFRFFFRFLLFFLFFFFFFRRFLRFRLFFFLFFFFFFFFLFFRLFFFFRFFFRFFFLFFFRLR',\n",
1082 " 'RLFFFLFFFRFFFRFFLFFLFFRFFFFLFFRFRFFFRFLLRLFFFFLFFRFRFFRLRFFLFLFFRFFLFLRFRFFFLFFFLFRFLFFFFRRLFRFLFFFFFFLFRFFLFRFFFFFFFFLLFRFFFLFRFFRFFFFFFFRRLFLLRFFRLFRLFFFLFFRFFRFRFLFFLFFRFFFRLLFFFLFFFLRFFFFFFRLFRFFLFFFFRLFFRRLLFFFFLRLFFFFRFRFFLFFFFFFFFLFFRRFFFFLFFFFLFLFFRFFFRFFFFFRLRFFFFFRFLFFFLFFFFLFFFFFRFFFFFFLFFFRFLLFFFRFRFFFFLRFFFRLFFRLFFRFLRFFFFFFFFFFLRFLFFFFFFRLFFFFLRLFRLFRLFFFRFLRFFLRFLFFFFFFFFFFFFFFLFFRLFFFRLFFFFFFFRFLRFRLFFFRLFRFFFFFFFFFFFFFLFFFFFFFFFFFLLRFFLFFRLFRFLRFFFLRFFFFFFRFFRLFRLFFFLRFFFFRFFRFFFFFFFFFFLFFFFFFLFLRFFFFRFLLFRFLRFFRFFFLFRFLFRLFFFFFFFFLFLFRFFFFLFFRFFFFRLRRFFLLFFRFLFRFFFFFFLRFFFFFRFFFRFRFLFFLFLRLRLFFLRFFLFFRFFFFLFFFFFLFFFFFRLFFFFRFFFFFRFFFFFFFFFFRFLFFFFFLRLLFFFFRFFFRFLRFFLFFFFLFRRFLFFFFLRFFRLFFLFFFFLRFFLFRRFFFFRFLFFFRFL',\n",
1083 " 'FLFFRRFFFFRLLFFFLFLLRRFFFRFFFLRFFFLFLFFRRFFFFLLFRFFLFRFFRFFFRFLFFFFRLFFFLRFFFFRFRLFFRLLFFFFFF']"
1084 ]
1085 },
1086 "execution_count": 97,
1087 "metadata": {},
1088 "output_type": "execute_result"
1089 }
1090 ],
1091 "source": [
1092 "split_valids[:4]"
1093 ]
1094 },
1095 {
1096 "cell_type": "code",
1097 "execution_count": 98,
1098 "metadata": {},
1099 "outputs": [
1100 {
1101 "data": {
1102 "text/plain": [
1103 "[(0, 1),\n",
1104 " (2, 3),\n",
1105 " (4, 5),\n",
1106 " (6, 7),\n",
1107 " (8, 9),\n",
1108 " (10, 11),\n",
1109 " (12, 13),\n",
1110 " (14, 15),\n",
1111 " (16, 17),\n",
1112 " (18, 19),\n",
1113 " (20, 21),\n",
1114 " (22, 23),\n",
1115 " (24, 25)]"
1116 ]
1117 },
1118 "execution_count": 98,
1119 "metadata": {},
1120 "output_type": "execute_result"
1121 }
1122 ],
1123 "source": [
1124 "[(i, j) \n",
1125 " for i in range(len(split_valids)) \n",
1126 " for j in range(len(split_valids))\n",
1127 " if i != j\n",
1128 " if valid(trace_tour(split_valids[i] + split_valids[j]))]"
1129 ]
1130 },
1131 {
1132 "cell_type": "code",
1133 "execution_count": 99,
1134 "metadata": {},
1135 "outputs": [
1136 {
1137 "data": {
1138 "text/plain": [
1139 "226"
1140 ]
1141 },
1142 "execution_count": 99,
1143 "metadata": {},
1144 "output_type": "execute_result"
1145 }
1146 ],
1147 "source": [
1148 "problem_set += (split_valids + unsplit_valids)\n",
1149 "len(problem_set)"
1150 ]
1151 },
1152 {
1153 "cell_type": "code",
1154 "execution_count": 100,
1155 "metadata": {
1156 "collapsed": true
1157 },
1158 "outputs": [],
1159 "source": [
1160 "with open('06-tours.txt', 'w') as f:\n",
1161 " f.writelines(t + '\\n' for t in random.sample(problem_set, len(problem_set)))"
1162 ]
1163 },
1164 {
1165 "cell_type": "code",
1166 "execution_count": null,
1167 "metadata": {
1168 "collapsed": true
1169 },
1170 "outputs": [],
1171 "source": []
1172 }
1173 ],
1174 "metadata": {
1175 "kernelspec": {
1176 "display_name": "Python 3",
1177 "language": "python",
1178 "name": "python3"
1179 },
1180 "language_info": {
1181 "codemirror_mode": {
1182 "name": "ipython",
1183 "version": 3
1184 },
1185 "file_extension": ".py",
1186 "mimetype": "text/x-python",
1187 "name": "python",
1188 "nbconvert_exporter": "python",
1189 "pygments_lexer": "ipython3",
1190 "version": "3.5.2+"
1191 }
1192 },
1193 "nbformat": 4,
1194 "nbformat_minor": 2
1195 }