{ "cells": [ { "kind": 1, "language": "markdown", "value": "# Drawing with Forth\n\nIn this tutorial, you'll learn basic Forth by drawing graphics with a turtle.\n\n> šŸ’” Click the *Run* button next to the examples to run the code, or click the *Run* button at the top to run all the code on this page.\n\n> ā• This is not a real tutorial, but a demo of a [WAForth notebook](https://github.com/remko/waforth#notebooks), and perhaps a glimpse of what an interactive Forth tutorial using notebooks could look like. \n\n## The stack\n\nForth is a stack-based language. Numbers are put on the stack, and words pop them off the stack (and put new ones on the stack) again.\nFor example, to take the sum of 8 and 14, put both numbers on the stack, and call `+`. To pop the result of the stack and print it out, use `.`:" }, { "kind": 2, "language": "waforth", "value": "8 14 +\n." }, { "kind": 1, "language": "markdown", "value": "## Drawing lines\n\nInstead of printing numbers to output, we can also draw lines.\n\nThe `FORWARD` word pops the number of the stack, and moves a turtle forward while drawing a line:" }, { "kind": 2, "language": "waforth", "value": "200 FORWARD" }, { "kind": 1, "language": "markdown", "value": "Let's now also turn the turtle 90 degrees, and create a complete square:" }, { "kind": 2, "language": "waforth", "value": "200 FORWARD\n90 RIGHT\n200 FORWARD\n90 RIGHT\n200 FORWARD\n90 RIGHT\n200 FORWARD\n90 RIGHT" }, { "kind": 1, "language": "markdown", "value": "## Creating your own words\n\nWe can create our own parameterized word that draws a square of the given size:" }, { "kind": 2, "language": "waforth", "value": ": SQUARE ( n -- )\n DUP FORWARD\n 90 RIGHT\n DUP FORWARD\n 90 RIGHT\n DUP FORWARD\n 90 RIGHT\n DUP FORWARD\n 90 RIGHT\n;\n\n500 SQUARE" }, { "kind": 1, "language": "markdown", "value": "## Loops\n\nForth also has loops using `DO` and `LOOP`:" }, { "kind": 2, "language": "waforth", "value": ": SQUARE ( n -- )\n 4 0 DO\n DUP FORWARD\n 90 RIGHT\n LOOP\n DROP\n;\n\n250 SQUARE" }, { "kind": 1, "language": "markdown", "value": "## Combining words\n\nWe can create more complex figures by using the `SQUARE` word from above, and repeating it.\n\n> šŸ’” Play with the numbers in `FLOWER` to create variations of the flower " }, { "kind": 2, "language": "waforth", "value": ": SQUARE ( n -- )\n 4 0 DO\n DUP FORWARD\n 90 RIGHT\n LOOP\n DROP\n;\n\n: FLOWER ( n -- )\n 24 0 DO\n DUP SQUARE\n 15 RIGHT\n LOOP\n DROP\n;\n\n250 FLOWER" }, { "kind": 1, "language": "markdown", "value": "## Recursion\n\nWords can also call themselves:" }, { "kind": 2, "language": "waforth", "value": ": SPIRAL ( n -- )\n DUP 1 < IF DROP EXIT THEN \n DUP FORWARD\n 15 RIGHT\n 98 100 */ RECURSE\n;\n\n140 SPIRAL" }, { "kind": 1, "language": "markdown", "value": "We can make a small variation of the above recursive program, where the lines become longer instead of shorter.\nTo avoid hard-coding some constants in the code, we use the word `CONSTANT` to define a new constant (`ANGLE`) to turn.\n\n> šŸ’” Change the constant `ANGLE` to 91 and see what happens." }, { "kind": 2, "language": "waforth", "value": "90 CONSTANT ANGLE\n\n: SPIRAL ( n -- )\n DUP 800 > IF DROP EXIT THEN \n DUP FORWARD\n ANGLE RIGHT\n 10 +\n RECURSE\n;\n\n1 SPIRAL" }, { "kind": 1, "language": "markdown", "value": "## Fractals\n\nYou can create more complex recursive drawings, called *fractals*. \n\nA famous fractal is the *Koch snowflake*.\n\n> šŸ’” Change the `DEPTH` constant to make a coarser or finer grained snowflake" }, { "kind": 2, "language": "waforth", "value": "730 CONSTANT LENGTH\n3 CONSTANT DEPTH\n\n: SIDE ( length depth -- )\n DUP 0= IF \n DROP FORWARD EXIT \n THEN\n SWAP 3 / SWAP 1-\n 2DUP RECURSE\n 60 LEFT 2DUP RECURSE\n 120 RIGHT 2DUP RECURSE\n 60 LEFT RECURSE\n;\n\n: SNOWFLAKE ( -- )\n 3 0 DO \n LENGTH DEPTH SIDE\n 120 RIGHT\n LOOP\n;\n\n1 SETPENSIZE\nSNOWFLAKE" }, { "kind": 1, "language": "markdown", "value": "You can also draw plants and trees using fractals:" }, { "kind": 2, "language": "waforth", "value": "450 CONSTANT SIZE\n7 CONSTANT BRANCHES\n160 CONSTANT SPREAD\n\nVARIABLE RND\nHERE RND !\n\n: RANDOM ( -- n )\n RND @ 75 * 74 + 65537 MOD\n DUP RND !\n;\n\n: CHOOSE ( n1 -- n2 )\n RANDOM 65537 */MOD SWAP DROP \n; \n\n: PLANT ( size angle -- )\n OVER 10 < IF 2DROP EXIT THEN\n DUP RIGHT\n OVER FORWARD\n BRANCHES 0 DO\n OVER 2/\n SPREAD CHOOSE SPREAD 2/ -\n RECURSE\n LOOP\n PENUP SWAP BACKWARD PENDOWN\n LEFT\n;\n \n1 SETPENSIZE\nSIZE 0 PLANT" }, { "kind": 1, "language": "markdown", "value": "## Creating your own language\n\nForth also provides all the tools necessary to create your own language. \n\nFor example, if we want the Thurtle language to be more like Logo, we can define the `TO` and `END` keywords to replace the standard Forth words for starting and ending compilation:" }, { "kind": 2, "language": "waforth", "value": ": TO : ;\n: END POSTPONE ; ; IMMEDIATE\n\nTO SQUARE\n 4 0 DO\n 200 FORWARD\n 90 RIGHT\n LOOP\nEND\n\nSQUARE" }, { "kind": 1, "language": "markdown", "value": "You can even create a graphical language based on emoji:" }, { "kind": 2, "language": "waforth", "value": "\\ Define our graphical language\n: šŸšœ : ; : šŸš§ POSTPONE ; ; IMMEDIATE : ā¤µļø RIGHT ; : āž”ļø FORWARD ; : ā–¶ļø POSTPONE DO ; IMMEDIATE : šŸ” POSTPONE LOOP ; IMMEDIATE\n\n\\ Build the definition of a pentagram\nšŸšœ ā›¤\n 18 ā¤µļø \n 5 0 ā–¶ļø\n 450 āž”ļø\n 144 ā¤µļø\n šŸ”\nšŸš§\n\n\\ Draw a pentagram\nā›¤" } ] }