Added animation images of solution
authorNeil Smith <neil.git@njae.me.uk>
Tue, 13 Jun 2017 15:36:00 +0000 (16:36 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Tue, 13 Jun 2017 15:36:00 +0000 (16:36 +0100)
05-display-board/display-board-animation.ipynb [new file with mode: 0644]
05-display-board/frames.gif [new file with mode: 0644]
05-display-board/frames.png [new file with mode: 0644]

diff --git a/05-display-board/display-board-animation.ipynb b/05-display-board/display-board-animation.ipynb
new file mode 100644 (file)
index 0000000..b004b96
--- /dev/null
@@ -0,0 +1,408 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "import re\n",
+    "from IPython.display import clear_output\n",
+    "from PIL import Image, ImageDraw, ImageColor, ImageFont"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "WIDTH = 80\n",
+    "HEIGHT = 8"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def new_grid(w=WIDTH, h=HEIGHT):\n",
+    "    return ['.' * w for r in range(1, h+1)]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def print_grid(grid, md=False, suppress_dots=False):\n",
+    "    if md:\n",
+    "        print('```')\n",
+    "    for row in grid:\n",
+    "        if suppress_dots:\n",
+    "            print(re.sub(r'\\.', ' ', row))\n",
+    "        else:\n",
+    "            print(row)\n",
+    "    if md:\n",
+    "        print('```')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def top(grid, l, r):\n",
+    "    new_segment = ''\n",
+    "    for i in range(l-1, r):\n",
+    "        if grid[0][i] == '.':\n",
+    "            new_segment += '*'\n",
+    "        else:\n",
+    "            new_segment += '.'\n",
+    "    grid[0] = grid[0][:l-1] + new_segment + grid[0][r:]\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def left(grid, t, b):\n",
+    "    for i in range(t-1, b):\n",
+    "        if grid[i][0] == '.':\n",
+    "            grid[i] = '*' + grid[i][1:]\n",
+    "        else:\n",
+    "            grid[i] = '.' + grid[i][1:]\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def rotate_column(grid, c, raw_n):\n",
+    "    n = raw_n % len(grid)\n",
+    "    col = [row[c-1] for row in grid]\n",
+    "    new_col = col[-n:] + col[:-n]\n",
+    "    for i in range(len(grid)):\n",
+    "        grid[i] = grid[i][:c-1] + new_col[i] + grid[i][c:]\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def rotate_row(grid, r, raw_n):\n",
+    "    n = raw_n % len(grid[0])\n",
+    "    grid[r-1] = grid[r-1][-n:] + grid[r-1][:-n]\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "command_dispatch = {'left': left, 'top': top,\n",
+    "                   'rotate row': rotate_row,\n",
+    "                   'rotate column': rotate_column}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def parse(command):\n",
+    "    cmd, a, b = command.rsplit(maxsplit=2)\n",
+    "    return cmd, int(a), int(b)  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 63,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def interpret(commands, grid=None, w=WIDTH, h=HEIGHT, \n",
+    "              show_each_step=False, md=False, overprint=False):\n",
+    "    if grid is None:\n",
+    "        grid = new_grid(w, h)\n",
+    "    frames = []\n",
+    "    for cn, c in enumerate(commands):\n",
+    "        cmd, a, b = parse(c)\n",
+    "        if cmd in command_dispatch:\n",
+    "            command_dispatch[cmd](grid, a, b)\n",
+    "        else:\n",
+    "            raise ValueError('Unknown command')\n",
+    "        if show_each_step:\n",
+    "            frames += [draw_frame(grid, c, cn)]\n",
+    "    if show_each_step: \n",
+    "        print('Final')\n",
+    "        print_grid(grid, md=md)\n",
+    "    frames[0].save('frames.gif', save_all=True, append_images=frames[1:], duration=200)\n",
+    "    return grid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "...****..............*...................*.....*..............*.................\n",
+      "......*..............*...................***..**..............*.................\n",
+      "......*.*****.*****.****.*****..****.....*.*.***.*****.*****.****.*****..****...\n",
+      "......*.....*.*...*..*.......*..*........*..**.*.....*.*...*..*.......*..*......\n",
+      "......*.*****.*...*..*...*****..*........*..*..*.*****.*...*..*...*****..*......\n",
+      "......*.*...*.*...*..*...*...*..*........*.....*.*...*.*...*..*...*...*..*......\n",
+      "...*..*.*..**.*...*..**..*..**..*........*.....*.*..**.*...*..**..*..**..*......\n",
+      "....**...**.*.*...*...**..**.*..*........*.....*..**.*.*...*...**..**.*..*......\n"
+     ]
+    }
+   ],
+   "source": [
+    "cmds = [c.strip() for c in open('05-pixels.txt').readlines()]\n",
+    "g = interpret(cmds)\n",
+    "print_grid(g)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(209, 17)\n"
+     ]
+    }
+   ],
+   "source": [
+    "im = Image.new('RGBA', (WIDTH * 10, HEIGHT * 10 + 21))\n",
+    "\n",
+    "# make a blank image for the text, initialized to transparent text color\n",
+    "# txt = Image.new('RGBA', im.size, (255,255,255,0))\n",
+    "txt = Image.new('RGBA', im.size, (0, 0, 0, 0))\n",
+    "\n",
+    "# get a font\n",
+    "fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 18)\n",
+    "# get a drawing context\n",
+    "d = ImageDraw.Draw(txt)\n",
+    "\n",
+    "# draw text, full opacity\n",
+    "d.text((1,1), \"Command description\", font=fnt, fill='black')\n",
+    "\n",
+    "print(d.textsize(\"Command description\", fnt))\n",
+    "\n",
+    "\n",
+    "draw = ImageDraw.Draw(im)\n",
+    "for (r, row) in enumerate(g):\n",
+    "    for (c, cell) in enumerate(row):\n",
+    "        rx = c * 10\n",
+    "        ry = r * 10 + 20\n",
+    "        if cell == '*':\n",
+    "            fill_colour = 'lime'\n",
+    "        else:\n",
+    "            fill_colour = 'black'\n",
+    "        draw.rectangle([rx, ry, rx + 10, ry + 10], fill=fill_colour, outline='orange')\n",
+    "            \n",
+    "# draw.line((0, 0) + im.size, fill=128)\n",
+    "# draw.line((0, im.size[1], im.size[0], 0), fill=128)\n",
+    "\n",
+    "out = Image.alpha_composite(im, txt)\n",
+    "out.save('test.png', 'PNG')\n",
+    "\n",
+    "del draw\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 76,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "def draw_frame(grid, command, frame_number):\n",
+    "    im = Image.new('RGBA', (WIDTH * 10, HEIGHT * 10 + 21))\n",
+    "\n",
+    "    # make a blank image for the text, initialized to transparent text color\n",
+    "    txt = Image.new('RGBA', im.size, (255,255,255,0))\n",
+    "#     txt = Image.new('RGBA', im.size, (0, 0, 0, 0)) # use this line rather than line above for animated png\n",
+    "\n",
+    "    # get a font\n",
+    "    fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 18)\n",
+    "    # get a drawing context\n",
+    "    d = ImageDraw.Draw(txt)\n",
+    "\n",
+    "    # draw text, full opacity\n",
+    "    d.text((1,1), command, font=fnt, fill='white')\n",
+    "#     d.text((1,1), command, font=fnt, fill='black') # use this line rather than line above for animated png\n",
+    "\n",
+    "    draw = ImageDraw.Draw(im)\n",
+    "    for (r, row) in enumerate(grid):\n",
+    "        for (c, cell) in enumerate(row):\n",
+    "            rx = c * 10\n",
+    "            ry = r * 10 + 20\n",
+    "            if cell == '*':\n",
+    "                fill_colour = 'lime'\n",
+    "            else:\n",
+    "                fill_colour = 'black'\n",
+    "            draw.rectangle([rx, ry, rx + 10, ry + 10], fill=fill_colour, outline=128)\n",
+    "\n",
+    "    # draw.line((0, 0) + im.size, fill=128)\n",
+    "    # draw.line((0, im.size[1], im.size[0], 0), fill=128)\n",
+    "\n",
+    "    out = Image.alpha_composite(im, txt)\n",
+    "#     out.save('frame{:04}.png'.format(frame_number), 'PNG') # uncomment here to save animated png frames\n",
+    "\n",
+    "    del draw\n",
+    "    \n",
+    "    return out"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['...****..............*...................*.....*..............*.................',\n",
+       " '......*..............*...................***..**..............*.................',\n",
+       " '......*.*****.*****.****.*****..****.....*.*.***.*****.*****.****.*****..****...',\n",
+       " '......*.....*.*...*..*.......*..*........*..**.*.....*.*...*..*.......*..*......',\n",
+       " '......*.*****.*...*..*...*****..*........*..*..*.*****.*...*..*...*****..*......',\n",
+       " '......*.*...*.*...*..*...*...*..*........*.....*.*...*.*...*..*...*...*..*......',\n",
+       " '...*..*.*..**.*...*..**..*..**..*........*.....*.*..**.*...*..**..*..**..*......',\n",
+       " '....**...**.*.*...*...**..**.*..*........*.....*..**.*.*...*...**..**.*..*......']"
+      ]
+     },
+     "execution_count": 24,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "g"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 77,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Final\n",
+      "...****..............*...................*.....*..............*.................\n",
+      "......*..............*...................***..**..............*.................\n",
+      "......*.*****.*****.****.*****..****.....*.*.***.*****.*****.****.*****..****...\n",
+      "......*.....*.*...*..*.......*..*........*..**.*.....*.*...*..*.......*..*......\n",
+      "......*.*****.*...*..*...*****..*........*..*..*.*****.*...*..*...*****..*......\n",
+      "......*.*...*.*...*..*...*...*..*........*.....*.*...*.*...*..*...*...*..*......\n",
+      "...*..*.*..**.*...*..**..*..**..*........*.....*.*..**.*...*..**..*..**..*......\n",
+      "....**...**.*.*...*...**..**.*..*........*.....*..**.*.*...*...**..**.*..*......\n",
+      "...****..............*...................*.....*..............*.................\n",
+      "......*..............*...................***..**..............*.................\n",
+      "......*.*****.*****.****.*****..****.....*.*.***.*****.*****.****.*****..****...\n",
+      "......*.....*.*...*..*.......*..*........*..**.*.....*.*...*..*.......*..*......\n",
+      "......*.*****.*...*..*...*****..*........*..*..*.*****.*...*..*...*****..*......\n",
+      "......*.*...*.*...*..*...*...*..*........*.....*.*...*.*...*..*...*...*..*......\n",
+      "...*..*.*..**.*...*..**..*..**..*........*.....*.*..**.*...*..**..*..**..*......\n",
+      "....**...**.*.*...*...**..**.*..*........*.....*..**.*.*...*...**..**.*..*......\n"
+     ]
+    }
+   ],
+   "source": [
+    "cmds = [c.strip() for c in open('05-pixels.txt').readlines()]\n",
+    "g = interpret(cmds, show_each_step=True)\n",
+    "print_grid(g)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Create animated png."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "! apngasm frames.png frame0*png 1 5"
+   ]
+  }
+ ],
+ "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
+}
diff --git a/05-display-board/frames.gif b/05-display-board/frames.gif
new file mode 100644 (file)
index 0000000..c1a27d8
Binary files /dev/null and b/05-display-board/frames.gif differ
diff --git a/05-display-board/frames.png b/05-display-board/frames.png
new file mode 100644 (file)
index 0000000..238de44
Binary files /dev/null and b/05-display-board/frames.png differ