X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=05-display-board%2Fdisplay-board-animation.ipynb;fp=05-display-board%2Fdisplay-board-animation.ipynb;h=b004b96a096e6dd9f9de815f1d3c00b38a2bda8f;hb=0d872921c8bfd3f68dbce5eeda4a4548814151ab;hp=0000000000000000000000000000000000000000;hpb=743e19357f7a93e3f7a7860bd174ddc5fe2610bc;p=ou-summer-of-code-2017.git diff --git a/05-display-board/display-board-animation.ipynb b/05-display-board/display-board-animation.ipynb new file mode 100644 index 0000000..b004b96 --- /dev/null +++ b/05-display-board/display-board-animation.ipynb @@ -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 +}