Task 3 done
[summerofcode2018soln.git] / src / task3 / task3.ipynb
diff --git a/src/task3/task3.ipynb b/src/task3/task3.ipynb
new file mode 100644 (file)
index 0000000..4f640f8
--- /dev/null
@@ -0,0 +1,274 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "instructions = [l.strip() for l in open('../../data/03-graffiti.txt') if not l.startswith('#')]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Part 1\n",
+    "Similar to task 1, but rather than just tracking the state of the mower, now we track the state of the grass as well.\n",
+    "\n",
+    "The grass is a `dict` of mown patches. The key in the `grass` is a pair (2-tuple) of `x` and `y` position. The value is `True` if the patch is mown. Unmown patches aren't recorded in the `grass`.\n",
+    "\n",
+    "`pen` records whether the Mowmaster is mowing or not."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def initial_world():\n",
+    "    return {'x': 0, 'y': 0, 'd': 0, 'pen': False, 'grass': {}}"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "One function for each command. The function is passed the world, and it updates the world."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def f(world, distance):\n",
+    "    for d in range(distance):\n",
+    "        if world['d'] == 0:\n",
+    "            world['y'] += 1\n",
+    "        elif world['d'] == 90:\n",
+    "            world['x'] += 1\n",
+    "        elif world['d'] == 180:\n",
+    "            world['y'] -= 1\n",
+    "        elif world['d'] == 270:\n",
+    "            world['x'] -= 1\n",
+    "        else:\n",
+    "            raise ValueError\n",
+    "        if world['pen']:\n",
+    "            world['grass'][world['x'], world['y']] = True\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def c(world):\n",
+    "    world['d'] = (world['d'] + 90) % 360\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def a(world):\n",
+    "    world['d'] = (world['d'] - 90) % 360\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def u(world):\n",
+    "    world['pen'] = False\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def d(world):\n",
+    "    world['pen'] = True\n",
+    "    world['grass'][world['x'], world['y']] = True\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A dispatch table of commands. The keys are the command names, the values is the function to call and whether that function takes an argument or not."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "table = {\n",
+    "    'F': {'func': f, 'arg': True},\n",
+    "    'C': {'func': c, 'arg': False},\n",
+    "    'A': {'func': a, 'arg': False},\n",
+    "    'U': {'func': u, 'arg': False},\n",
+    "    'D': {'func': d, 'arg': False},\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def execute(world, instructions, debug=False):\n",
+    "    for instruction in instructions:\n",
+    "        world = execute_one(world, instruction, debug=debug)\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To execute a command, look it up in the dispatch table. If it's there, call the function."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def execute_one(world, instruction, debug=False):\n",
+    "    instruction_name = instruction[0]\n",
+    "    if instruction_name in table:\n",
+    "        if table[instruction_name]['arg']:\n",
+    "            arg = int(instruction[1:])\n",
+    "            world = table[instruction_name]['func'](world, arg)\n",
+    "        else:\n",
+    "            world = table[instruction_name]['func'](world)\n",
+    "    return world"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "246"
+      ]
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "w = initial_world()\n",
+    "execute(w, instructions)\n",
+    "len(w['grass'])"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Part 2\n",
+    "\n",
+    "The `show_world` returns a string with a square for each mown patch. The string contains the embedded newlines, so I call `print` on the result."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def show_world(world):\n",
+    "    width_max = max(p[0] for p in world['grass'])\n",
+    "    width_min = min(p[0] for p in world['grass'])\n",
+    "    height_max = max(p[1] for p in world['grass'])\n",
+    "    height_min = min(p[1] for p in world['grass'])\n",
+    "    display = {}\n",
+    "    for r in range(height_max, height_min-1, -1):\n",
+    "        display[r] = ''\n",
+    "        for c in range(width_min, width_max+1):\n",
+    "            if (c, r) in world['grass']:\n",
+    "                display[r] += '⌷'\n",
+    "            else:\n",
+    "                display[r] += ' '\n",
+    "    return '\\n'.join(display[r] for r in reversed(sorted(display)))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "⌷⌷⌷⌷⌷⌷    \n",
+      "⌷         \n",
+      "⌷         \n",
+      "⌷⌷⌷⌷⌷⌷    \n",
+      "⌷         \n",
+      "⌷         \n",
+      "⌷         \n",
+      "⌷         \n",
+      "⌷⌷⌷⌷⌷⌷   ⌷\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(show_world(w))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "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.6.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}