diff --git a/encoding-systems/encoding-systems.ipynb b/encoding-systems/encoding-systems.ipynb new file mode 100644 index 0000000..9522243 --- /dev/null +++ b/encoding-systems/encoding-systems.ipynb @@ -0,0 +1,1113 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Encoding systems: *ASCII*, *PETSCII*, *Unicode*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Encoding systems\n", + "\n", + "The process of converting from one type of information to another is called encoding. You can think of it as a similar process to [Morse Code](https://en.wikipedia.org/wiki/Morse_code) where longer and shorter beeps represent letters. \n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/thumb/b/b5/International_Morse_Code.svg/450px-International_Morse_Code.svg.png)\n", + "\n", + "`(Exercise: try to use the encoding system above to decode this: .... . .-.. .-.. ---- .-- ---- .-. -..)`\n", + "\n", + "Or the process of dialing a phone number, where pressing the keys generate [a specific sound](https://www.youtube.com/watch?v=dIHqT0IhZwI) which tells the computers at the phone central who to connect you to. \n", + "\n", + "Using the technique of encoding and decoding binary numbers can be made to represent everthing you see on the computer. There are standards, conventions which describe how something should be encoded and decoded so that one type of information can be translated in multiple places.\n", + "\n", + "**n.b.** That encoding is not the same as encrypting! In the process of encoding the mapping between the code and the desired result are known and communicated. In encryption that mapping is purposely kept a secret. \n", + "\n", + "## Text encodings\n", + "\n", + "As a computer can only work with numbers, it cannot process of letters text directly. In order to work with text, textual characters need to be translated into numbers and vice versa. This is done via the process of text encodings.\n", + "\n", + "It might be your first reaction to think that this shouldn't be so difficult. We could represent the letter in binary code. An `a` encoded as a `0`, `b` as a `1` and `c` as a `01` etc. And in fact this is more or less how text encodings work. However, at the time when computing was being developed different encodings emerged.\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/7/77/Wikipedia_in_binary.gif)\n", + "\n", + "### ASCII encoding \n", + "\n", + "![ASCII table](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/USASCII_code_chart.png/640px-USASCII_code_chart.png)\n", + "\n", + "The dominant encoding at the time became ASCII (for *American Standard Code for Information Interchange*.), which was created on behalf of the U.S. Government in 1963 to allow for information interchange between their different computing systems.\n", + "\n", + "The encoding uses a 7-bit system, which means that they could only store characters in 128 (`2^7=128`) numbers (`0000 0000` until `0111 1111`). The resulting encoding schema assigned to each of these 128 numbers:\n", + " \n", + "* all the letters in the English alphabet\n", + "* numbers from 0-9\n", + "* punctuation marks \n", + "* and control characters \n", + "\n", + "Thanks to the simplicity of the encoding it quickly became a standard for the American computing industry.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ASCII imperialism\n", + "\n", + "Thanks to the power of the US Military and US corporations the American computing industry became the global computing industry. Computers that we use today are rooted in American networking history, and so is the ASCII standard. However, the reality is that ASCII can only represent 26 Latin letters in the English alphabet but computers are used all over the world, by people speaking different languages. They would often end up with American computers that could not represent their language in ASCII. Think for example of scripts like Greek, Cyrillic and Arabic or even Latin scripts that use accents such as the `ü` or `ø`. Altough 128 might sound like a lot of characters, it is not enough to represent all different languages." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise - the limits of ASCII\n", + "\n", + "Not all the characters fit within 128 or even 256 bits. \n", + "\n", + "Try this for example:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + "UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)\n" + ] + } + ], + "source": [ + "! python2.7 -c \"print 'ø'.encode('ascii')\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For a time people used the 8th bit, numbers `1000 0000` to `1111 1111` (or 128 to 256) to encode the specific parts of their own language. That way there was an overlap with ASCII but the own language could also be encoded. \n", + "\n", + "A list of all the 128 ASCII characters, and their corresponding numbers can be seen in this table:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ASCII(7) Linux Programmer's Manual ASCII(7)\n", + "\n", + "NAME\n", + " ascii - ASCII character set encoded in octal, decimal, and hexadecimal\n", + "\n", + "DESCRIPTION\n", + " ASCII is the American Standard Code for Information Interchange. It is\n", + " a 7-bit code. Many 8-bit codes (e.g., ISO 8859-1) contain ASCII as\n", + " their lower half. The international counterpart of ASCII is known as\n", + " ISO 646-IRV.\n", + "\n", + " The following table contains the 128 ASCII characters.\n", + "\n", + " C program '\\X' escapes are noted.\n", + "\n", + " Oct Dec Hex Char Oct Dec Hex Char\n", + " ────────────────────────────────────────────────────────────────────────\n", + " 000 0 00 NUL '\\0' (null character) 100 64 40 @\n", + " 001 1 01 SOH (start of heading) 101 65 41 A\n", + " 002 2 02 STX (start of text) 102 66 42 B\n", + " 003 3 03 ETX (end of text) 103 67 43 C\n", + " 004 4 04 EOT (end of transmission) 104 68 44 D\n", + " 005 5 05 ENQ (enquiry) 105 69 45 E\n", + " 006 6 06 ACK (acknowledge) 106 70 46 F\n", + " 007 7 07 BEL '\\a' (bell) 107 71 47 G\n", + " 010 8 08 BS '\\b' (backspace) 110 72 48 H\n", + " 011 9 09 HT '\\t' (horizontal tab) 111 73 49 I\n", + " 012 10 0A LF '\\n' (new line) 112 74 4A J\n", + " 013 11 0B VT '\\v' (vertical tab) 113 75 4B K\n", + " 014 12 0C FF '\\f' (form feed) 114 76 4C L\n", + " 015 13 0D CR '\\r' (carriage ret) 115 77 4D M\n", + " 016 14 0E SO (shift out) 116 78 4E N\n", + " 017 15 0F SI (shift in) 117 79 4F O\n", + " 020 16 10 DLE (data link escape) 120 80 50 P\n", + " 021 17 11 DC1 (device control 1) 121 81 51 Q\n", + " 022 18 12 DC2 (device control 2) 122 82 52 R\n", + " 023 19 13 DC3 (device control 3) 123 83 53 S\n", + " 024 20 14 DC4 (device control 4) 124 84 54 T\n", + " 025 21 15 NAK (negative ack.) 125 85 55 U\n", + " 026 22 16 SYN (synchronous idle) 126 86 56 V\n", + " 027 23 17 ETB (end of trans. blk) 127 87 57 W\n", + " 030 24 18 CAN (cancel) 130 88 58 X\n", + " 031 25 19 EM (end of medium) 131 89 59 Y\n", + " 032 26 1A SUB (substitute) 132 90 5A Z\n", + " 033 27 1B ESC (escape) 133 91 5B [\n", + " 034 28 1C FS (file separator) 134 92 5C \\ '\\\\'\n", + " 035 29 1D GS (group separator) 135 93 5D ]\n", + " 036 30 1E RS (record separator) 136 94 5E ^\n", + " 037 31 1F US (unit separator) 137 95 5F _\n", + " 040 32 20 SPACE 140 96 60 `\n", + " 041 33 21 ! 141 97 61 a\n", + " 042 34 22 \" 142 98 62 b\n", + " 043 35 23 # 143 99 63 c\n", + " 044 36 24 $ 144 100 64 d\n", + " 045 37 25 % 145 101 65 e\n", + " 046 38 26 & 146 102 66 f\n", + " 047 39 27 ' 147 103 67 g\n", + " 050 40 28 ( 150 104 68 h\n", + " 051 41 29 ) 151 105 69 i\n", + " 052 42 2A * 152 106 6A j\n", + " 053 43 2B + 153 107 6B k\n", + " 054 44 2C , 154 108 6C l\n", + " 055 45 2D - 155 109 6D m\n", + "\n", + " 056 46 2E . 156 110 6E n\n", + " 057 47 2F / 157 111 6F o\n", + " 060 48 30 0 160 112 70 p\n", + " 061 49 31 1 161 113 71 q\n", + " 062 50 32 2 162 114 72 r\n", + " 063 51 33 3 163 115 73 s\n", + " 064 52 34 4 164 116 74 t\n", + " 065 53 35 5 165 117 75 u\n", + " 066 54 36 6 166 118 76 v\n", + " 067 55 37 7 167 119 77 w\n", + " 070 56 38 8 170 120 78 x\n", + " 071 57 39 9 171 121 79 y\n", + " 072 58 3A : 172 122 7A z\n", + " 073 59 3B ; 173 123 7B {\n", + " 074 60 3C < 174 124 7C |\n", + " 075 61 3D = 175 125 7D }\n", + " 076 62 3E > 176 126 7E ~\n", + " 077 63 3F ? 177 127 7F DEL\n", + "\n", + " Tables\n", + " For convenience, below are more compact tables in hex and decimal.\n", + "\n", + " 2 3 4 5 6 7 30 40 50 60 70 80 90 100 110 120\n", + " ------------- ---------------------------------\n", + " 0: 0 @ P ` p 0: ( 2 < F P Z d n x\n", + " 1: ! 1 A Q a q 1: ) 3 = G Q [ e o y\n", + " 2: \" 2 B R b r 2: * 4 > H R \\ f p z\n", + " 3: # 3 C S c s 3: ! + 5 ? I S ] g q {\n", + " 4: $ 4 D T d t 4: \" , 6 @ J T ^ h r |\n", + " 5: % 5 E U e u 5: # - 7 A K U _ i s }\n", + " 6: & 6 F V f v 6: $ . 8 B L V ` j t ~\n", + " 7: ' 7 G W g w 7: % / 9 C M W a k u DEL\n", + " 8: ( 8 H X h x 8: & 0 : D N X b l v\n", + " 9: ) 9 I Y i y 9: ' 1 ; E O Y c m w\n", + " A: * : J Z j z\n", + " B: + ; K [ k {\n", + " C: , < L \\ l |\n", + " D: - = M ] m }\n", + " E: . > N ^ n ~\n", + " F: / ? O _ o DEL\n", + "\n", + "NOTES\n", + " History\n", + " An ascii manual page appeared in Version 7 of AT&T UNIX.\n", + "\n", + " On older terminals, the underscore code is displayed as a left arrow,\n", + " called backarrow, the caret is displayed as an up-arrow and the verti‐\n", + " cal bar has a hole in the middle.\n", + "\n", + " Uppercase and lowercase characters differ by just one bit and the ASCII\n", + " character 2 differs from the double quote by just one bit, too. That\n", + " made it much easier to encode characters mechanically or with a non-mi‐\n", + " crocontroller-based electronic keyboard and that pairing was found on\n", + " old teletypes.\n", + "\n", + " The ASCII standard was published by the United States of America Stan‐\n", + " dards Institute (USASI) in 1968.\n", + "\n", + "SEE ALSO\n", + " charsets(7), iso_8859-1(7), iso_8859-10(7), iso_8859-11(7),\n", + " iso_8859-13(7), iso_8859-14(7), iso_8859-15(7), iso_8859-16(7),\n", + " iso_8859-2(7), iso_8859-3(7), iso_8859-4(7), iso_8859-5(7),\n", + " iso_8859-6(7), iso_8859-7(7), iso_8859-8(7), iso_8859-9(7), utf-8(7)\n", + "\n", + "COLOPHON\n", + " This page is part of release 4.16 of the Linux man-pages project. A\n", + " description of the project, information about reporting bugs, and the\n", + " latest version of this page, can be found at\n", + " https://www.kernel.org/doc/man-pages/.\n", + "\n", + "Linux 2016-10-08 ASCII(7)\n" + ] + } + ], + "source": [ + "! man ascii" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise - decode binary into ASCII\n", + "\n", + "Use an ASCII code table and decode the following binary code:\n", + "\n", + " 0100 1000\n", + " 0110 0101\n", + " 0110 1100\n", + " 0110 1100\n", + " 0110 1111\n", + " 0010 0000\n", + " 0101 0111\n", + " 0110 1111\n", + " 0111 0010\n", + " 0110 1100\n", + " 0110 0100\n", + " 0010 0001" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ASCII flavours: PETSCII\n", + "\n", + "### Commodore 64 (1982)\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Commodore-64-Computer-FL.jpg/320px-Commodore-64-Computer-FL.jpg)\n", + "\n", + "> The Commodore 64, also known as the C64 or the CBM 64, is an 8-bit home computer introduced in January 1982 by Commodore International (first shown at the Consumer Electronics Show, January 7–10, 1982, in Las Vegas). It has been listed in the Guinness World Records as the highest-selling single computer model of all time, with independent estimates placing the number sold between 12.5 and 17 million units. \n", + "\n", + "> Preceded by the Commodore VIC-20 and Commodore PET, the C64 took its name from its 64 kilobytes (65,536 bytes) of RAM. With support for multicolor sprites and a custom chip for waveform generation, the C64 could create superior visuals and audio compared to systems without such custom hardware. \n", + "\n", + "https://en.wikipedia.org/wiki/Commodore_64\n", + "\n", + "> Part of the Commodore 64's success was its sale in regular retail stores instead of only electronics or computer hobbyist specialty stores. Commodore produced many of its parts in-house to control costs, including custom integrated circuit chips from MOS Technology. In the United States, it has been compared to the Ford Model T automobile for its role in bringing a new technology to middle-class households via creative and affordable mass-production.\n", + "\n", + "Kahney, Leander (September 9, 2003). \"Grandiose Price for a Modest PC\". CondéNet, Inc. Archived from the original on September 14, 2008. Retrieved September 13, 2008.\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/4/48/C64_startup_animiert.gif)\n", + "\n", + "### PETSCII \n", + "\n", + "![](https://www.pagetable.com/docs/c64ref_charset/colorscheme.gif)\n", + "\n", + "> The Commodore PET's lack of a programmable bitmap-mode for computer graphics, as well as it having no redefinable character set capability, may be one of the reasons PETSCII was developed; by creatively using the well-thought-out block graphics, a higher degree of sophistication in screen graphics is attainable than by using plain ASCII's letter/digit/punctuation characters. In addition to the relatively diverse set of geometrical shapes that can thus be produced, PETSCII allows for several grayscale levels by its provision of differently hatched checkerboard squares/half-squares. Finally, the reverse-video mode (see below) is used to complete the range of graphics characters, in that it provides mirrored half-square blocks. \n", + "\n", + "https://en.wikipedia.org/wiki/PETSCII\n", + "\n", + "Draw PETSCII art in the browser:\n", + "\n", + "* https://petscii.krissz.hu/\n", + "* https://www.masswerk.at/pet/\n", + "\n", + "Use PETSCII as a font!\n", + "\n", + "* https://style64.org/c64-truetype\n", + "\n", + "PETSCII bots!\n", + "\n", + "* https://twitter.com/PETSCIIBOTS" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unicode universalism\n", + "\n", + "> 'As electronic text was increasingly being exchanged online and between language areas, issues emerged when text encoded in one language was shared and read on systems assuming an encoding in another language. Unicode was a response to the incompatible text encoding standards that were proliferating. \n", + "> \n", + "> When different encodings assign the same binary numbers to different characters, this results in illegible documents. The solution, partly made possible by increased computing capacity, was to strive for a single universal encoding which would encompass all writing systems' \n", + "> \n", + "> (Roel Roscam Abbing, Peggy Pierrot, Femke Snelting (2016), [*Modifying the Universal*](http://roelof.info/~r/DB06_Executing_Practices_Modifiying_the_Universal_Pierrot_Roscam_Abbing_Snelting.pdf))\n", + "\n", + "You can experience this following the \"break Yahoo\" exercise below.\n", + "\n", + "So in order to overcome the limitations of ASCII people created the Unicode Consortium to create a single universal character encoding:\n", + "\n", + "> 'The Unicode standards are designed to normalise the encoding of characters, to efficiently manage the way they are stored, referred to and displayed in order to facilitate cross-platform, multilingual and international text exchange. The Unicode Standard is mammoth in size and covers well over 110,000 characters, of which [..] 1,000 are [..] emoji.' \n", + "> \n", + "> (Roel Roscam Abbing, Peggy Pierrot, Femke Snelting (2016), [*Modifying the Universal*](http://roelof.info/~r/DB06_Executing_Practices_Modifiying_the_Universal_Pierrot_Roscam_Abbing_Snelting.pdf))\n", + "\n", + "In effect the Unicode Standard combined all the different national character encodings together into a single large ledger in order to try to represent all languages. It is divided in so called blocks, which are basically number tables that describe which number is connected to which character. The table starts counting at `0x0` and continues all the way up to `0x10FFFF`. \n", + "\n", + "The first block actually corresponds with ASCII: \n", + "\n", + "It contains many different scripts for supporting large and smaller language groups, including for example Ethiopian and Cherokee: \n", + "\n", + "However there are also blocks that describe Arrows and other symbols: \n", + " \n", + "Emoji are also part of the unicode table. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## From Unicode codepoint, to character, to glyph\n", + "\n", + "![Image representing a Unicode codepoint, a character and various glyphs](https://vvvvvvaria.org/~r/codepointglyph.png)\n", + "\n", + "In the Unicode standard every text character has a representation as a number or codepoint. The standard defines what codepoint is connected to what character, but not what *glyph* should look like. That is left to individual font designers.\n", + "\n", + "Next to the letters, there are many control characters that are used for example to display text from right to left and reverse or to join two separate characters together into one (as happens with Asian language scripts)\n", + "\n", + "One of the curious things about Unicode is that there are many homographs (characters look identical, have different code points).\n", + "\n", + "For example:\n", + "Greek `Ο`, Latin `O`, and Cyrillic `О` are identical to the eye, but different to the computer.\n", + "\n", + "You can tell when you take a closer look:\n", + " \n", + "`Ο` = `0x39f` for Greek \n", + "`O` = `0x4f` for Latin\n", + "`О` = `0x41e` for Cyrillic\n", + " \n", + "Try to copy the Greek or Cyrillic `О` and search for it in the document by pressing `ctrl + f` and entering it in the search bar. Then do the same with the Latin O." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise - generating \"Unicode-codepoint-art\"\n", + "\n", + "Here is a piece of python code that will fill try to print out all Unicode characters by counting from `0x0` to `0x10FFFF` and converting that into a printable character:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\n", + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\n", + "\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\u0002\n", + "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\n", + "\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\u0004\n", + "\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\n", + "\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\u0006\n", + "\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\n", + "\n", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\u000b", + "\n", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\f", + "\n", + "\n", + "\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\u000e\n", + "\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\u000f\n", + "\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\u0010\n", + "\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\u0011\n", + "\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\n", + "\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\u0013\n", + "\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\u0014\n", + "\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\u0015\n", + "\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\u0016\n", + "\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\u0017\n", + "\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\u0018\n", + "\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\u0019\n", + "\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\u001a\n", + "\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\u001b\n", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\u001c", + "\n", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\u001d", + "\n", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\u001e", + "\n", + "\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\u001f\n", + " \n", + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", + "\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n", + "################################################################################\n", + "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n", + "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\n", + "''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''\n", + "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\n", + "))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))\n", + "********************************************************************************\n", + "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n", + ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\n", + "--------------------------------------------------------------------------------\n", + "................................................................................\n", + "////////////////////////////////////////////////////////////////////////////////\n", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000\n", + "11111111111111111111111111111111111111111111111111111111111111111111111111111111\n", + "22222222222222222222222222222222222222222222222222222222222222222222222222222222\n", + "33333333333333333333333333333333333333333333333333333333333333333333333333333333\n", + "44444444444444444444444444444444444444444444444444444444444444444444444444444444\n", + "55555555555555555555555555555555555555555555555555555555555555555555555555555555\n", + "66666666666666666666666666666666666666666666666666666666666666666666666666666666\n", + "77777777777777777777777777777777777777777777777777777777777777777777777777777777\n", + "88888888888888888888888888888888888888888888888888888888888888888888888888888888\n", + "99999999999999999999999999999999999999999999999999999999999999999999999999999999\n", + "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n", + ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n", + "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + "================================================================================\n", + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", + "????????????????????????????????????????????????????????????????????????????????\n", + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n", + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n", + "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n", + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\n", + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n", + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\n", + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\n", + "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\n", + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\n", + "KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK\n", + "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN\n", + "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n", + "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP\n", + "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ\n", + "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\n", + "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\n", + "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\n", + "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\n", + "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n", + "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n", + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n", + "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY\n", + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\n", + "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\n", + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n", + "]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\n", + "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "________________________________________________________________________________\n", + "````````````````````````````````````````````````````````````````````````````````\n", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n", + "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n", + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\n", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n", + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n", + "gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg\n", + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", + "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\n", + "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n", + "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\n", + "llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll\n", + "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm\n", + "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\n", + "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\n", + "pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp\n", + "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\n", + "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\n", + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\n", + "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt\n", + "^C\n", + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + " File \"\", line 6, in \n", + "KeyboardInterrupt\n" + ] + } + ], + "source": [ + "! python -c 'exec \"\"\"\\nimport time\\nwhile True:\\n for i in range(0x0,0x10FFFF):\\n print unichr(i)*80\\n time.sleep(0.05)\\n\"\"\"'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this technique it is also possible to make animations:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑\n", + "🌒🌒🌒🌒🌒🌒🌒🌒🌒🌒\n", + "🌓🌓🌓🌓🌓🌓🌓🌓🌓🌓\n", + "🌔🌔🌔🌔🌔🌔🌔🌔🌔🌔\n", + "🌕🌕🌕🌕🌕🌕🌕🌕🌕🌕\n", + "🌖🌖🌖🌖🌖🌖🌖🌖🌖🌖\n", + "🌗🌗🌗🌗🌗🌗🌗🌗🌗🌗\n", + "🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑\n", + "🌒🌒🌒🌒🌒🌒🌒🌒🌒🌒\n", + "🌓🌓🌓🌓🌓🌓🌓🌓🌓🌓\n", + "🌔🌔🌔🌔🌔🌔🌔🌔🌔🌔\n", + "🌕🌕🌕🌕🌕🌕🌕🌕🌕🌕\n", + "🌖🌖🌖🌖🌖🌖🌖🌖🌖🌖\n", + "🌗🌗🌗🌗🌗🌗🌗🌗🌗🌗\n", + "🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑\n", + "🌒🌒🌒🌒🌒🌒🌒🌒🌒🌒\n", + "🌓🌓🌓🌓🌓🌓🌓🌓🌓🌓\n", + "🌔🌔🌔🌔🌔🌔🌔🌔🌔🌔\n", + "🌕🌕🌕🌕🌕🌕🌕🌕🌕🌕\n", + "🌖🌖🌖🌖🌖🌖🌖🌖🌖🌖\n", + "🌗🌗🌗🌗🌗🌗🌗🌗🌗🌗\n", + "🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑\n", + "🌒🌒🌒🌒🌒🌒🌒🌒🌒🌒\n", + "🌓🌓🌓🌓🌓🌓🌓🌓🌓🌓\n", + "🌔🌔🌔🌔🌔🌔🌔🌔🌔🌔\n", + "🌕🌕🌕🌕🌕🌕🌕🌕🌕🌕\n", + "🌖🌖🌖🌖🌖🌖🌖🌖🌖🌖\n", + "🌗🌗🌗🌗🌗🌗🌗🌗🌗🌗\n", + "🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑\n", + "🌒🌒🌒🌒🌒🌒🌒🌒🌒🌒\n", + "🌓🌓🌓🌓🌓🌓🌓🌓🌓🌓\n", + "🌕🌕🌕🌕🌕🌕🌕🌕🌕🌕\n", + "^C\n", + "Traceback (most recent call last):\n", + " File \"\", line 1, in \n", + " File \"\", line 6, in \n", + "KeyboardInterrupt\n" + ] + } + ], + "source": [ + "! python -c 'exec \"\"\"\\nimport time\\nwhile True:\\n for i in range(127761,127768):\\n print unichr(i)*10\\n time.sleep(0.05)\\n\"\"\"'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercise - what does a japanese website look like in ASCII?\n", + "\n", + "1. Go to [https://www.yahoo.co.jp/](https://www.yahoo.co.jp/) in your browser.\n", + "2. Save the page to your computer. You could use `CMD+S` or `CTRL+S` for this.\n", + "3. Open the page in a text editor.\n", + "4. Edit line 3 of the file: `` and change the encoding of the document from `UTF-8` into `ASCII`.\n", + "5. Open the page.\n", + "\n", + "You have now Mojibaked the page!\n", + "\n", + "([Mojibake article on Wikipedia](https://en.wikipedia.org/wiki/Mojibake))" + ] + }, + { + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/mazes-and-maps/Screenshot-c64-ad.png b/mazes-and-maps/Screenshot-c64-ad.png new file mode 100644 index 0000000..83eb972 Binary files /dev/null and b/mazes-and-maps/Screenshot-c64-ad.png differ diff --git a/mazes-and-maps/labyrinths-and-mazes.ipynb b/mazes-and-maps/labyrinths-and-mazes.ipynb new file mode 100644 index 0000000..39b4647 --- /dev/null +++ b/mazes-and-maps/labyrinths-and-mazes.ipynb @@ -0,0 +1,467 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Labyrinths and mazes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "🐭\n", + "┃┣━━━┳━━━━┳━━┓\n", + "┃┗┓┏┛┃╻╺━━┛╺┓┃\n", + "┣┓┃┗┓┗┻━━━┳╸┃┃\n", + "┃┃┣╸┣━━┳━┓┗━┛┃\n", + "┃┃┃┏┛┏╸┃╻┣━┳╸┃\n", + "┃┗━┫╻┣━━┫┗╸┃┏┫\n", + "┃┏━┫┃┃╺┓┗━┓┃┃┃\n", + "┃┃┃┃┃┗┓┗━┓┗┻╸┃\n", + "┗━┫┏┻━━━━┻━━━┛\n", + " 🧀\n", + "```\n", + "http://xahlee.info/comp/unicode_drawing_shapes.html by [Xah Lee](http://xahlee.org/index.html)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Situationist Times #04: International Labyrinth Edition\n", + "\n", + "[![](https://vandal.ist/thesituationisttimes/covers/st04.cover.m.jpg)](https://vandal.ist/thesituationisttimes/04/)\n", + "\n", + "Jacqueline de Jong (one of the makers of the Situationist Times) talking about [printed mazes with overlay](https://vandal.ist/thesituationisttimes/04/index.html#8/-1.869/118.973).\n", + "\n", + "The PDFs of the Situationist Times are [available on Monoskop](https://monoskop.org/Situationist_Times)! " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 10 PRINT\n", + "\n", + "Nick Montfort and others compilation of maze generation and other simple scripts from early home computing.\n", + "\n", + "https://hub.xpub.nl/bootleglibrary/book/583\n", + "\n", + "Some links to nice parts:\n", + "\n", + "* Including [what is a maze](https://hub.xpub.nl/bootleglibrary/read/583/pdf#page=47), and the ever useful (controversial?) distinction between maze and labyrinth...\n", + "\n", + "> The terms “maze” and “labyrinth” are generally synonyms in colloquial English. Still, many scholars and historians have argued over the distinction between these two terms. In the most popular proposed distinction, “labyrinth” refers only to single-path (unicursal) structures, while “maze” refers only to branching-path (multicursal) structures.In this book, the terms “maze” and “labyrinth” are not used to distinguish two different categories of structure or image. Instead, the two terms indicate a single conceptual category, with this book primarily using the term “maze” for both\n", + "\n", + "* the [map from Atari adventure](https://hub.xpub.nl/bootleglibrary/read/583/pdf#page=62), \n", + "* the (missing) [Vera Molnar work](https://hub.xpub.nl/bootleglibrary/read/583/pdf#page=78) but which you can see [online](https://www.centrepompidou.fr/fr/ressources/oeuvre/cez6op), \n", + "* the [commodore keyboard](https://hub.xpub.nl/bootleglibrary/read/583/pdf#page=227) and the [PETSCII table in the manual](https://hub.xpub.nl/bootleglibrary/read/583/pdf#page=238)\n", + "\n", + "AND an interesting link to the conversation about popular culture and the middle-class:\n", + "\n", + "![](Screenshot-c64-ad.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fun With Python #1: Maze Generator\n", + "\n", + "This notebook is based on the Medium article \"Fun with Python part 1: Maze Generator\" written by [Orestis Zekai](https://orestiszekai.com/) in 2020. \n", + "\n", + "It is a nice tutorial which talks you through a Python implementation of a maze generator. \n", + "\n", + "You can find the tutorial here: https://medium.com/swlh/fun-with-python-1-maze-generator-931639b4fb7e\n", + "\n", + "The maze generator is based on a **randomized version of Prim's algorithm**, which is one of the [maze algorithms](https://en.wikipedia.org/wiki/Maze_generation_algorithm) that is used to generate a maze:\n", + "\n", + "* Start with a grid full of walls.\n", + "* Pick a cell, mark it as part of the maze. Add the walls of the cell to the wall list.\n", + "* While there are walls in the list:\n", + " * Pick a random wall from the list. If only one of the cells that the wall divides is visited, then:\n", + " * Make the wall a passage and mark the unvisited cell as part of the maze.\n", + " * Add the neighboring walls of the cell to the wall list.\n", + " * Remove the wall from the list." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating mazes on paper\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import IFrame\n", + "IFrame(\"maze-algorithm-on-paper.pdf\", width=600, height=400)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Maze Generator\n", + "\n", + "The code below is a slightly adapted version of `maze.py` written by Orestis Zekai: https://github.com/OrWestSide/python-scripts/blob/master/maze.py\n", + "\n", + "You can use the code to generate custom mazes. \n", + "\n", + "Change the following variables in the code, to make your maze bigger or smaller and to change how your maze looks like!\n", + "\n", + "```\n", + "# --------------------------\n", + "wall_tile = \"▓\"\n", + "cell_tile = \"░\"\n", + "height = 11\n", + "width = 27\n", + "# --------------------------\n", + "\n", + "```\n", + "\n", + "**NOTE**: The code below is a slightly different version of the code from the tutorial. The variable names are changed in the double for-loops, to make them connect to the other canvas examples in the other notebooks. For example, a for loop to move block by block through the maze is written below in the following way, using `y` and `x` to refer to the coordinates of a block:\n", + "\n", + "```\n", + "for y in range(height):\n", + " for x in range(width):\n", + " if (maze[y][x] == \"u\"):\n", + " print(unvisited, end=\"\")\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "▓░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n", + "▓░▓▓░▓▓░▓░▓░░░░░░░░▓░░░░░░▓\n", + "▓░░░░░░░░░░░▓▓░▓░▓░░░▓░▓▓▓▓\n", + "▓░▓▓▓▓▓▓▓▓░▓▓▓░▓░▓▓▓░▓░░░░▓\n", + "▓░░░░░░░░▓▓▓░▓▓▓░░▓▓▓▓▓▓▓▓▓\n", + "▓░▓░▓▓▓▓░░░░░░░▓▓░░░▓░▓▓▓▓▓\n", + "▓░▓░░▓▓▓▓▓▓▓░▓░░▓░▓░░░░░░░▓\n", + "▓░▓▓░░░░░░▓▓░▓▓░▓░▓░▓▓░▓░▓▓\n", + "▓▓▓▓▓░▓▓▓▓▓▓░░▓░▓▓▓░░▓░▓▓▓▓\n", + "▓░░░░░░░░░░▓░▓▓░▓▓░░▓▓░░░░▓\n", + "▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░▓\n" + ] + } + ], + "source": [ + "# Maze generator -- Randomized Prim Algorithm\n", + "\n", + "## Imports\n", + "import random\n", + "\n", + "## Functions\n", + "def printMaze(maze):\n", + " for y in range(height):\n", + " for x in range(width):\n", + " if (maze[y][x] == \"u\"):\n", + " print(unvisited, end=\"\")\n", + " elif (maze[y][x] == \"c\"):\n", + " print(cell_tile, end=\"\")\n", + " else:\n", + " print(wall_tile, end=\"\")\n", + " \n", + " print(\"\")\n", + "\n", + "# Find number of surrounding cells\n", + "def surroundingCells(rand_wall):\n", + " s_cells = 0\n", + " if (maze[rand_wall[0]-1][rand_wall[1]] == \"c\"):\n", + " s_cells += 1\n", + " if (maze[rand_wall[0]+1][rand_wall[1]] == \"c\"):\n", + " s_cells += 1\n", + " if (maze[rand_wall[0]][rand_wall[1]-1] == \"c\"):\n", + " s_cells +=1\n", + " if (maze[rand_wall[0]][rand_wall[1]+1] == \"c\"):\n", + " s_cells += 1\n", + "\n", + " return s_cells\n", + "\n", + "## Main code\n", + "\n", + "# Init variables\n", + "# --------------------------\n", + "wall_tile = \"▓\"\n", + "cell_tile = \"░\"\n", + "height = 11\n", + "width = 27\n", + "# --------------------------\n", + "wall = \"w\"\n", + "cell = \"c\"\n", + "unvisited = \"u\"\n", + "maze = []\n", + "\n", + "# Denote all cells as unvisited\n", + "for y in range(height):\n", + " line = []\n", + " for x in range(width):\n", + " line.append(unvisited)\n", + " maze.append(line)\n", + "\n", + "# Randomize starting point and set it a cell\n", + "starting_height = int(random.random()*height)\n", + "starting_width = int(random.random()*width)\n", + "if (starting_height == 0):\n", + " starting_height += 1\n", + "if (starting_height == height-1):\n", + " starting_height -= 1\n", + "if (starting_width == 0):\n", + " starting_width += 1\n", + "if (starting_width == width-1):\n", + " starting_width -= 1\n", + "\n", + "# Mark it as cell and add surrounding walls to the list\n", + "maze[starting_height][starting_width] = cell\n", + "walls = []\n", + "walls.append([starting_height - 1, starting_width])\n", + "walls.append([starting_height, starting_width - 1])\n", + "walls.append([starting_height, starting_width + 1])\n", + "walls.append([starting_height + 1, starting_width])\n", + "\n", + "# Denote walls in maze\n", + "maze[starting_height-1][starting_width] = \"w\"\n", + "maze[starting_height][starting_width - 1] = \"w\"\n", + "maze[starting_height][starting_width + 1] = \"w\"\n", + "maze[starting_height + 1][starting_width] = \"w\"\n", + "\n", + "while (walls):\n", + " # Pick a random wall\n", + " rand_wall = walls[int(random.random()*len(walls))-1]\n", + "\n", + " # Check if it is a left wall\n", + " if (rand_wall[1] != 0):\n", + " if (maze[rand_wall[0]][rand_wall[1]-1] == \"u\" and maze[rand_wall[0]][rand_wall[1]+1] == \"c\"):\n", + " # Find the number of surrounding cells\n", + " s_cells = surroundingCells(rand_wall)\n", + "\n", + " if (s_cells < 2):\n", + " # Denote the new path\n", + " maze[rand_wall[0]][rand_wall[1]] = \"c\"\n", + "\n", + " # Mark the new walls\n", + " # Upper cell\n", + " if (rand_wall[0] != 0):\n", + " if (maze[rand_wall[0]-1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]-1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]-1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]-1, rand_wall[1]])\n", + "\n", + " # Bottom cell\n", + " if (rand_wall[0] != height-1):\n", + " if (maze[rand_wall[0]+1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]+1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]+1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]+1, rand_wall[1]])\n", + "\n", + " # Leftmost cell\n", + " if (rand_wall[1] != 0): \n", + " if (maze[rand_wall[0]][rand_wall[1]-1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]-1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]-1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]-1])\n", + "\n", + " # Delete wall\n", + " for wall in walls:\n", + " if (wall[0] == rand_wall[0] and wall[1] == rand_wall[1]):\n", + " walls.remove(wall)\n", + "\n", + " continue\n", + "\n", + " # Check if it is an upper wall\n", + " if (rand_wall[0] != 0):\n", + " if (maze[rand_wall[0]-1][rand_wall[1]] == \"u\" and maze[rand_wall[0]+1][rand_wall[1]] == \"c\"):\n", + "\n", + " s_cells = surroundingCells(rand_wall)\n", + " if (s_cells < 2):\n", + " # Denote the new path\n", + " maze[rand_wall[0]][rand_wall[1]] = \"c\"\n", + "\n", + " # Mark the new walls\n", + " # Upper cell\n", + " if (rand_wall[0] != 0):\n", + " if (maze[rand_wall[0]-1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]-1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]-1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]-1, rand_wall[1]])\n", + "\n", + " # Leftmost cell\n", + " if (rand_wall[1] != 0):\n", + " if (maze[rand_wall[0]][rand_wall[1]-1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]-1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]-1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]-1])\n", + "\n", + " # Rightmost cell\n", + " if (rand_wall[1] != width-1):\n", + " if (maze[rand_wall[0]][rand_wall[1]+1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]+1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]+1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]+1])\n", + "\n", + " # Delete wall\n", + " for wall in walls:\n", + " if (wall[0] == rand_wall[0] and wall[1] == rand_wall[1]):\n", + " walls.remove(wall)\n", + "\n", + " continue\n", + "\n", + " # Check the bottom wall\n", + " if (rand_wall[0] != height-1):\n", + " if (maze[rand_wall[0]+1][rand_wall[1]] == \"u\" and maze[rand_wall[0]-1][rand_wall[1]] == \"c\"):\n", + "\n", + " s_cells = surroundingCells(rand_wall)\n", + " if (s_cells < 2):\n", + " # Denote the new path\n", + " maze[rand_wall[0]][rand_wall[1]] = \"c\"\n", + "\n", + " # Mark the new walls\n", + " if (rand_wall[0] != height-1):\n", + " if (maze[rand_wall[0]+1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]+1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]+1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]+1, rand_wall[1]])\n", + " if (rand_wall[1] != 0):\n", + " if (maze[rand_wall[0]][rand_wall[1]-1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]-1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]-1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]-1])\n", + " if (rand_wall[1] != width-1):\n", + " if (maze[rand_wall[0]][rand_wall[1]+1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]+1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]+1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]+1])\n", + "\n", + " # Delete wall\n", + " for wall in walls:\n", + " if (wall[0] == rand_wall[0] and wall[1] == rand_wall[1]):\n", + " walls.remove(wall)\n", + "\n", + " continue\n", + "\n", + " # Check the right wall\n", + " if (rand_wall[1] != width-1):\n", + " if (maze[rand_wall[0]][rand_wall[1]+1] == \"u\" and maze[rand_wall[0]][rand_wall[1]-1] == \"c\"):\n", + "\n", + " s_cells = surroundingCells(rand_wall)\n", + " if (s_cells < 2):\n", + " # Denote the new path\n", + " maze[rand_wall[0]][rand_wall[1]] = \"c\"\n", + "\n", + " # Mark the new walls\n", + " if (rand_wall[1] != width-1):\n", + " if (maze[rand_wall[0]][rand_wall[1]+1] != \"c\"):\n", + " maze[rand_wall[0]][rand_wall[1]+1] = \"w\"\n", + " if ([rand_wall[0], rand_wall[1]+1] not in walls):\n", + " walls.append([rand_wall[0], rand_wall[1]+1])\n", + " if (rand_wall[0] != height-1):\n", + " if (maze[rand_wall[0]+1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]+1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]+1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]+1, rand_wall[1]])\n", + " if (rand_wall[0] != 0): \n", + " if (maze[rand_wall[0]-1][rand_wall[1]] != \"c\"):\n", + " maze[rand_wall[0]-1][rand_wall[1]] = \"w\"\n", + " if ([rand_wall[0]-1, rand_wall[1]] not in walls):\n", + " walls.append([rand_wall[0]-1, rand_wall[1]])\n", + "\n", + " # Delete wall\n", + " for wall in walls:\n", + " if (wall[0] == rand_wall[0] and wall[1] == rand_wall[1]):\n", + " walls.remove(wall)\n", + "\n", + " continue\n", + "\n", + " # Delete the wall from the list anyway\n", + " for wall in walls:\n", + " if (wall[0] == rand_wall[0] and wall[1] == rand_wall[1]):\n", + " walls.remove(wall)\n", + " \n", + "# Mark the remaining unvisited cells as walls\n", + "for y in range(height):\n", + " for x in range(width):\n", + " if (maze[y][x] == \"u\"):\n", + " maze[y][x] = \"w\"\n", + "\n", + "# Set entrance and exit\n", + "for x in range(width):\n", + " if (maze[1][x] == \"c\"):\n", + " maze[0][x] = \"c\"\n", + " break\n", + "\n", + "for x in range(width-1, 0, -1):\n", + " if (maze[height-2][x] == \"c\"):\n", + " maze[height-1][x] = \"c\"\n", + " break\n", + "\n", + "# Print final maze\n", + "printMaze(maze)" + ] + }, + { + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/mazes-and-maps/map.html b/mazes-and-maps/map.html new file mode 100644 index 0000000..aa5497c --- /dev/null +++ b/mazes-and-maps/map.html @@ -0,0 +1,12 @@ + +
\ No newline at end of file diff --git a/mazes-and-maps/maps.ipynb b/mazes-and-maps/maps.ipynb new file mode 100644 index 0000000..4165448 --- /dev/null +++ b/mazes-and-maps/maps.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating maps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A*maze*ing maps with game assets\n", + "\n", + "Our journey begins here...\n", + "\n", + "https://www.kenney.nl/assets/cartography-pack" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "!wget \"https://www.kenney.nl/content/3-assets/26-cartography-pack/cartographypack.zip\"\n", + "!mkdir cartographypack\n", + "!unzip cartographypack.zip -d cartographypack" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!ls cartographypack/PNG/Default/path*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from glob import glob\n", + "import os\n", + "from IPython.display import display, HTML\n", + "\n", + "html = \"\"\n", + "\n", + "for img_path in glob(\"cartographypack/PNG/Default/path*\"):\n", + "\n", + " html += f''\n", + "\n", + "display(HTML(html))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from random import choice\n", + "\n", + "pieces = glob(\"cartographypack/PNG/Default/path*\")\n", + "html = \"\"\n", + "\n", + "for i in range(100):\n", + " piece = choice(pieces)\n", + " html += f''\n", + " \n", + "display(HTML(html))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stepping away from random.choice(): writing an algorithm to generate patterns" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to generate patterns in a non-random way, we might want to move around through our canvas in a **non-linear way**, to make the patterns a bit more complex.\n", + "\n", + "### moving through the canvas\n", + "\n", + "Each character on our \"canvas\" has a specific position and thus is connected to a `x` and `y` coordinate.\n", + "\n", + "How can we do that?\n", + "\n", + "We will use a `list-of-lists`... or in other words: \n", + "\n", + "we make **one big list**, that contains a # of **rows** (**the `y` axis, or *height* of the canvas**), with a # of **characters** (**the `x` axis, or *width* of the canvas**). \n", + "\n", + "To make this `list-of-lists`, we will use a `loop-in-a-loop`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "width = 10\n", + "height = 10\n", + "\n", + "canvas = []\n", + "\n", + "for y in range(height):\n", + " \n", + " row = []\n", + "\n", + " for x in range(width):\n", + " row.append(x)\n", + " \n", + " canvas.append(row)\n", + " \n", + "print(canvas)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's print the canvas row for row, to make it easier to see it as a x-y canvas:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for row in canvas:\n", + " print(row)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "And let's bring it back into an plain text pattern: turn this `list-of-lists` into a `multiline string`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# canvas is our list-of-lists\n", + "# canvas_string is the plain text version that we want to create\n", + "\n", + "canvas_string = ''\n", + "\n", + "for row in canvas:\n", + " row_string = ''\n", + " for character in row:\n", + " row_string += str(character)\n", + " canvas_string += row_string + \"\\n\"\n", + "\n", + "print(canvas_string)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's save this as a function that we can reuse later!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def plain(canvas):\n", + " canvas_string = ''\n", + " for row in canvas:\n", + " row_string = \"\".join(row)\n", + " canvas_string += row_string + \"\\n\"\n", + "\n", + " return canvas_string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can work with the `x` and `y` axes of the canvas, by *slicing* the `canvas`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "canvas[0][0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "canvas[1][9]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### My first algorithm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's write a short algorithm, to generate a map.\n", + "\n", + "We will start by writing the **rules** of our algorithm.\n", + "\n", + "Let's first think of these rules without writing them in code. \n", + "\n", + "How would you like to generate a pattern?\n", + "\n", + "For example: \n", + "\n", + "**Characters**\n", + "\n", + "* `.` is used as background\n", + "* `░` as light shade\n", + "* `▒` as darker shade\n", + "\n", + "**Rules** \n", + "\n", + "* `░` always appears in horizontal ánd vertical blocks of 3\n", + "\n", + "```\n", + ".....\n", + "..░..\n", + ".░░░.\n", + "..░..\n", + ".....\n", + "```\n", + "\n", + "* `▒` surrounds the blobs of light shade on the left side of each light shadow \n", + "\n", + "```\n", + ".....\n", + ".▒░..\n", + "▒░░░.\n", + ".▒░..\n", + ".....\n", + "```\n", + "\n", + "Let's try this!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we create a new canvas and fill it with `.`'s." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "width = 100\n", + "height = 25\n", + "\n", + "canvas = []\n", + "for y in range(height):\n", + " row = []\n", + " for x in range(width):\n", + " row.append('.')\n", + " canvas.append(row)\n", + "\n", + "print(plain(canvas))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's add the light shade..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from random import randrange\n", + "\n", + "light_shade = '░'\n", + "\n", + "for y in range(height):\n", + " for x in range(width):\n", + " \n", + " # To work with a degree of chance, \n", + " # we \"roll the dice\" and only add a ░\n", + " # when the number is lower then 5\n", + " random_number = randrange(0, 100, 1)\n", + " if random_number < 3: \n", + " \n", + " # If so, then we add a ░\n", + " canvas[y][x] = light_shade\n", + " \n", + " # Check is there is a character on the left, right, \n", + " # top and bottom AT ALL, before adding them...\n", + " if x - 1 >= 0:\n", + " canvas[y][x - 1] = light_shade\n", + " if x + 1 < width:\n", + " canvas[y][x + 1] = light_shade\n", + " if y - 1 >= 0:\n", + " canvas[y - 1][x] = light_shade\n", + " if y + 1 < height:\n", + " canvas[y + 1][x] = light_shade\n", + " \n", + " else:\n", + " continue\n", + " \n", + "print(plain(canvas))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's add the darker shade..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from random import randrange\n", + "\n", + "light_shade = '░'\n", + "darker_shade = '▒'\n", + "\n", + "for y in range(height):\n", + " for x in range(width):\n", + " \n", + " # First we check if the current character is a light shade\n", + " if canvas[y][x] == light_shade:\n", + " \n", + " # If that is the case, we need to look around, to see if we need to place a shade on the left, right, top or bottom\n", + " \n", + " # Check is there is a left character AT ALL\n", + " if x - 1 >= 0:\n", + " # If so, then we check if the left character is a '.'\n", + " if canvas[y][x - 1] == '.':\n", + " # If so, then we replace it with a dark shade\n", + " canvas[y][x - 1] = '▒'\n", + " \n", + " else:\n", + " continue\n", + " \n", + "print(plain(canvas))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Could we make a maze generator with the cartographypack now?\n", + "\n", + ":---)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/mazes-and-maps/maze-algorithm-on-paper.pdf b/mazes-and-maps/maze-algorithm-on-paper.pdf new file mode 100644 index 0000000..75aba22 Binary files /dev/null and b/mazes-and-maps/maze-algorithm-on-paper.pdf differ diff --git a/mazes-and-maps/maze-generator-on-paper.txt b/mazes-and-maps/maze-generator-on-paper.txt new file mode 100644 index 0000000..6b96213 --- /dev/null +++ b/mazes-and-maps/maze-generator-on-paper.txt @@ -0,0 +1,98 @@ + + _ _ _ _ __ __ _ _ _ ____ U ___ u __ __ ____ _ _ _____ _ _ ____ + |'| |'|U |"|u| |U|' \/ '|uU /"\ u | \ |"| U /"___| \/"_ \/U|' \/ '|uU| _"\ uU |"|u| ||_ " _| ___ | \ |"| U /"___|u +/| |_| |\\| |\| |\| |\/| |/ \/ _ \/ <| \| |> \| | u | | | |\| |\/| |/\| |_) |/ \| |\| | | | |_"_| <| \| |>\| | _ / +U| _ |u | |_| | | | | | / ___ \ U| |\ |u | |/__.-,_| |_| | | | | | | __/ | |_| | /| |\ | | U| |\ |u | |_| | + |_| |_| <<\___/ |_| |_| /_/ \_\ |_| \_| \____|\_)-\___/ |_| |_| |_| <<\___/ u |_|U U/| |\u |_| \_| \____| + // \\(__) )( <<,-,,-. \\ >> || \\,-. _// \\ \\ <<,-,,-. ||>>_ (__) )( _// \\_.-,_|___|_,-.|| \\,-._)(|_ +(_") ("_) (__) (./ \.) (__) (__)(_") (_/ (__)(__) (__) (./ \.) (__)__) (__)(__) (__)\_)-' '-(_/ (_") (_/(__)__) + + + + + . . . . . . . . . . . . . . . ╓ WALL LIST ╖ + ╟ ╢ + . . . . . . . . . . . . . . . ╟ ╢ + ╟ ╢ + . . . . . . . . . . . . . . . ╟ ╢ + ╟ ╢ + . . . . . . . . . . . . . . . ╟ ╢ + ╟ ╢ + . . . . . . . . . . . . . . . ╟ ╢ + ╟ ╢ + . . . . . . . . . . . . . . . ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╟ ╢ + ╔═══════════════════════════╗ ╟ ╢ + ║Randomized Prim's Algorithm║ ╟ ╢ + ╚═══════════════════════════╝ ╟ ╢ + ╟ ╢ + - Start with a grid full of walls. ╟ ╢ + ╟ ╢ + - Pick a cell, mark it as part of the maze. ╟ ╢ + Add the walls of the cell to the wall list. ╟ ╢ + ╟ ╢ + - While there are walls in the list: ╙ ╜ + + - Pick a random wall from the list. + If only one of the cells that the wall + divides is visited, then: + + - Make the wall a passage and mark + the unvisited cell as part of + the maze. + + - Add the neighboring walls of the + cell to the wall list. + + - Remove the wall from the list. + + + + + + + + + + + + + + + + + + + ,. ( . ) . " + (" ) )' ,' ) . (` '` + .; ) ' (( (" ) ;(, (( ( ;) " )" + _"., ,._'_.,)_(..,( . )_ _' )_') (. _..( '..jb + + + ASCII font "Dancing Font" http://patorjk.com/software/taag/ + + Randomized Prim's Algorithm from + https://en.wikipedia.org/wiki/Maze_generation_algorithm + + Based on Orestis Zekai's maze generator + https://medium.com/swlh/fun-with-python-1-maze-generator-931639b4fb7e + + ASCII fire by jb https://hopemoji.com/text-art-ascii/fire/ + + Made in the context of Special Issue 17: Productive Play + XPUB™ + + + + + diff --git a/patterns/tile1.png b/mazes-and-maps/tile1.png similarity index 100% rename from patterns/tile1.png rename to mazes-and-maps/tile1.png diff --git a/patterns/tile2.png b/mazes-and-maps/tile2.png similarity index 100% rename from patterns/tile2.png rename to mazes-and-maps/tile2.png diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/STYLE.nfo b/patterns/C64_TrueType_v1.2.1-STYLE/STYLE.nfo deleted file mode 100644 index 9aa033a..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/STYLE.nfo +++ /dev/null @@ -1,129 +0,0 @@ - - - ۰ ۱ - ۲ - ۲ - ۲ ۲ - ۱ ۲ - ۱ ۲ - ۰ ۲ - ۲ - ۲ - ۱ - ۲ ۱ - ۱ - ۰ - - - - - ۲ - ۱ - ۱ - ۰ - - - ۲ - ۲ - ۱ - ۰ - - - - - ۲ - ۲ - ۲ - - ۰ ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۲ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - ۰ ۰ ۰ ۰ ۰ - - - title: C64 TrueType v1.2.1 type: fonts - date: April 15, 2019 platform: Any OS/web - - - - >> What the hell is it? - - Our C64 TrueType fonts provide monospace and - variable pitch versions of the legendary C64 - character set. For programmers, each font contains - Unicode mappings to accomodate either a direct - PETSCII mapping or a screencode mapping. For users, - the fonts map to some obvious code points (like the - Unicode box drawing range) and should also support - easy mapping from applicable code points in cp437 - and cp1252. Our goal is to provide all 304 necessary - glyphs in the C64 character set in as small a file - as possible while still being programmer-friendly. - Finally, six additional glyphs are included to round - out the US-ASCII table with \, ^, `, {, }, and ~ for - the sake of providing a usable PETSCII experience - in code editors/IDEs. - - This update corrects some bounding box issues as - reported in the updated Microsoft Font Validator, - left side bearing on one glyph, and updates some - PS names. - - This update also adds a 'proper' OpenType format - (.otf) with CFF outlines. All files should be - smaller than the previous release. SVG format - has been dropped. - - "C64 Pro Mono" is the fixed pitch while "C64 Pro" - is a variable pitch (propertional) version. In the - legacy folder you can also find "C64 Elite Mono" - which was used in DirMaster v2.x - we don't - recommend using it for anything else other than - if you need it for running an older version of - DirMaster. The "C64 Pro Mono" in this release is - the same as what ships with DirMaster v3.1.2 but - will work with any older 3.x version of DirMaster. - - - >> What does the future hold? - - The Unicode Consortium (or acolytes thereof) - recently tackled the issue of missing legacy - computing character sets. The first attempt - has omitted several of the C64's vertical and - horizontal 'quarter-bar' characters. Pending - the final outcome we'll add whatever new - mappings that are relevant to the C64 when - the next Unicode update drops. - - - >> Previous releases: - - v1.0 - Oct 1, 2010 - v1.2 - Sep 2, 2014 - - - >> For more information: - - http://style64.org/c64-truetype - - http://style64.org/c64-truetype/license - - http://style64.org/petscii - - - - Keep scene spirit alive! - diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/file_id.diz b/patterns/C64_TrueType_v1.2.1-STYLE/file_id.diz deleted file mode 100644 index df67707..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/file_id.diz +++ /dev/null @@ -1,16 +0,0 @@ - - - C64 TrueType v1.2.1/Style - - - ۲ - ۱ ܰ release type: - ۰ ߰ fonts - ۲ - ۲ for platform: - ۱ Any OS/web - ۰ - released on: - 2019-04-15 - - [01/01] diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.eot b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.eot deleted file mode 100644 index 3124016..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.eot and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.otf b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.otf deleted file mode 100644 index f1e4dfe..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.otf and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.ttf b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.ttf deleted file mode 100644 index a6c30a6..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.ttf and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff deleted file mode 100644 index c711dd8..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff2 b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff2 deleted file mode 100644 index 1d0a8d6..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro-STYLE.woff2 and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.eot b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.eot deleted file mode 100644 index b671904..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.eot and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.otf b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.otf deleted file mode 100644 index b96258c..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.otf and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.ttf b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.ttf deleted file mode 100644 index 02ff5fc..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.ttf and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff deleted file mode 100644 index 60347be..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff2 b/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff2 deleted file mode 100644 index a1b72c5..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/fonts/C64_Pro_Mono-STYLE.woff2 and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/legacy_fonts/C64_Elite_Mono_v1.0-STYLE.ttf b/patterns/C64_TrueType_v1.2.1-STYLE/legacy_fonts/C64_Elite_Mono_v1.0-STYLE.ttf deleted file mode 100644 index 3cdc289..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/legacy_fonts/C64_Elite_Mono_v1.0-STYLE.ttf and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/license.txt b/patterns/C64_TrueType_v1.2.1-STYLE/license.txt deleted file mode 100644 index e8ab319..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/license.txt +++ /dev/null @@ -1,8 +0,0 @@ - -Fonts in this package are (c) 2010-2019 Style. - -This license is applicable to each font file included in this package in all their variants (ttf, otf, eot, woff, woff2, svg). - -You MAY NOT: sell this font; include/redistribute the font in any font collection regardless of pricing; provide the font for direct download from any web site, modify or rename the font. You MAY: link to "http://style64.org/c64-truetype" in order for others to download and install the font; embed the font (without any modification or file renaming) for display on any web site using @font-face rules; use this font in static images and vector art; include this font (without any modification or file renaming) as part of a software package but ONLY if said software package is freely provided to end users. You may also contact us to negotiate a (possibly commercial) license for your use outside of these guidelines at "http://style64.org/contact-style". - -At all times the most recent version of this license can be found at "http://style64.org/c64-truetype/license". diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/screenshot.png b/patterns/C64_TrueType_v1.2.1-STYLE/screenshot.png deleted file mode 100644 index dcec67f..0000000 Binary files a/patterns/C64_TrueType_v1.2.1-STYLE/screenshot.png and /dev/null differ diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-eot.html b/patterns/C64_TrueType_v1.2.1-STYLE/test/test-eot.html deleted file mode 100644 index d5a81c4..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-eot.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - C64 Pro Mono: EOT (Embedded OpenType) test - - - - - -
- -
- See: http://caniuse.com/#feat=eot -

If you do not see the font, you may be using a browser that disallows local font loading due to CORS (probably Firefox or IE).

-
- -
-
- -
- “C64 Pro Mono/Style”
-    upper/graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
- -
- “C64 Pro Mono/Style”
-    lower/upper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
-
- - - - - diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-otf.html b/patterns/C64_TrueType_v1.2.1-STYLE/test/test-otf.html deleted file mode 100644 index 5e571b0..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-otf.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - C64 Pro Mono: OTF (OpenType) test - - - - - -
- -
- See: http://caniuse.com/#feat=otf -

If you do not see the font, you may be using a browser that disallows local font loading due to CORS (probably Firefox or IE).

-
- -
-
- -
- “C64 Pro Mono/Style”
-    upper/graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
- -
- “C64 Pro Mono/Style”
-    lower/upper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
-
- - - - - diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-ttf.html b/patterns/C64_TrueType_v1.2.1-STYLE/test/test-ttf.html deleted file mode 100644 index ef2666d..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-ttf.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - C64 Pro Mono: TTF (TrueType) test - - - - - -
- -
- See: http://caniuse.com/#feat=ttf -

If you do not see the font, you may be using a browser that disallows local font loading due to CORS (probably Firefox or IE).

-
- -
-
- -
- “C64 Pro Mono/Style”
-    upper/graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
- -
- “C64 Pro Mono/Style”
-    lower/upper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
-
- - - - diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff.html b/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff.html deleted file mode 100644 index 0451af0..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - C64 Pro Mono: WOFF (Web Open Font Format) test - - - - - -
- -
- See: http://caniuse.com/#feat=woff -

If you do not see the font, you may be using a browser that disallows local font loading due to CORS (probably Firefox or IE).

-
- -
-
- -
- “C64 Pro Mono/Style”
-    upper/graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
- -
- “C64 Pro Mono/Style”
-    lower/upper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
-
- - - - - diff --git a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff2.html b/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff2.html deleted file mode 100644 index f9bd457..0000000 --- a/patterns/C64_TrueType_v1.2.1-STYLE/test/test-woff2.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - C64 Pro Mono: WOFF2 (Web Open Font Format 2.0) test - - - - - -
- -
- See: http://caniuse.com/#feat=woff2 -

If you do not see the font, you may be using a browser that disallows local font loading due to CORS (probably Firefox or IE).

-
- -
-
- -
- “C64 Pro Mono/Style”
-    upper/graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
- -
- “C64 Pro Mono/Style”
-    lower/upper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -




-
-
- - - - - diff --git a/patterns/bits-ascii-unicode.ipynb b/patterns/bits-ascii-unicode.ipynb deleted file mode 100644 index 988213c..0000000 --- a/patterns/bits-ascii-unicode.ipynb +++ /dev/null @@ -1,149 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# *bits*, *ASCII*, *Unicode*" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Encoding systems\n", - "\n", - "As a computer can only work with numbers, it cannot process of letters text directly. In order to work with text, textual characters need to be translated into numbers and vice versa. This is done via the process of text encodings.\n", - "\n", - "It might be your first reaction to think that this shouldn’t be so difficult. We could represent the letter in binary code. An a encoded as a 0, b as a 1 and c as a 01 etc. And in fact this is more or less how text encodings work. However, at the time when computing was being developed different encodings emerged.\n", - "\n", - "## ASCII encoding\n", - "\n", - "The dominant encoding at the time became ASCII (for American Standard Code for Information Interchange.), which was created on behalf of the U.S. Government in 1963 to allow for information interchange between their different computing systems.\n", - "\n", - "The encoding uses a 7-bit system, which means that they could only store characters in 128 (2^7=128) numbers (0000 0000 until 0111 1111). The resulting encoding schema assigned to each of these 128 numbers:\n", - "\n", - " all the letters in the English alphabet\n", - " numbers from 0-9\n", - " punctuation marks\n", - " and control characters\n", - "\n", - "Thanks to the simplicity of the encoding it quickly became a standard for the American computing industry.\n", - "\n", - "## ASCII imperialism\n", - "\n", - "Thanks to the power of the US Military and US corporations the American computing industry became the global computing industry. Computers that we use today are rooted in American networking history, and so is the ASCII standard. However, the reality is that ASCII can only represent 26 Latin letters in the English alphabet but computers are used all over the world, by people speaking different languages. They would often end up with American computers that could not represent their language in ASCII. Think for example of scripts like Greek, Cyrillic and Arabic or even Latin scripts that use accents such as the ü or ø. Altough 128 might sound like a lot of characters, it is not enough to represent all different languages." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ASCII flavours: PETSCII\n", - "\n", - "### Commodore 64 (1982)\n", - "\n", - "![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Commodore-64-Computer-FL.jpg/320px-Commodore-64-Computer-FL.jpg)\n", - "\n", - "> The Commodore 64, also known as the C64 or the CBM 64, is an 8-bit home computer introduced in January 1982 by Commodore International (first shown at the Consumer Electronics Show, January 7–10, 1982, in Las Vegas). It has been listed in the Guinness World Records as the highest-selling single computer model of all time, with independent estimates placing the number sold between 12.5 and 17 million units. \n", - "\n", - "> Preceded by the Commodore VIC-20 and Commodore PET, the C64 took its name from its 64 kilobytes (65,536 bytes) of RAM. With support for multicolor sprites and a custom chip for waveform generation, the C64 could create superior visuals and audio compared to systems without such custom hardware. \n", - "\n", - "https://en.wikipedia.org/wiki/Commodore_64\n", - "\n", - "> Part of the Commodore 64's success was its sale in regular retail stores instead of only electronics or computer hobbyist specialty stores. Commodore produced many of its parts in-house to control costs, including custom integrated circuit chips from MOS Technology. In the United States, it has been compared to the Ford Model T automobile for its role in bringing a new technology to middle-class households via creative and affordable mass-production.\n", - "\n", - "Kahney, Leander (September 9, 2003). \"Grandiose Price for a Modest PC\". CondéNet, Inc. Archived from the original on September 14, 2008. Retrieved September 13, 2008.\n", - "\n", - "![](https://upload.wikimedia.org/wikipedia/commons/4/48/C64_startup_animiert.gif)\n", - "\n", - "### PETSCII \n", - "\n", - "![](https://www.pagetable.com/docs/c64ref_charset/colorscheme.gif)\n", - "\n", - "> The Commodore PET's lack of a programmable bitmap-mode for computer graphics, as well as it having no redefinable character set capability, may be one of the reasons PETSCII was developed; by creatively using the well-thought-out block graphics, a higher degree of sophistication in screen graphics is attainable than by using plain ASCII's letter/digit/punctuation characters. In addition to the relatively diverse set of geometrical shapes that can thus be produced, PETSCII allows for several grayscale levels by its provision of differently hatched checkerboard squares/half-squares. Finally, the reverse-video mode (see below) is used to complete the range of graphics characters, in that it provides mirrored half-square blocks. \n", - "\n", - "https://en.wikipedia.org/wiki/PETSCII\n", - "\n", - "Draw PETSCII art in the browser:\n", - "\n", - "* https://petscii.krissz.hu/\n", - "* https://www.masswerk.at/pet/\n", - "\n", - "Use PETSCII as a font!\n", - "\n", - "* https://style64.org/c64-truetype\n", - "\n", - "PETSCII bots!\n", - "\n", - "* https://twitter.com/PETSCIIBOTS" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Unicode universalism\n", - "\n", - "’As electronic text was increasingly being exchanged online and between language areas, issues emerged when text encoded in one language was shared and read on systems assuming an encoding in another language. Unicode was a response to the incompatible text encoding standards that were proliferating.\n", - "\n", - "When different encodings assign the same binary numbers to different characters, this results in illegible documents. The solution, partly made possible by increased computing capacity, was to strive for a single universal encoding which would encompass all writing systems’ 6\n", - "\n", - "You can experience this following this exercise.\n", - "\n", - "So in order to overcome the limitations of ASCII people created the Unicode Consortium to create a single universal character encoding:\n", - "\n", - "‘The Unicode standards are designed to normalise the encoding of characters, to efficiently manage the way they are stored, referred to and displayed in order to facilitate cross-platform, multilingual and international text exchange. The Unicode Standard is mammoth in\n", - "size and covers well over 110,000 characters, of which [..] 1,000 are [..] emoji.’ 7\n", - "\n", - "In effect the Unicode Standard combined all the different national character encodings together into a single large ledger in order to try to represent all languages.\n", - "\n", - "It is divided in so called blocks, which are basically number tables that describe which number is connected to which character.\n", - "\n", - "The table starts counting at 0x0 and continues all the way up to 0x10FFFF.\n", - "\n", - "The first block actually corresponds with ASCII:\n", - "\n", - "https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF\n", - "\n", - "It contains many different scripts for supporting large and smaller language groups, including for example Ethiopian and Cherokee:\n", - "\n", - "https://en.wikibooks.org/wiki/Unicode/Character_reference/1000-1FFF\n", - "\n", - "However there are also blocks that describe Arrows and other symbols:\n", - "\n", - "https://en.wikibooks.org/wiki/Unicode/Character_reference/2000-2FFF\n", - "\n", - "Emoji are also part of the unicode table." - ] - }, - { - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/patterns/generating-maps.ipynb b/patterns/generating-maps.ipynb deleted file mode 100644 index fbbe405..0000000 --- a/patterns/generating-maps.ipynb +++ /dev/null @@ -1,652 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generating maps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Stepping away from random.choice(): writing an algorithm to create ASCII tile maps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to generate patterns in a non-random way, we might want to move around through our canvas in a **non-linear way**, to make the patterns a bit more complex.\n", - "\n", - "### moving through the canvas\n", - "\n", - "Each character on our \"canvas\" has a specific position and thus is connected to a `x` and `y` coordinate.\n", - "\n", - "How can we do that?\n", - "\n", - "We will use a `list-of-lists`... or in other words: \n", - "\n", - "we make **one big list**, that contains a # of **rows** (**the `y` axis, or *height* of the canvas**), with a # of **characters** (**the `x` axis, or *width* of the canvas**). \n", - "\n", - "To make this `list-of-lists`, we will use a `loop-in-a-loop`:" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]\n" - ] - } - ], - "source": [ - "width = 10\n", - "height = 10\n", - "\n", - "canvas = []\n", - "\n", - "for y in range(height):\n", - " \n", - " row = []\n", - "\n", - " for x in range(width):\n", - " row.append(x)\n", - " \n", - " canvas.append(row)\n", - " \n", - "print(canvas)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's print the canvas row for row, to make it easier to see it as a x-y canvas:" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" - ] - } - ], - "source": [ - "for row in canvas:\n", - " print(row)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "And let's bring it back into an plain text pattern: turn this `list-of-lists` into a `multiline string`:" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "0123456789\n", - "\n" - ] - } - ], - "source": [ - "# canvas is our list-of-lists\n", - "# canvas_string is the plain text version that we want to create\n", - "\n", - "canvas_string = ''\n", - "\n", - "for row in canvas:\n", - " row_string = ''\n", - " for character in row:\n", - " row_string += str(character)\n", - " canvas_string += row_string + \"\\n\"\n", - "\n", - "print(canvas_string)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's save this as a function that we can reuse later!" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [], - "source": [ - "def plain(canvas):\n", - " canvas_string = ''\n", - " for row in canvas:\n", - " row_string = \"\".join(row)\n", - " canvas_string += row_string + \"\\n\"\n", - "\n", - " return canvas_string" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we can work with the `x` and `y` axes of the canvas, by *slicing* the `canvas`:" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 76, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "canvas[0][0]" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "9" - ] - }, - "execution_count": 77, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "canvas[1][9]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### My first algorithm" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's write a short algorithm, to generate a map.\n", - "\n", - "We will start by writing the **rules** of our algorithm.\n", - "\n", - "Let's first think of these rules without writing them in code. \n", - "\n", - "How would you like to generate a pattern?\n", - "\n", - "For example: \n", - "\n", - "**Characters**\n", - "\n", - "* `.` is used as background\n", - "* `░` as light shade\n", - "* `▒` as darker shade\n", - "\n", - "**Rules** \n", - "\n", - "* `░` always appears in horizontal ánd vertical blocks of 3\n", - "\n", - "```\n", - ".....\n", - "..░..\n", - ".░░░.\n", - "..░..\n", - ".....\n", - "```\n", - "\n", - "* `▒` surrounds the blobs of light shade on the left side of each light shadow \n", - "\n", - "```\n", - ".....\n", - ".▒░..\n", - "▒░░░.\n", - ".▒░..\n", - ".....\n", - "```\n", - "\n", - "Let's try this!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we create a new canvas and fill it with `.`'s." - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "....................................................................................................\n", - "\n" - ] - } - ], - "source": [ - "width = 100\n", - "height = 25\n", - "\n", - "canvas = []\n", - "for y in range(height):\n", - " row = []\n", - " for x in range(width):\n", - " row.append('.')\n", - " canvas.append(row)\n", - "\n", - "print(plain(canvas))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's add the light shade..." - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "░.░.................░..........░............................░.........░░░.........░.................\n", - "░░░░...............░░░........░░░..........................░░░..░......░.......░.░░░................\n", - "░.░.......░.........░..........░...........░................░..░░░............░░░.░.................\n", - ".........░░░........░.....................░░░..░................░..............░.............░......\n", - "..........░........░░░.....................░..░░░.............................░.............░░░.....\n", - "...................░░░....░....................░.............................░░░.............░......\n", - "............░.......░....░░░.................░..░..............░...░.........░░░....................\n", - "...░.......░░░............░.....░...........░░░░░░............░░░.░░░.........░.........░...........\n", - "..░░░...░.░.░.......░..........░░░...........░..░....░....░....░...░....░..............░░░..........\n", - "...░...░░░░░.......░░░..........░...................░░░..░░░...........░░░..............░...........\n", - "........░░░░........░░░.......░.....................░░░...░.............░............░.░░░..........\n", - ".......░░░░░.........░.......░░░....░................░..░...........................░░░.░...........\n", - "........░.░░.................░░░...░░░..░...░..........░░░........░................░░░..........░...\n", - ".....░....░░░.............░...░.....░..░░░.░░░..........░......░.░░░................░..........░░░..\n", - "....░░░....░.............░░░............░.░.░............░....░░░.░......░.░....................░...\n", - "....░░......░.............░...░.....░....░░░............░░░....░░.......░░░░░.......................\n", - "...░░░.....░░░.........░..░..░░░...░░░....░..............░.....░░░.......░.░........................\n", - "....░.......░.........░░░░░░..░.....░....................░......░........░..........................\n", - ".......................░..░..░..........................░░░░.░..........░░░.................░.......\n", - "............................░░░░.........................░░░░░░..........░.................░░░.....░\n", - "....................░........░░░░..........................░.░..............................░.....░░\n", - ".....░......░......░░░.........░..................................................................░░\n", - "..░.░░░....░░░░.....░...........................................░...............................░..░\n", - ".░░░.░.....░░░░░...................░...........................░░░.............................░░░..\n", - "..░░░.......░░░░..................░░░...........................░...............................░...\n", - "\n" - ] - } - ], - "source": [ - "from random import randrange\n", - "\n", - "light_shade = '░'\n", - "\n", - "for y in range(height):\n", - " for x in range(width):\n", - " \n", - " # To work with a degree of chance, \n", - " # we \"roll the dice\" and only add a ░\n", - " # when the number is lower then 5\n", - " random_number = randrange(0, 100, 1)\n", - " if random_number < 3: \n", - " \n", - " # If so, then we add a ░\n", - " canvas[y][x] = light_shade\n", - " \n", - " # Check is there is a character on the left, right, \n", - " # top and bottom AT ALL, before adding them...\n", - " if x - 1 >= 0:\n", - " canvas[y][x - 1] = light_shade\n", - " if x + 1 < width:\n", - " canvas[y][x + 1] = light_shade\n", - " if y - 1 >= 0:\n", - " canvas[y - 1][x] = light_shade\n", - " if y + 1 < height:\n", - " canvas[y + 1][x] = light_shade\n", - " \n", - " else:\n", - " continue\n", - " \n", - "print(plain(canvas))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's add the darker shade..." - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "░▒░................▒░.........▒░...........................▒░........▒░░░........▒░.................\n", - "░░░░..............▒░░░.......▒░░░.........................▒░░░.▒░.....▒░......▒░▒░░░................\n", - "░▒░......▒░........▒░.........▒░..........▒░...............▒░.▒░░░...........▒░░░▒░.................\n", - "........▒░░░.......▒░....................▒░░░.▒░...............▒░.............▒░............▒░......\n", - ".........▒░.......▒░░░....................▒░.▒░░░............................▒░............▒░░░.....\n", - "..................▒░░░...▒░...................▒░............................▒░░░............▒░......\n", - "...........▒░......▒░...▒░░░................▒░.▒░.............▒░..▒░........▒░░░....................\n", - "..▒░......▒░░░...........▒░....▒░..........▒░░░░░░...........▒░░░▒░░░........▒░........▒░...........\n", - ".▒░░░..▒░▒░▒░......▒░.........▒░░░..........▒░.▒░...▒░...▒░...▒░..▒░...▒░.............▒░░░..........\n", - "..▒░..▒░░░░░......▒░░░.........▒░..................▒░░░.▒░░░..........▒░░░.............▒░...........\n", - ".......▒░░░░.......▒░░░......▒░....................▒░░░..▒░............▒░...........▒░▒░░░..........\n", - "......▒░░░░░........▒░......▒░░░...▒░...............▒░.▒░..........................▒░░░▒░...........\n", - ".......▒░▒░░................▒░░░..▒░░░.▒░..▒░.........▒░░░.......▒░...............▒░░░.........▒░...\n", - "....▒░...▒░░░............▒░..▒░....▒░.▒░░░▒░░░.........▒░.....▒░▒░░░...............▒░.........▒░░░..\n", - "...▒░░░...▒░............▒░░░...........▒░▒░▒░...........▒░...▒░░░▒░.....▒░▒░...................▒░...\n", - "...▒░░.....▒░............▒░..▒░....▒░...▒░░░...........▒░░░...▒░░......▒░░░░░.......................\n", - "..▒░░░....▒░░░........▒░.▒░.▒░░░..▒░░░...▒░.............▒░....▒░░░......▒░▒░........................\n", - "...▒░......▒░........▒░░░░░░.▒░....▒░...................▒░.....▒░.......▒░..........................\n", - "......................▒░.▒░.▒░.........................▒░░░░▒░.........▒░░░................▒░.......\n", - "...........................▒░░░░........................▒░░░░░░.........▒░................▒░░░....▒░\n", - "...................▒░.......▒░░░░.........................▒░▒░.............................▒░....▒░░\n", - "....▒░.....▒░.....▒░░░........▒░.................................................................▒░░\n", - ".▒░▒░░░...▒░░░░....▒░..........................................▒░..............................▒░.▒░\n", - "▒░░░▒░....▒░░░░░..................▒░..........................▒░░░............................▒░░░..\n", - ".▒░░░......▒░░░░.................▒░░░..........................▒░..............................▒░...\n", - "\n" - ] - } - ], - "source": [ - "from random import randrange\n", - "\n", - "light_shade = '░'\n", - "darker_shade = '▒'\n", - "\n", - "for y in range(height):\n", - " for x in range(width):\n", - " \n", - " # First we check if the current character is a light shade\n", - " if canvas[y][x] == light_shade:\n", - " \n", - " # If that is the case, we need to look around, to see if we need to place a shade on the left, right, top or bottom\n", - " \n", - " # Check is there is a left character AT ALL\n", - " if x - 1 >= 0:\n", - " # If so, then we check if the left character is a '.'\n", - " if canvas[y][x - 1] == '.':\n", - " # If so, then we replace it with a dark shade\n", - " canvas[y][x - 1] = '▒'\n", - " \n", - " else:\n", - " continue\n", - " \n", - "print(plain(canvas))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Make your own tiles! " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Instead of ASCII characters, you could also replace each character with your own tiny png tiles!\n", - "\n", - "If we turn the generated ASCII into HTML, we can replace the ` ` (space) and `.` characters into images.\n", - "\n", - "Let's start with two small tiles. The example below is based on two world tiles from this tileset: https://opengameart.org/content/pixel-world-hex-tileset\n", - "\n", - "![](tile1.png) `tile1.png`\n", - "\n", - "and\n", - "\n", - "![](tile2.png) `tile2.png`" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": { - "scrolled": true, - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "
\n" - ] - } - ], - "source": [ - "from random import choice\n", - "\n", - "tiles = ['tile1.png', 'tile2.png']\n", - "width = 50\n", - "height = 25\n", - "\n", - "html = ''\n", - "\n", - "css = '''\n", - "'''\n", - "\n", - "html += css\n", - "\n", - "for y in range(height):\n", - " html += '
'\n", - " for x in range(width):\n", - " tile = choice(tiles)\n", - " tile_html = f''\n", - " html += tile_html\n", - " html += '
'\n", - "\n", - "print(html)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use a feature of the Notebooks to preview this HTML here:" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.core.display import display, HTML\n", - "\n", - "display(HTML(html))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or save it to a file:" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [], - "source": [ - "with open('map.html', 'w+') as out:\n", - " out.write(html)" - ] - }, - { - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/patterns/generating-mini-games.ipynb b/patterns/generating-mini-games.ipynb deleted file mode 100644 index 00b4560..0000000 --- a/patterns/generating-mini-games.ipynb +++ /dev/null @@ -1,158 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generating mini-games with random.choice()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - ". . . . .. . . .. \n", - " . . . . . . . . . . . \n", - " . . . .. .. . . .\n", - " . . . . . . . . \n", - " . . . . . . . . . . \n", - " . . . . . . . . . \n", - " . . . . . . .. \n", - " . . . .. . . . . .. . .. \n", - " . . . . . . . .. . \n", - ". . . . . . . . .. . \n", - ". . . .. . . \n", - " . . . . . . . .. . \n", - " . . . . . \n", - " . . . . . . . \n", - " . . . . . . . .\n", - ". . . .. . . . . . \n", - " .. . . . . \n", - " . . . . . . . . . . . \n", - " . . . . . . . .. \n", - " . . . . . \n", - " . . . . . . . . . . . . \n", - " . . . . . . . . . . . \n", - " . . . . . . . . . . \n", - " . . . . . . . . . \n", - " . . . . . . . . . \n" - ] - } - ], - "source": [ - "from random import choice\n", - "\n", - "characters = ['.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']\n", - "width = 100\n", - "height = 25\n", - "\n", - "for y in range(height):\n", - " for x in range(width):\n", - " print(choice(characters), end='')\n", - " print('')" - ] - }, - { - "cell_type": "code", - "execution_count": 130, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " a o it m i i m f c \n", - " c i ag n o amf f o i \n", - " o i o f i a g af i g\n", - " m i f a t g c f t i\n", - " n o f a f tnf o f \n", - " a i i i i i t in c caa \n", - " t fa n f i t a i o\n", - " o i ag ig g g a i i i n ag \n", - " n m gt a i o f i o ni i i \n", - " m i f i a a a o i m a g c \n", - " f am a c o i f cna f mi\n", - " t a i c f g f n i c o o g \n", - " o f t a g ng i a i a n n o a t oi i it\n", - " o t n o m f g a i a m ni \n", - " f i i g m o i a n t a i a a m i a i a\n", - "i a a ac i a t i tn t a \n", - " o f tf i an i n o f i t t \n", - " c g fg i o o ca i o o o m t \n", - " f o i i i c i ta i ca c f \n", - " c n aa g i m g m i c \n", - " c i c i f i n m f i i \n", - " a o i g m o ot a i a c f m i \n", - " i a a i f f a c g i\n", - " to in a t og im i o i f n c \n", - "ao m g ii c n a to t \n" - ] - } - ], - "source": [ - "from random import choice\n", - "\n", - "character_set = 'gamification '\n", - "characters = [character for character in character_set]\n", - "width = 100\n", - "height = 25\n", - "\n", - "for y in range(height):\n", - " for x in range(width):\n", - " print(choice(characters), end='')\n", - " print('')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# More games plz!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Try to make some more mini-games yourself.\n", - "\n", - "You can restrict yourself to using **ASCII characters only** (see https://en.wikipedia.org/wiki/ASCII) and stay in touch with early computer graphics ASCII art...\n", - "\n", - "Or you can extend your pallete with **Unicode characters**. This is a nice website that highlights specific character sets: http://xahlee.info/comp/unicode_index.html" - ] - }, - { - "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.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/patterns/labyrinths.ipynb b/puzzles/crossword.ipynb similarity index 74% rename from patterns/labyrinths.ipynb rename to puzzles/crossword.ipynb index 7c36d42..7ceec77 100644 --- a/patterns/labyrinths.ipynb +++ b/puzzles/crossword.ipynb @@ -4,22 +4,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Labyrithns" + "# Generating crossword puzzles" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "https://en.wikipedia.org/wiki/Maze_generation_algorithm" + "![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/CrosswordUSA.svg/480px-CrosswordUSA.svg.png)\n", + "\n", + "https://github.com/akhof/pyCrossword" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/puzzles/crossword.py b/puzzles/crossword.py new file mode 100644 index 0000000..26c23f0 --- /dev/null +++ b/puzzles/crossword.py @@ -0,0 +1,313 @@ +# make_wordsearch.py +import os +import sys +import random +from copy import deepcopy + +# Maximum number of rows and columns. +NMAX = 32 +alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +def circle_mask(grid): + """A circular mask to shape the grid.""" + r2 = min(ncols, nrows)**2 // 4 + cx, cy = ncols//2, nrows // 2 + for irow in range(nrows): + for icol in range(ncols): + if (irow - cy)**2 + (icol - cx)**2 > r2: + grid[irow][icol] = '*' + +def squares_mask(grid): + """A mask of overlapping squares to shape the grid.""" + a = int(0.38 * min(ncols, nrows)) + cy = nrows // 2 + cx = ncols // 2 + for irow in range(nrows): + for icol in range(ncols): + if a <= icol < ncols-a: + if irow < cy-a or irow > cy+a: + grid[irow][icol] = '*' + if a <= irow < nrows-a: + if icol < cx-a or icol > cx+a: + grid[irow][icol] = '*' + +def no_mask(grid): + """The default, no mask.""" + pass + +# A dictionary of masking functions, keyed by their name. +apply_mask = { + None: no_mask, + 'circle': circle_mask, + 'squares': squares_mask, + } + +def make_grid(mask=None): + """Make the grid and apply a mask (locations a letter cannot be placed).""" + grid = [[' ']*ncols for _ in range(nrows)] + apply_mask[mask](grid) + return grid + +def _make_wordsearch(nrows, ncols, wordlist, allow_backwards_words=True, + mask=None): + """Attempt to make a word search with the given parameters.""" + + grid = make_grid(mask) + + def fill_grid_randomly(grid): + """Fill up the empty, unmasked positions with random letters.""" + for irow in range(nrows): + for icol in range(ncols): + if grid[irow][icol] == ' ': + grid[irow][icol] = random.choice(alphabet) + + def remove_mask(grid): + """Remove the mask, for text output, by replacing with whitespace.""" + for irow in range(nrows): + for icol in range(ncols): + if grid[irow][icol] == '*': + grid[irow][icol] = ' ' + + + def test_candidate(irow, icol, dx, dy, word): + """Test the candidate location (icol, irow) for word in orientation + dx, dy).""" + for j in range(len(word)): + if grid[irow][icol] not in (' ', word[j]): + return False + irow += dy + icol += dx + return True + + def place_word(word): + """Place word randomly in the grid and return True, if possible.""" + + # Left, down, and the diagonals. + dxdy_choices = [(0,1), (1,0), (1,1), (1,-1)] + random.shuffle(dxdy_choices) + for (dx, dy) in dxdy_choices: + if allow_backwards_words and random.choice([True, False]): + # If backwards words are allowed, simply reverse word. + word = word[::-1] + # Work out the minimum and maximum column and row indexes, given + # the word length. + n = len(word) + colmin = 0 + colmax = ncols - n if dx else ncols - 1 + rowmin = 0 if dy >= 0 else n - 1 + rowmax = nrows - n if dy >= 0 else nrows - 1 + if colmax - colmin < 0 or rowmax - rowmin < 0: + # No possible place for the word in this orientation. + continue + # Build a list of candidate locations for the word. + candidates = [] + for irow in range(rowmin, rowmax+1): + for icol in range(colmin, colmax+1): + if test_candidate(irow, icol, dx, dy, word): + candidates.append((irow, icol)) + # If we don't have any candidates, try the next orientation. + if not candidates: + continue + # Pick a random candidate location and place the word in this + # orientation. + loc = irow, icol = random.choice(candidates) + for j in range(n): + grid[irow][icol] = word[j] + irow += dy + icol += dx + # We're done: no need to try any more orientations. + break + else: + # If we're here, it's because we tried all orientations but + # couldn't find anywhere to place the word. Oh dear. + return False + print(word, loc, (dx, dy)) + return True + + # Iterate over the word list and try to place each word (without spaces). + for word in wordlist: + word = word.replace(' ', '') + if not place_word(word): + # We failed to place word, so bail. + return None, None + + # grid is a list of lists, so we need to deepcopy here for an independent + # copy to keep as the solution (without random letters in unfilled spots). + solution = deepcopy(grid) + fill_grid_randomly(grid) + remove_mask(grid) + remove_mask(solution) + + return grid, solution + + +def make_wordsearch(*args, **kwargs): + """Make a word search, attempting to fit words into the specified grid.""" + + # We try NATTEMPTS times (with random orientations) before giving up. + NATTEMPTS = 10 + for i in range(NATTEMPTS): + grid, solution = _make_wordsearch(*args, **kwargs) + if grid: + print('Fitted the words in {} attempt(s)'.format(i+1)) + return grid, solution + print('I failed to place all the words after {} attempts.' + .format(NATTEMPTS)) + return None, None + + +def show_grid_text(grid): + """Output a text version of the filled grid wordsearch.""" + for irow in range(nrows): + print(' '.join(grid[irow])) + +def show_wordlist_text(wordlist): + """Output a text version of the list of the words to find.""" + for word in wordlist: + print(word) + +def show_wordsearch_text(grid, wordlist): + """Output the wordsearch grid and list of words to find.""" + show_grid_text(grid) + print() + show_wordlist_text(wordlist) + + +def svg_preamble(fo, width, height): + """Output the SVG preamble, with styles, to open file object fo.""" + + print(""" + + + + + """.format(width, height), file=fo) + +def grid_as_svg(grid, width, height): + """Return the wordsearch grid as a sequence of SVG elements.""" + + # A bit of padding at the top. + YPAD = 20 + # There is some (not much) wiggle room to squeeze in wider grids by + # reducing the letter spacing. + letter_width = min(32, width / ncols) + grid_width = letter_width * ncols + # The grid is centred; this is the padding either side of it. + XPAD = (width - grid_width) / 2 + letter_height = letter_width + grid_height = letter_height * nrows + s = [] + + # Output the grid, one letter at a time, keeping track of the y-coord. + y = YPAD + letter_height / 2 + for irow in range(nrows): + x = XPAD + letter_width / 2 + for icol in range(ncols): + letter = grid[irow][icol] + if letter != ' ': + s.append('{}' + .format(x, y, letter)) + x += letter_width + y += letter_height + + # We return the last y-coord used, to decide where to put the word list. + return y, '\n'.join(s) + +def wordlist_svg(wordlist, width, height, y0): + """Return a list of the words to find as a sequence of elements.""" + + # Use two columns of words to save (some) space. + n = len(wordlist) + col1, col2 = wordlist[:n//2], wordlist[n//2:] + + def word_at(x, y, word): + """The SVG element for word centred at (x, y).""" + return ( '' + '{}'.format(x, y, word) ) + + s = [] + x = width * 0.25 + # Build the list of elements for each column of words. + y0 += 25 + for i, word in enumerate(col1): + s.append(word_at(x, y0 + 25*i, word)) + x = width * 0.75 + for i, word in enumerate(col2): + s.append(word_at(x, y0 + 25*i, word)) + return '\n'.join(s) + +def write_wordsearch_svg(filename, grid, wordlist): + """Save the wordsearch grid as an SVG file to filename.""" + + width, height = 1000, 1414 + with open(filename, 'w') as fo: + svg_preamble(fo, width, height) + y0, svg_grid = grid_as_svg(grid, width, height) + print(svg_grid, file=fo) + # If there's room print the word list. + if y0 + 25 * len(wordlist) // 2 < height: + print(wordlist_svg(wordlist, width, height, y0), file=fo) + print('', file=fo) + + +def get_wordlist(wordlist_filename): + """Read in the word list from wordlist_filename.""" + wordlist = [] + with open(wordlist_filename) as fi: + for line in fi: + # The word is upper-cased and comments and blank lines are ignored. + line = line.strip().upper() + if not line or line.startswith('#'): + continue + wordlist.append(line) + return wordlist + +# Read the wordlist filename and grid dimensions (nrows, ncols) from the +# command line. +wordlist_filename = sys.argv[1] +nrows, ncols = int(sys.argv[2]), int(sys.argv[3]) +mask = None +if len(sys.argv) > 4: + mask = sys.argv[4] +if nrows > NMAX or ncols > NMAX: + sys.exit('Maximum number of rows and columns is {}'.format(NMAX)) +wordlist = sorted(get_wordlist(wordlist_filename), key=lambda w: len(w), + reverse=True) +# Obviously, no word can be longer than the maximum dimension. +max_word_len = max(nrows, ncols) +if max(len(word) for word in wordlist) > max_word_len: + raise ValueError('Word list contains a word with too many letters.' + 'The maximum is {}'.format(max(nrows, ncols))) + +# This flag determines whether words can be fitted backwards into the grid +# (which makes the puzzle a bit harder). +allow_backwards_words = False +# If using a mask, specify it by a key to the apply_mask dictionary. +grid, solution = make_wordsearch(nrows, ncols, wordlist, allow_backwards_words, + mask) + +# If we fitted the words to the grid, show it in text format and save SVG files +# of the grid and its solution. +if grid: + show_wordsearch_text(grid, wordlist) + filename = os.path.splitext(wordlist_filename)[0] + '.svg' + write_wordsearch_svg(filename, grid, wordlist) + filename = os.path.splitext(wordlist_filename)[0] + '-solution.svg' + write_wordsearch_svg(filename, solution, []) + diff --git a/puzzles/dots-and-boxes-or-connect-the-dots.pdf b/puzzles/dots-and-boxes-or-connect-the-dots.pdf new file mode 100644 index 0000000..58311b3 Binary files /dev/null and b/puzzles/dots-and-boxes-or-connect-the-dots.pdf differ diff --git a/puzzles/dots-and-boxes-or-connect-the-dots.txt b/puzzles/dots-and-boxes-or-connect-the-dots.txt new file mode 100644 index 0000000..5e46ac4 --- /dev/null +++ b/puzzles/dots-and-boxes-or-connect-the-dots.txt @@ -0,0 +1,86 @@ + . .. . . . . + . . .. . . . . .. . +. . . . . . . . . . . .. . + . . . . . . . .. . + . . . . . .. .. . . . + . . . . . + . . . . . .. + . . . . . + . . . . . . . . + . . . . . . .. . . . . . . + . . . . . . . . . . .. .. . + . . . .. . . . . . + . . . . . . . . . + ... . . . . . . . .. . .. . + .. . . . ... . . . . + . . . . . +. . . . . . . . . . .. + . . . . .. . .. .. .. . . +. . . . . . . . . + . . . . .. . + . . . . .. . . .. . .. + . .. . . . . + .. . . . . + . . . . . . . .. . + . . . . . . . . . . + . .. . . . . + . . .. . . . . .. . +. . . . . . . . . . . .. . + . . . . . . . .. . + . . . . . .. .. . . . + . . . . . + . . . . . .. + . . . . . + . . . . . . . . + . . . . . . .. . . . . . . + . . . . . . . . . . .. .. . + . . . .. . . . . . + . . . . . . . . . + ... . . . . . . . .. . .. . + .. . . . ... . . . . + . . . . . +. . . . . . . . . . .. + . . . . .. . .. .. .. . . +. . . . . . . . . + . . . . .. . + . . . . .. . . .. . .. + . .. . . . . + .. . . . . + . . . . . . . .. . + . . . . . . . . . . + + . . . . . + . . . . . .. + . . . . . + . . . . . . . . + . . . . . . .. . . . . . . + . . . . . . . . . . .. .. . + . . . .. . . . . . + . . . . . . . . . + ... . . . . . . . .. . .. . + .. . . . ... . . . . + . . . . . +. . . . . . . . . . .. + . . . . .. . .. .. .. . . +. . . . . . . . . + . . . . .. . + . . . . .. . . .. . .. + . .. . . . . + .. . . . . + . . . . . . . .. . + . . . . . . . . . . + . .. . . . . + . . .. . . . . .. . +. . . . . . . . . . . .. . + . . . . . . . .. . + . . . . . .. .. . . . + . . . . . + . . . . . .. + . . . . . + . . . . . . . . + . . . . . . .. . . . . . . + . . . . . . . . . . .. .. . + . . . .. . . . . . + . . . . . . . . . + ... . . . . . . . .. . .. . + .. . . . ... . . . . diff --git a/puzzles/generating-puzzles.ipynb b/puzzles/generating-puzzles.ipynb new file mode 100644 index 0000000..3b0f4cd --- /dev/null +++ b/puzzles/generating-puzzles.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating mini-puzzles with random.choice()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dots-and-boxes & Connect the dots & ... ?\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/b/b7/Dots-and-boxes-chains.png)\n", + "\n", + "![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Connect_the_dots_puzzle_%28partially_solved%29.png/400px-Connect_the_dots_puzzle_%28partially_solved%29.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " . . . . . . \n", + " . . . .. . \n", + " . . . . . . . \n", + " . . . . . . . . .. \n", + " . . . . . . . . . .\n", + " . . . .. . . . . . \n", + " . . . . . \n", + " . . . . . . \n", + " . .. . . . \n", + " . . . .. . . . \n", + " . . . . . . . \n", + ". . . . . . . . \n", + " . . . . .. .. . . . \n", + " . . . . . . . . . . . . . \n", + " . . . . . . \n", + " . ... . .. . . . . . . . . . .. \n", + " . . . . . . . . . \n", + " . . ... .. . .. . . . . . . \n", + " . . . . .. . . ... . \n", + " . . . . . . . . . . \n", + " . . . . . . . .. . . . .. \n", + " . . . . . . . . \n", + ". . . . . . . . .. . . . . . \n", + " . . . .. .\n", + " . . .. . . . . . . . \n" + ] + } + ], + "source": [ + "from random import choice\n", + "\n", + "characters = ['.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']\n", + "width = 100\n", + "height = 25\n", + "\n", + "for y in range(height):\n", + " for x in range(width):\n", + " print(choice(characters), end='')\n", + " print('')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate a \"Connect the dots\" with jp2a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](play.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "jp2a 1.0.6\n", + "Copyright (C) 2006 Christian Stigen Larsen\n", + "Distributed under the GNU General Public License (GPL) v2.\n", + "\n", + "Usage: jp2a [ options ] [ file(s) | URL(s) ]\n", + "\n", + "Convert files or URLs from JPEG format to ASCII.\n", + "\n", + "OPTIONS\n", + " - Read images from standard input.\n", + " --blue=N.N Set RGB to grayscale conversion weight, default is 0.1145\n", + " -b, --border Print a border around the output image.\n", + " --chars=... Select character palette used to paint the image.\n", + " Leftmost character corresponds to black pixel, right-\n", + " most to white. Minimum two characters must be specified.\n", + " --clear Clears screen before drawing each output image.\n", + " --colors Use ANSI colors in output.\n", + " -d, --debug Print additional debug information.\n", + " --fill When used with --color and/or --html, color each character's\n", + " background color.\n", + " -x, --flipx Flip image in X direction.\n", + " -y, --flipy Flip image in Y direction.\n", + " -f, --term-fit Use the largest image dimension that fits in your terminal\n", + " display with correct aspect ratio.\n", + " --term-height Use terminal display height.\n", + " --term-width Use terminal display width.\n", + " -z, --term-zoom Use terminal display dimension for output.\n", + " --grayscale Convert image to grayscale when using --html or --colors\n", + " --green=N.N Set RGB to grayscale conversion weight, default is 0.5866\n", + " --height=N Set output height, calculate width from aspect ratio.\n", + " -h, --help Print program help.\n", + " --html Produce strict XHTML 1.0 output.\n", + " --html-fill Same as --fill (will be phased out)\n", + " --html-fontsize=N Set fontsize to N pt, default is 4.\n", + " --html-no-bold Do not use bold characters with HTML output\n", + " --html-raw Output raw HTML codes, i.e. without the section etc.\n", + " --html-title=... Set HTML output title\n", + " -i, --invert Invert output image. Use if your display has a dark\n", + " background.\n", + " --background=dark These are just mnemonics whether to use --invert\n", + " --background=light or not. If your console has light characters on\n", + " a dark background, use --background=dark.\n", + " --output=... Write output to file.\n", + " --red=N.N Set RGB to grayscale conversion weight, default 0.2989f.\n", + " --size=WxH Set output width and height.\n", + " -v, --verbose Verbose output.\n", + " -V, --version Print program version.\n", + " --width=N Set output width, calculate height from ratio.\n", + "\n", + " The default mode is `jp2a --term-fit --background=dark'.\n", + " See the man-page for jp2a for more detailed help text.\n", + "\n", + "Project homepage on http://jp2a.sf.net\n", + "Report bugs to \n" + ] + } + ], + "source": [ + "! jp2a --help" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMWMMMMMMMMMMMMMMMMMMMMWNMMNNWMMMMNWNNMMMMMMMMMMMMMMMMWMMMMMMMMWMMMMMMMMKNNWMMMMMMMMMMMMMMMMMMMM\n", + "MMKdWWNXMMMxNWNNWNNONNNWNNNNWokWMNNXNNNMMWNXMMMMMMMMM0NNNNXNNNNoXWWKMMMMMMMdKMMNXMMM00NXWMMM00NNNMMM\n", + "MM0oMMMNMMM;NMMMMMM;KXWMMMMXXKcMMxkMMMNXkkXMMMMMMMMMMcMMMMXNMMW:XMMNMMMMMMOkMMMMNXXONMMMNNNkXMMMXNMM\n", + "MMXlMMMNMMMcXMX00KXNXkxMMMWXMM00KKoOXMWNNNNNMMMMMMMMMcMMMXNxxMW:0MMNMMMMMXdMMKlMMNox0MMMMMXMMMWXWMMM\n", + "MMNcMMMNWWN,0MMXXNMMM0xMMMXWMMMMMMMKK00oWMMWNMMMMMMMMcMMMWWXWNXx0MMWWWWNXoWMMKcKMMNXKxxKMMMMMNNMMMMM\n", + "MMMlMMMMMMM,0MMWWWNNM0kMMMXMMMMMMWdNNNNXMMMMXMMMMMMMMcMMMMXXNMMkkMMMMMMMcXMMMMMMMMMNNMMcMMMMMNMMMMMM\n", + "MMMcMMWWWXN:kNXXXXXWMKd0KWXMMMMMMoOMMMMMMWNXMMMMMMMMMcMMMMXMMMMOxMWWWNXNlKMMNXXcXMNNNMMcNWWWMNMMMMMM\n", + "MMMKXXKXXXNNXNMMMMMMMMMMX0WMMMMMMMKO0KKXNWMMMMMMMMMMMXKKKKNMMMMWKXXKXXXWMKk0NMMWONWMMMMNXKKXKWMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n" + ] + } + ], + "source": [ + "! jp2a play.jpg --width=100" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \n", + " \n", + " \n", + " . .. ... .... . . .... \n", + " ...... ..................... ...... ... ............... .. .. ..... ..... \n", + " .. . .. .... .... .. ..... . .. ... . .. ..... ..... .. \n", + " .. . .. ......... .. ....... ...... . .... ... . .. .. .... . ... \n", + " .. ...... ... .. .. ...... .. . ........ ........ ... ...... .. \n", + " . .. ..... .. . ....... . . ... .. .. .. . . \n", + " . .............. ...... .. ... . . .. ........ ..... ... ..... . \n", + " ........... ... ........ ...... ......... .... .... ....... \n", + " \n", + " \n", + " \n" + ] + } + ], + "source": [ + "img = '''MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMWMMMMMMMMMMMMMMMMMMMMWNMMNNWMMMMNWNNMMMMMMMMMMMMMMMMWMMMMMMMMWMMMMMMMMKNNWMMMMMMMMMMMMMMMMMMMM\n", + "MMKdWWNXMMMxNWNNWNNONNNWNNNNWokWMNNXNNNMMWNXMMMMMMMMM0NNNNXNNNNoXWWKMMMMMMMdKMMNXMMM00NXWMMM00NNNMMM\n", + "MM0oMMMNMMM;NMMMMMM;KXWMMMMXXKcMMxkMMMNXkkXMMMMMMMMMMcMMMMXNMMW:XMMNMMMMMMOkMMMMNXXONMMMNNNkXMMMXNMM\n", + "MMXlMMMNMMMcXMX00KXNXkxMMMWXMM00KKoOXMWNNNNNMMMMMMMMMcMMMXNxxMW:0MMNMMMMMXdMMKlMMNox0MMMMMXMMMWXWMMM\n", + "MMNcMMMNWWN,0MMXXNMMM0xMMMXWMMMMMMMKK00oWMMWNMMMMMMMMcMMMWWXWNXx0MMWWWWNXoWMMKcKMMNXKxxKMMMMMNNMMMMM\n", + "MMMlMMMMMMM,0MMWWWNNM0kMMMXMMMMMMWdNNNNXMMMMXMMMMMMMMcMMMMXXNMMkkMMMMMMMcXMMMMMMMMMNNMMcMMMMMNMMMMMM\n", + "MMMcMMWWWXN:kNXXXXXWMKd0KWXMMMMMMoOMMMMMMWNXMMMMMMMMMcMMMMXMMMMOxMWWWNXNlKMMNXXcXMNNNMMcNWWWMNMMMMMM\n", + "MMMKXXKXXXNNXNMMMMMMMMMMX0WMMMMMMMKO0KKXNWMMMMMMMMMMMXKKKKNMMMMWKXXKXXXWMKk0NMMWONWMMMMNXKKXKWMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n", + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM'''\n", + "\n", + "for line in img.split(\"\\n\"):\n", + " for letter in line:\n", + " if letter == \"M\":\n", + " img = img.replace(letter, \" \")\n", + " else:\n", + " img = img.replace(letter, \".\")\n", + " \n", + "print(img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## World Wheel but different\n", + "\n", + "![](https://literacystarter.files.wordpress.com/2014/11/word-wheel.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " a a n i i i o a f i fi i \n", + " a cm i i a \n", + " c ti n a c ii a n n \n", + " a f i g n a i i c \n", + " nt i c i n c o \n", + " a a m o m fg a cm g m \n", + " i a i n ia a a o g i t\n", + "nm g n i a f i i i i a i n o i if t \n", + "o c i a i gt o g a a i i \n", + " g o o i o f c a c a i i\n", + " o g f i i a t c i an t a i i f n\n", + " i i o a gm g f i \n", + " i g f c a a ca i t c a t \n", + " i a to a n o n o c io \n", + " f o f iam c i i a \n", + " g g a a m g a n a n i g \n", + " c f o o t n o g n m t c \n", + " f i g ng o m i i im \n", + " a iim a i i t i i n \n", + " c oa m a c g a n g ig i naag \n", + " f i o a f o a a o t o g m \n", + " t t i a i a a fa c c n \n", + " o g m i a i i n g m m i f n i i \n", + " n g a m i i o ft i f i f\n", + " t m ia g i i \n" + ] + } + ], + "source": [ + "from random import choice\n", + "\n", + "character_set = 'gamification '\n", + "characters = [character for character in character_set]\n", + "width = 100\n", + "height = 25\n", + "\n", + "for y in range(height):\n", + " for x in range(width):\n", + " print(choice(characters), end='')\n", + " print('')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# More games plz!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What other mini-games can we make?\n", + "\n", + "You can restrict yourself to using **ASCII characters only** (see https://en.wikipedia.org/wiki/ASCII) and stay in touch with early computer graphics ASCII art...\n", + "\n", + "Or you can extend your pallete with **Unicode characters**. This is a nice website that highlights specific character sets: http://xahlee.info/comp/unicode_index.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/puzzles/play.jpg b/puzzles/play.jpg new file mode 100644 index 0000000..63e9455 Binary files /dev/null and b/puzzles/play.jpg differ diff --git a/puzzles/word-search-puzzle-generator/README.md b/puzzles/word-search-puzzle-generator/README.md new file mode 100644 index 0000000..628b972 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/README.md @@ -0,0 +1,18 @@ +# Word Search Puzzle +A simple word search made in python + +![#demo](./demo.png) + +## Usage + +``` +$ python3 main.py -h +usage: main.py [-h] [-c] [-f FILE] + +Generates a word search puzzle + +optional arguments: + -h, --help show this help message and exit + -c, --cheated Hightlight words + -f FILE, --file FILE Path to a custom words file. One word per line. +``` \ No newline at end of file diff --git a/puzzles/word-search-puzzle-generator/demo.png b/puzzles/word-search-puzzle-generator/demo.png new file mode 100644 index 0000000..2bc2429 Binary files /dev/null and b/puzzles/word-search-puzzle-generator/demo.png differ diff --git a/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/main-checkpoint.py b/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/main-checkpoint.py new file mode 100644 index 0000000..3816b27 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/main-checkpoint.py @@ -0,0 +1,50 @@ +from word_grid import * +import argparse + + +# Initialize parser +parser = argparse.ArgumentParser(description="Generates a word search puzzle") + +# Adding optional argument +parser.add_argument("-c", "--cheated", action="store_true", help = "Hightlight words") +parser.add_argument("-f", "--file", type=str, default="words.txt", help = "Path to a custom words file. One word per line.") +parser.add_argument("-s", "--size", type=int, default=20, help = "Sets a custom grid size (Default: 20)") + +# Read arguments from command line +args = parser.parse_args() + +def main(cheated=False, words_file=None, size=20): + + # generating words from file + # words = ["wear", "variable", "print", "minimum", "graduate", "room", "bulk", "advise", "completed", "memory"] + file1 = open(words_file, 'r') + # lines = file1.readlines() # !!! THIS LINE BLOCKED CUSTOM WORD FILES !!! -- mb + words = [word.strip() for word in file1.readlines()] # !!! STRIP() IS ADDED !!! -- mb + file1.close() + + # appending words to array + # for _ in range(10): + # words.append(lines[random.randint(0, len(lines)-1)].strip()) + + # creating the word grid + grid = WordGrid(size) + + print("┌────────────────────┐") + print("│ Word Search Puzzle │") + print("└────────────────────┘") + + grid.cheated = cheated + grid.generate_with_words(words) + + # printing the words to find + print("Words:") + count = 0 + for word in words: + count += 1 + print(f"{count}. {word}", end=" | ") + print() + +if __name__ == "__main__": + main(cheated=args.cheated, words_file=args.file, size=args.size) + +# Created by Magoninho \ No newline at end of file diff --git a/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/words-checkpoint.txt b/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/words-checkpoint.txt new file mode 100644 index 0000000..64ceb46 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/.ipynb_checkpoints/words-checkpoint.txt @@ -0,0 +1,2 @@ +hello +worlds \ No newline at end of file diff --git a/puzzles/word-search-puzzle-generator/src/alphabet.py b/puzzles/word-search-puzzle-generator/src/alphabet.py new file mode 100644 index 0000000..6368c0b --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/alphabet.py @@ -0,0 +1,6 @@ +import random + +alphabet = 'abcdefghijklmnopqrstuvwxyz' + +def get_random_letter(): + return alphabet[random.randint(0, len(alphabet)-1)] diff --git a/puzzles/word-search-puzzle-generator/src/main.py b/puzzles/word-search-puzzle-generator/src/main.py new file mode 100644 index 0000000..3816b27 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/main.py @@ -0,0 +1,50 @@ +from word_grid import * +import argparse + + +# Initialize parser +parser = argparse.ArgumentParser(description="Generates a word search puzzle") + +# Adding optional argument +parser.add_argument("-c", "--cheated", action="store_true", help = "Hightlight words") +parser.add_argument("-f", "--file", type=str, default="words.txt", help = "Path to a custom words file. One word per line.") +parser.add_argument("-s", "--size", type=int, default=20, help = "Sets a custom grid size (Default: 20)") + +# Read arguments from command line +args = parser.parse_args() + +def main(cheated=False, words_file=None, size=20): + + # generating words from file + # words = ["wear", "variable", "print", "minimum", "graduate", "room", "bulk", "advise", "completed", "memory"] + file1 = open(words_file, 'r') + # lines = file1.readlines() # !!! THIS LINE BLOCKED CUSTOM WORD FILES !!! -- mb + words = [word.strip() for word in file1.readlines()] # !!! STRIP() IS ADDED !!! -- mb + file1.close() + + # appending words to array + # for _ in range(10): + # words.append(lines[random.randint(0, len(lines)-1)].strip()) + + # creating the word grid + grid = WordGrid(size) + + print("┌────────────────────┐") + print("│ Word Search Puzzle │") + print("└────────────────────┘") + + grid.cheated = cheated + grid.generate_with_words(words) + + # printing the words to find + print("Words:") + count = 0 + for word in words: + count += 1 + print(f"{count}. {word}", end=" | ") + print() + +if __name__ == "__main__": + main(cheated=args.cheated, words_file=args.file, size=args.size) + +# Created by Magoninho \ No newline at end of file diff --git a/puzzles/word-search-puzzle-generator/src/word_grid.py b/puzzles/word-search-puzzle-generator/src/word_grid.py new file mode 100644 index 0000000..d510268 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/word_grid.py @@ -0,0 +1,115 @@ +from math import sqrt +from alphabet import * +import random + +HORIZONTAL = 0 +VERTICAL = 1 + +class WordGrid: + def __init__(self, width) -> None: + self.grid = [] + self.width = width + self.area = width**2 + self.cheated = False + + # creating the grid array + for col in range(self.area): + self.grid.append(get_random_letter()) + + self.available_spots = [] + + # all the available spots that a letter can be placed + # True: can be placed + # False: can not be placed + for spot in range(self.area): + self.available_spots.append(True) # all spots are available at the beginning + + + # generates the word grid with words + # if this method is not called before printing the grid, + # it will print just some random letters + def generate_with_words(self, words): + # check if there are too much letters + if self.can_generate(words): + for word in words: + finded_place_to_enter_word = False + while not finded_place_to_enter_word: + + # chooses a random direction + random_direction = random.choice([HORIZONTAL, VERTICAL]) + + # random x and y positions of the first letter of the current word + random_x = random.randint(0, self.width-1) + random_y = random.randint(0, self.width-1) + + + # making sure the word won't go out of bounds + if random_x + len(word) > self.width and random_direction == HORIZONTAL: + random_x -= (random_x + len(word)) - self.width + if random_y + len(word) > self.width and random_direction == VERTICAL: + random_y -= (random_y + len(word)) - self.width + + + # checking if the word can be placed before placing it + if self.is_placeable(word, random_x, random_y, random_direction): + self.place_word(word, random_x, random_y, random_direction) + finded_place_to_enter_word = True + + + # when generating finishes, print itself + self.print() + + # sets a word in a position and with a particular direction + def place_word(self, word, x, y, direction): + # for every letter on the word + for l in range(len(word)): + if direction == HORIZONTAL: + # place horizontally + self.grid[x+l + y * self.width] = "\033[32m" + word[l] + "\033[0m" if self.cheated else word[l] + self.available_spots[x+l + y * self.width] = False # making the horizontal spot unavaliable + elif direction == VERTICAL: + # place vertically + self.grid[x + (y+l) * self.width] = "\033[32m" + word[l] + "\033[0m" if self.cheated else word[l] + self.available_spots[x + (y+l) * self.width] = False # making the vertical spot unavaliable + + + # checks if a word can be placed in a position and with a particular direction + def is_placeable(self, word, x, y, direction): + # for every letter on the word + for l in range(len(word)): + spot_available = self.available_spots[x+l + y * self.width] if direction == HORIZONTAL else self.available_spots[x + (y+l) * self.width] + + # if the spot is available, then continue checking + if spot_available: + continue + # if a spot is unavaliable, then is not placeable, returns false + else: + return False + # if the loop finishes without returning false, it means that is placeable, returns true + return True + + def can_generate(self, words): + letter_count = 0 + for word in words: + for letter in word: + letter_count += 1 + # if there are much more letters than the grid area + if letter_count > self.area: + print("\nToo many words for a little grid!") + return False + if len(word) > self.width: + print(f"\nYou entered a word too big for the grid size! (Grid size: {self.width})") + return False + return True + + # prints the grid on the terminal + def print(self): + + print("\033[96m┌" + ("─"*(2*(self.width)+1)) + "┐\033[0m" ) # just a nice little line + for y in range(self.width): + print("\033[96m│\033[0m", end=" ") + for x in range(self.width): + print(self.grid[x + y * self.width], end=" ") + print("\033[96m│\033[0m") + print("\033[96m└" + ("─"*(2*(self.width)+1)) + "┘\033[0m" ) + diff --git a/puzzles/word-search-puzzle-generator/src/words.txt b/puzzles/word-search-puzzle-generator/src/words.txt new file mode 100644 index 0000000..64ceb46 --- /dev/null +++ b/puzzles/word-search-puzzle-generator/src/words.txt @@ -0,0 +1,2 @@ +hello +worlds \ No newline at end of file diff --git a/puzzles/word-search.ipynb b/puzzles/word-search.ipynb new file mode 100644 index 0000000..691ce1e --- /dev/null +++ b/puzzles/word-search.ipynb @@ -0,0 +1,108 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating word search puzzles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](https://mario.wiki.gallery/images/thumb/3/31/WordSearch_178_1.png/683px-WordSearch_178_1.png)\n", + "\n", + "https://github.com/Magoninho/word-search-puzzle-generator.git" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "! git clone https://github.com/Magoninho/word-search-puzzle-generator.git" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**NOTE**: two small changes need to be made in main.py to make this code work.\n", + "\n", + "Comment this line out: \n", + "\n", + "`# words = [\"wear\", \"variable\", \"print\", \"minimum\", \"graduate\", \"room\", \"bulk\", \"advise\", \"completed\", \"memory\"]`\n", + "\n", + "And change this line...\n", + "\n", + "`lines = file1.readlines()`\n", + "\n", + "into: \n", + "\n", + "`words = [word.strip() for word in file1.readlines()]`\n", + "\n", + "Now it should work!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "! python3 word-search-puzzle-generator/src/main.py -h" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "! python3 word-search-puzzle-generator/src/main.py --file word-search.txt -s 20 -c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "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.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/puzzles/word-search.txt b/puzzles/word-search.txt new file mode 100644 index 0000000..8ab3b76 --- /dev/null +++ b/puzzles/word-search.txt @@ -0,0 +1,10 @@ +hello +world +and +what +other +words +can +i +play +with \ No newline at end of file diff --git a/puzzles/world-wheel-but-different.pdf b/puzzles/world-wheel-but-different.pdf new file mode 100644 index 0000000..ff611a7 Binary files /dev/null and b/puzzles/world-wheel-but-different.pdf differ diff --git a/puzzles/world-wheel-but-different.txt b/puzzles/world-wheel-but-different.txt new file mode 100644 index 0000000..57d7a85 --- /dev/null +++ b/puzzles/world-wheel-but-different.txt @@ -0,0 +1,69 @@ + a o it m i i m f c + c i ag n o amf f o i + o i o f i a g af i g + m i f a t g c f t i + n o f a f tnf o f + a i i i i i t in c caa + t fa n f i t a i o + o i ag ig g g a i i i n ag + n m gt a i o f i o ni i i + m i f i a a a o i m a g c + f am a c o i f cna f mi + t a i c f g f n i c o o g + o f t a g ng i a i a n n o a t oi i it + o t n o m f g a i a m ni + f i i g m o i a n t a i a a m i a i a +i a a ac i a t i tn t a + o f tf i an i n o f i t t + c g fg i o o ca i o o o m t + f o i i i c i ta i ca c f + c n aa g i m g m i c + c i c i f i n m f i i + a o i g m o ot a i a c f m i + i a a i f f a c g i + to in a t og im i o i f n c +ao m g ii c n a to t + + + + + + + + + + + + + + + + + + + + c a of g m g i a c n m a i c m i g + fm f oi i c t g g f a c c i i n + i i mf a in n m n + o a i o t g o m ag + m o o t c m c i i + i f gii a f ic m oc m f + m c m i t a i m go i + n mn m a n i a i i +i i i c i g +iii c i a a i a o ai t i c a + a c m i o o an f t m i a a g +g g a c f a n c m a m f o m c i +a g a a i n g a n +ani a t m c n f i o g a t + i f in i n m g ita o i a o i mc a + in i i f ci a i to tf i ct i + i a t o ga i t n t +a a ii o mt fi n g f a t n a i + g f in t ig a o i a g m ma o + o o o g a o ni n i in f i + i i a a n i f + a i o i g a f a ta c a o g a i + t tc a f i n g t i fg no + f ot i a a a i i i g n t i t m c i n + ic a n a i i i mi ni m a t i