--- /dev/null
+{
+ "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
+}