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