{"id":15443479,"url":"https://github.com/lemonyte/the-top-level-walruses","last_synced_at":"2026-01-30T01:43:32.745Z","repository":{"id":191254367,"uuid":"684250107","full_name":"lemonyte/the-top-level-walruses","owner":"lemonyte","description":"Piet program generator and interpreter, created for the 10th Python Discord Code Jam.","archived":false,"fork":false,"pushed_at":"2024-10-28T19:30:37.000Z","size":398,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-24T00:39:08.202Z","etag":null,"topics":["code-jam","esoteric","piet","python-discord"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lemonyte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-28T18:54:59.000Z","updated_at":"2025-01-30T07:40:12.000Z","dependencies_parsed_at":"2023-08-29T03:21:09.744Z","dependency_job_id":"65caafaa-2965-43e9-bb4b-fa6d05c27d20","html_url":"https://github.com/lemonyte/the-top-level-walruses","commit_stats":{"total_commits":94,"total_committers":3,"mean_commits":"31.333333333333332","dds":0.0957446808510638,"last_synced_commit":"5c9b4c224c3464853b6488ff4fe0592c8dd3b89a"},"previous_names":["lemonyte/the-top-level-walruses"],"tags_count":0,"template":false,"template_full_name":"python-discord/code-jam-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fthe-top-level-walruses","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fthe-top-level-walruses/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fthe-top-level-walruses/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fthe-top-level-walruses/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lemonyte","download_url":"https://codeload.github.com/lemonyte/the-top-level-walruses/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248124907,"owners_count":21051757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-jam","esoteric","piet","python-discord"],"created_at":"2024-10-01T19:35:10.916Z","updated_at":"2026-01-30T01:43:32.688Z","avatar_url":"https://github.com/lemonyte.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# :=\n\nThis repository contains **The Top-level Walruses** team's submission for the [10th Python Discord Code Jam](https://www.pythondiscord.com/events/code-jams/10/).\n\n## Secret codes\n\nThe theme of the code jam was **secret codes**.\nWe decided to create a program that can encode and decode secret messages (or even *code*) into images, using a *secret code* for a Vigenère cipher.\nBut wait, they're not just any images, they're [Piet](https://www.dangermouse.net/esoteric/piet.html) programs!\nPiet is an esoteric programming language that uses changes in color to represent instructions.\nWhen executed with the correct key as input, the Piet program will output the encoded message.\n\n## Usage\n\n### Setting up\n\nThis project was built and tested with Python 3.11.\n\nTo get started, run the commands below in your terminal:\n\n```sh\n# Clone the repository and change into the project directory.\ngit clone https://github.com/lemonyte/the-top-level-walruses.git\ncd the-top-level-walruses\n\n# Create a virtual environment and activate it.\npython -m venv .venv\n# PowerShell or Command Prompt.\n.\\.venv\\Scripts\\activate\n# Bash or other Linux shell.\nsource ./.venv/bin/activate\n\n# Install project dependencies.\npip install -r requirements.txt\n```\n\n### Generating an image\n\nUse the `generate` command to generate an image. The command can take input data either as a string or a path to a file.\n\n```sh\npython -m piet generate \"My super secret message!\" out.png\n```\n\nThis will generate an image that looks like this:\n\n![demo_generate.png](demo/demo_generate.png)\n\nBesides input and output paths, the command also accepts the following options:\n\n- `--cols \u003cint\u003e`: Override the number of columns in the output image, by default the generator will automatically determine the best number of columns.\n- `--recurse \u003cint\u003e`: Generate images recursively, by default this is disabled. [More on this](#recursive-encoding) later.\n- `--input \u003cstring\u003e`: Input to pass to the interpreter, used as a cipher shift. [More on this](#encrypting-with-a-key) later as well.\n- `--step-limit \u003cint\u003e`: Limit the number of steps the interpreter can take, by default this is 1 million. This is useful to prevent infinite loops.\n- `--debug`: Enable debug mode, which will print out the state of the interpreter after each step.\n\n### Interpreting an image\n\nRunning your newly generated image is pretty straightforward:\n\n```sh\npython -m piet run out.png\n```\n\nThis command has the same `--input`, `--step-limit` and `--debug` options as the `generate` command.\nAdditionally, the `--execute` flag will try to execute the content of the image as Python code.\n\n### Encrypting with a key\n\nBy passing a string to the `--input` option, you can encrypt your message with a key.\n\n```sh\npython -m piet generate \"My super secret message!\" out.png --input \"my secret key\"\n```\n\nUsing a Vigenère cipher, the bytes in the input data will be shifted by the bytes in the key before being encoded into the image.\nThe catch is the reverse operation is encoded in the image as well, so you must pass the same key to the interpreter to decrypt the message.\nIf run without a key, the interpreter will fail to execute the program.\n\n### Recursive encoding\n\nIf you pass `--recurse` a value greater than 0, the generator will recursively generate an image for the input data, then use that image as the input data for the next image.\n\n\u003e Note: be careful when using this option, as the size of the image and the time it takes to generate will grow very quickly.\n\n```sh\npython -m piet generate \"My super secret message!\" out.png --recurse 3\n```\n\nTo use keys with recursive encoding, you must pass multiple keys by specifying the `--input` option multiple times. If the number of keys is less than the number of recursions, remaining recursions will not be encrypted.\n\n```sh\npython -m piet generate \"My super secret message!\" out.png --recurse 3 --input \"key1\" --input \"key2\" --input \"key3\"\n```\n\nThis will generate a substantially larger image:\n\n![demo_recurse.png](demo/demo_recurse.png)\n\nTo decrypt a recursively encoded image, you must run the images sequentially using same keys that were used in the generation process *in reverse order*.\nThis is because the first key was used to encrypt the innermost image, and the last key was used to encrypt the outermost image.\n\nDue to a technical limitation, each nested image is also wrapped in a snippet of Python code that simply decodes the image from base64 and saves it.\nTo skip the step of saving and running the wrapper code, you can pass the `--execute` flag to the interpreter.\n\n\u003e Note: by default the wrapper code will write to a file named `out.png`.\n\u003e If this is undesirable, you can save the wrapper code to a file by passing an output path and not using the `--execute` flag, then edit the file path in the wrapper code and run it manually.\n\n```sh\npython -m piet run out.png --input \"key3\" --execute\npython -m piet run out.png --input \"key2\" --execute\npython -m piet run out.png --input \"key1\"\n```\n\n## Technical\n\nWe used Pillow for reading and writing image files, and a custom list subclass to store the color data as tuples of RGB values.\nWe opted not to use numpy arrays because it was more work to resize the arrays dynamically than to use a list.\n\n### Common\n\nThis module simply contains common classes and constants used by the other modules, like the `Color` named tuple and the `SelfExpandingList` class.\n\n### Reader\n\nInterpreting an image starts with the reader module.\nThe `ImageReader` class is responsible for converting an input image into a two-dimensional list of `Color` objects, and analyzing the image to determine information about codels and color blocks.\n\n### Runtime\n\nThe runtime module contains the classes that simulate Piet's behavior, including the stack, direction pointer, and codel chooser.\nA `PietRuntime` object keeps track of the state of the stack, pointer, and codel chooser, and provides methods to manipulate them.\nIt also provides the binary input and output interfaces.\n\n### Interpreter\n\nThe `PietInterpreter` class contains the logic for executing a Piet program.\nIt exposes the methods `run` to run the program, and `step` to execute a single step in the execution loop.\n\n### Generator\n\nThe `ImageGenerator` class is responsible for generating an image from input data.\nIt has methods for setting specific locations in the image to specific commands, and setting the next command in the path of the interpreter's execution.\nInternally, it uses the interpreter to run the program as it is being generated, to determine the position of the next command.\nIt also has a method for generating an image recursively up to a specified depth.\nOnce the generated image is complete, the colors are inserted into an Pillow `Image` object and returned.\n\n### CLI\n\nThis module provides a command-line interface for the generator and interpreter.\n\n## Known issues\n\nA number of issues are present in this project, as we didn't have enough time to properly investigate and fix them.\n\n- The interpreter does not support scaled images, and does not have an option to specify codel size.\n- Extremely large input data will cause a RecursionError.\n- Using arbitrary binary data as input data will in some cases cause the generator to create an incomplete image, making decoding impossible. This can be worked around using base64, but that negates the benefit of compression.\n- Adding zlib compression breaks the project due to the above issue.\n\n## Development\n\nFollow the steps in the [Setting up](#setting-up) section, then:\n\n```sh\n# Install development dependencies.\npip install -r requirements-dev.txt\n\n# Set up pre-commit hooks.\npre-commit install\n```\n\nRun the tests by simply invoking pytest:\n\n```sh\npytest\n```\n\n## Credits\n\nThe [Piet](https://www.dangermouse.net/esoteric/piet.html) language was created by David Morgan-Mar.\n\nTeam contributions:\n\n- Interpreter and runtime: [Noah Tanner](https://github.com/kevinshome)\n- Image generator and CLI: [Lemonyte](https://github.com/lemonyte)\n- Image reader: [Dayshaun Lee](https://github.com/dayshaunlee)\n- Web interface: [aditheawesome](https://github.com/aditheawesome) \u0026 [Dreadrook](https://github.com/Dreadrook)\n\n## License\n\n[MIT License](LICENSE)\n\n## Gallery\n\nFor those of you who just want to admire the code art a little more, here is a collection of images generated by our program.\nDecrypting them is left as an exercise for the reader.\nCan you solve the puzzle? 😉\n\n### key.png\n\nIt's a key... but for what?\n\nGenerally, images encoded without a key will look more uniform, with large white areas and less distinct colors.\n\n![key.png](demo/key.png)\n\n### piet.png\n\nThis one looks a little different because of the encryption cipher shifting the byte values.\n\n\u003cdetails\u003e\n\u003csummary\u003eKey hint\u003c/summary\u003e\nSurname.\n\u003c/details\u003e\n\n![piet.png](demo/piet.png)\n\n### key2.png\n\nIt's gotta be called \"key\" for a reason, right?\n\n![key2.png](demo/key2.png)\n\n### generator.png\n\nThat filename sounds familiar... what an interesting color pattern!\n\n\u003cdetails\u003e\n\u003csummary\u003eKey hint\u003c/summary\u003e\nWhat is the name of the first parameter of an instance method?\n\u003c/details\u003e\n\n![generator.png](demo/generator.png)\n\n### key3.png\n\nI think you get the idea by now.\nThis one looks a bit bigger than the other two...\n\n![key3.png](demo/key3.png)\n\n### zen.png\n\nSo beautiful... I could stare at it for hours.\n\n\u003cdetails\u003e\n\u003csummary\u003eKey hint\u003c/summary\u003e\nWhat do you import to get the Zen of Python?\n\u003c/details\u003e\n\n![zen.png](demo/zen.png)\n\n### secret.png\n\nThis is a rather big one, I wonder what could be inside...\n\n\u003cdetails\u003e\n\u003csummary\u003eKey hint\u003c/summary\u003e\nThe keys are hidden in plain sight.\n\u003c/details\u003e\n\n![secret.png](demo/secret.png)\n\n### walrus.png\n\nThis one was manually created using an image editor to look like something, run it to see what it does!\n\n![walrus.png](demo/walrus.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonyte%2Fthe-top-level-walruses","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemonyte%2Fthe-top-level-walruses","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonyte%2Fthe-top-level-walruses/lists"}