Work on adaptations; most are complete.

This commit is contained in:
Scott Richmond 2024-12-01 20:08:49 -05:00
parent 31739b4caa
commit 936bd238bf

View File

@ -34,18 +34,23 @@ If you are stimulated by this idea, then you are exactly who I hope you are.
### Your computer baggage ### Your computer baggage
This chapter gives a very quick summary of basic Ludus. This chapter gives a very quick summary of basic Ludus.
It is brief, not just because I hope that you already know a little Ludus but because I expect that you are willing to use the manual that came with your copy of Ludus. It is brief, not just because I hope that you already know a little Ludus but because I expect that you are willing to use the reference that comes with the Ludus web interpreter.
In other words, I expect that you are willing to do some learning about Ludus mechanics on your own. In other words, I expect that you are willing to do some learning about Ludus mechanics on your own.
If you have never met Ludus before, probably you have been introduced to some other computer language and most likely this other language was BASIC. If you have never met Ludus before, probably you have been introduced to some other computer language and most likely this other language was BASIC.
(I am saddened to think of you learning BASIC before Ludus, and this book will give you the chance to right that terrible wrong.) (I am saddened to think of you learning BASIC before Ludus, and this book will give you the chance to right that terrible wrong.)
> Reader, we do not actually expect BASIC to have been your first language, although we share Clayson's distate for it. Likely your first language was Javascript, or Python, or Processing, or maybe even Scratch. The distance from these to Ludus is not unlike the distance from BASIC to Logo was.
If you do know something about one computer language, you should be able to plunge happily into the manual of a second language--Ludus. If you do know something about one computer language, you should be able to plunge happily into the manual of a second language--Ludus.
I will give you some directional help, though, by suggesting what questions you need answered in your manual. I will give you some directional help, though, by suggesting what questions you need answered in your manual.
Then it will be up to you to learn the specifics. Then it will be up to you to learn the specifics.
I assume, too, that you have played around with personal computers and I assume, too, that you have played around with personal computers and
know how they "feel." You may like or dislike these machines, but your feelings are based on personal experience. know how they "feel." You may like or dislike these machines, but your feelings are based on personal experience.
You are familiar with disks, disk drives, keyboards,and program editors. You are familiar with disks, disk drives, keyboards, and program editors.
> In fact, we expect you may well not be familiar with disk drives, but it's definitely good to have some familiarity with a keyboard.
### No baggage ### No baggage
If you have had no experience with personal computers, and have never tried to learn a computer language--on your own or in a course--you may find this book rough going. If you have had no experience with personal computers, and have never tried to learn a computer language--on your own or in a course--you may find this book rough going.
@ -75,33 +80,33 @@ Craft is about building things by hand, and that is what you will be doing with
### Copying and tinkering ### Copying and tinkering
Copying computer programs is so widespread that I had better give you my opinion about the usefulness of it all. Copying computer programs is so widespread that I had better give you my opinion about the usefulness of it all.
In the previous paragraph I said that copying was a good thing at the start of one's apprenticeship. In the previous paragraph I said that copying was a good thing at the start of one's apprenticeship.
As you go through this chapter, I hope you will want to try out my procedures. As you go through this chapter, I hope you will want to try out my functions.
That's OK. That's OK.
But if you simply type my procedures into your computer, you will only reproduce what I have done. But if you simply type my functions into your computer, you will only reproduce what I have done.
And that will bore us both. And that will bore us both.
The book shows what I have done; it doesn't show what you can do. The book shows what I have done; it doesn't show what you can do.
My procedures offer you a starting place, so that you don't have to build from zero. My functions offer you a starting place, so that you don't have to build from zero.
But it is up to you to go beyond that start. But it is up to you to go beyond that start.
So please do copy the ideas of any procedure that strike your fancy. So please do copy the ideas of any function that strike your fancy.
But, once you have made those ideas work on the screen, play rough with them. But, once you have made those ideas work on the screen, play rough with them.
Give the copied procedure funny and outlandish arguments. Give the copied function funny and outlandish arguments.
(Very big or very small numbers could be outlandish, but what is a funny argument?) (Very big or very small numbers could be outlandish, but what is a funny argument?)
What happens then? What happens then?
Does your copied procedure still work? Does your copied function still work?
Can you explain how? Can you explain how?
Go on to make a few changes inside the body of the procedure; change some of the commands just a little. Go on to make a few changes inside the body of the function; change some of the commands just a little.
Can you guess what might happen before you experiment on these changes? Can you guess what might happen before you experiment on these changes?
Get into the habit of tinkering, just a little. Get into the habit of tinkering, just a little.
Whenever you write, or copy, a nice procedure, make a few changes to it so that it does something else. Whenever you write, or copy, a nice function, make a few changes to it so that it does something else.
### Equipment ### Equipment
Your most important piece of equipment is a notebook. Your most important piece of equipment is a notebook.
It is far more important than the computer you work on and all the technical manuals at your disposal. It is far more important than the computer you work on and all the technical manuals at your disposal.
Select a notebook with large, unlined, and bound-in pages. Select a notebook with large, unlined, and bound-in pages.
I want you to keep track of your work in this notebook. I want you to keep track of your work in this notebook.
That means everything: the little sketches, word portraits, diagrams, procedure listings, the printed images. That means everything: the little sketches, word portraits, diagrams, function listings, the printed images.
Stick in any magazine and newspaper illustrations that strike your fancy, whenever you find them; don't worry aobut organization. Stick in any magazine and newspaper illustrations that strike your fancy, whenever you find them; don't worry aobut organization.
You will be mixing the good with the less than good, the things that worked well with those that never will. You will be mixing the good with the less than good, the things that worked well with those that never will.
@ -120,12 +125,17 @@ Get a lot of it.
Be careful using this glue, though; it is very flammable. Be careful using this glue, though; it is very flammable.
Don't smoke and glue at the same time. Don't smoke and glue at the same time.
> Don't smoke.
> But seriously, even though you might imagine that we're fully digital, nearly four decades later, we encourage you, still, to use pen and paper liberally. Rubber cement may be less interesting, and you're probably not reading magazines. But we take tools and media and affordances seriously, and pen and paper are what you want, not some shiny new digital toy.
<!--
### Dialects ### Dialects
Unfortunately, there is not just one Ludus. Unfortunately, there is not just one Ludus.
While some Luduss are more alike than others, most have quirks. While some Luduss are more alike than others, most have quirks.
I use Terrapin MacLudus throughout this book. I use Terrapin MacLudus throughout this book.
All the procedures have been written in this dialect using an Apple Macintosh Plus. All the functions have been written in this dialect using an Apple Macintosh Plus.
Most of the images were generated by Ludus procedures and printed on an Apple Imagewriter II printer. Most of the images were generated by Ludus functions and printed on an Apple Imagewriter II printer.
The rest were done by hand, mine. The rest were done by hand, mine.
> Appendix A in Brian Harvey's _Computer Science Ludus Style_, volume 1: _Intermediate Programming_ (Cambridge, MA: MIT Press, 1985), gives a nice summary of the syntactic differences between Luduss. It gives no help with the differences in graphics, though. > Appendix A in Brian Harvey's _Computer Science Ludus Style_, volume 1: _Intermediate Programming_ (Cambridge, MA: MIT Press, 1985), gives a nice summary of the syntactic differences between Luduss. It gives no help with the differences in graphics, though.
@ -138,20 +148,23 @@ I don't use funny pen patterns, polygons filled with patterns that look like bri
There are no sprites or multiple turtles. There are no sprites or multiple turtles.
The only colors I use are white, black, and (very occasionally) a reversing pen color. The only colors I use are white, black, and (very occasionally) a reversing pen color.
All the line drawings have been done with a standard, narrow-width pen. All the line drawings have been done with a standard, narrow-width pen.
-->
### Caveat emptor ### Caveat emptor
This is a little late for a warning, but here it is anyway: _This is not a bookabout Ludus._ This is a little late for a warning, but here it is anyway: _This is not a book about Ludus._
You will end up knowing a lot about Ludus, and that is no bad thing. You will end up knowing a lot about Ludus, and that is no bad thing.
But the goal of the book is to get you to build visual models, and Ludus is only a means to that end. But the goal of the book is to get you to build visual models, and Ludus is only a means to that end.
God knows, we could have used Pascal. God knows, we could have used Python.
But it just so happens that Ludus is easier to learn and easier to use than most of the other languages that we could have selected. But it just so happens that Ludus is easier to learn and easier to use than most of the other languages that we could have selected.
Ludus notation is neat and tidy; it looks nice on the page and that encourages visual thinking. Ludus notation is neat and tidy; it looks nice on the page and that encourages visual thinking.
But most important, because Ludus is so easy to play around with, it won't get in the way. But most important, because Ludus is so easy to play around with, it won't get in the way.
> In fact, while we're sure Logo had some of these advantages over its competition (Clayson used Pascal, not Python, as his strawman here), we have different ideas about what's interesting about Ludus. We think Ludus, like Logo, is better for learning _how to think well with computers_, and that it teaches a different set of things than you might learn in a typical introductory programming situation, whether that be computer-scientific, artistic or creative, or digital-humanistic.
### Turtles are us ### Turtles are us
We will concentrate on the graphic parts of Ludus. We will concentrate on the graphic parts of Ludus.
And that means "turtle graphics." And that means "turtle graphics," which Ludus borrows from Logo.
The intent of Ludus's turtle metaphor was to inspire young children to explore shapes. The intent of Logo's turtle metaphor was to inspire young children to explore shapes.
The turtle is a tiny triangle of light that is moved about the screen via Ludus commands. The turtle is a tiny triangle of light that is moved about the screen via Ludus commands.
As the turtle moves, it leaves a trace of light. As the turtle moves, it leaves a trace of light.
Children are encouraged to imagine themselves in the turtle's place and to draw a shape by walking through it, as the turtle would walk through it. Children are encouraged to imagine themselves in the turtle's place and to draw a shape by walking through it, as the turtle would walk through it.
@ -178,58 +191,54 @@ The above elements are, in my case, of the visual and some of the muscular type.
### Turtle space ### Turtle space
Turtles live on your computer screen. Turtles live on your computer screen.
Make sure you know the size of yours, since different computer screens have different dimensions.
Screen dimensions are generally stated in vertical (the y-axis direction) and horizontal (the x-axis direction) measurements.
Pinpoint the `x = 0` and `y = 0` point on your screen.
The turtle can be moved about the screen using cartesian x-y coordinates or turtle coordinates.
Cartesian commands send the turtle to a specific xy position on the screen, without regard to the turtle's current position.
Various `set` commands move the turtle through cartesian space.
Review them.
In the turtle reference system, all commands refer to the turtle's current position, not its final position.
The turtle is moved forward, backward, turned left or right in relation to where it is now. The turtle is moved forward, backward, turned left or right in relation to where it is now.
Review the turtle reference commands: `fd`, `bk`, `pu`, `pd`, `rt` `lt`. Review the [Ludus documentation for turtle commands](https://alea.ludus.dev/twc/ludus/src/branch/main/prelude.md#turtle-graphics), especially: `forward!`, `back!`, `penup!`, `pendown!`, `right!`, `left!`.
In the cartesian system, the destination is the important thing; in the turtle reference system, it's the trip. In the cartesian system, the destination is the important thing; in the turtle reference system, it's the trip.
### Making shapes ### Making shapes
Let's draw a simple shape using turtle reference commands. Let's draw a simple shape using turtle reference commands.
Suppose you would like the turtle to draw a square box located at the center of the screen (usually the origin of the coordinate system). Suppose you would like the turtle to draw a square box located at the center of the screen (usually the origin of the coordinate system).
Here are the steps you would take:
First, you would clear the screen by typing `cg` (clear graphics). First, you would think about the commands needed to walk the turtle through the shape.
The trutle now sits at 0,0 and faces straight up.
Second, you would think about the commands needed to walk the turtle through the shape.
_Use_ the turtle metaphor. _Use_ the turtle metaphor.
1. "OK turtle? Go forward 50 steps and turn right by 90 degrees. That completes the left side of the box." 1. "OK turtle? Go forward 50 steps and turn right by a quarter turn. That completes the left side of the box."
2. "Now, go forward another 50 steps and turn right by 90 degrees. That completes the top of the box." 2. "Now, go forward another 50 steps and turn right by a quarter turn. That completes the top of the box."
3. "Go forward yet another 50 steps and turn right again by 90 degrees. That completes the right side of the box." 3. "Go forward yet another 50 steps and turn right again by a quarter turn. That completes the right side of the box."
4. "Go forward another 50 units and turn right 90 degrees. That completes the 4. "Go forward another 50 units and turn right a quarter turn. That completes the
bottom edge of the box." bottom edge of the box."
That's it. That's it.
The turtle has walked around the four sides of a size 50 box, arriving back to where it started. The turtle has walked around the four sides of a size 50 box, arriving back to where it started.
These prose commands would translate into Ludus as: These prose commands would translate into Ludus as:
1. `forward! (50); right! (0.25)` ```
2. `forward! (50); right! (0.25)` forward! (50)
3. `forward! (50); right! (0.25)` right! (0.25)
4. `forward! (50); right! (0.25)`
forward! (50)
right! (0.25)
forward! (50)
right! (0.25)
forward! (50)
right! (0.25)
```
The third and last step would be to type these commands on the keyboard. The third and last step would be to type these commands on the keyboard.
And here is what you will see. And here is what you will see.
{{Figure 1: A simple box. Top of p. 10.}} {{Figure 1: A simple box. Top of p. 10.}}
> You might consider copying and pasting. That would certainly be easier! But actually, we encourage you to type out everything by hand. It gives you a kind of muscle memory for the language.
Great. Great.
This series of commands does indeed draw the square you wanted; but wasn't it tedious to type in all that stuff? This series of commands does indeed draw the square you wanted; but wasn't it tedious to type in all that stuff?
The command `forward! (50); right! (0.25)` was typed four times. The commands `forward! (50)` and `right! (0.25)` were typed four times.
Surely there is a shorthand method to repeat this line four times without typing four times. Surely there is a shorthand method to repeat this line four times without typing four times.
Review the `repeat` command; it is exactly what we need here. Thus the `repeat` form; it is exactly what we need here.
Try it. Try it.
``` ```
@ -239,22 +248,24 @@ repeat 4 {
} }
``` ```
Notice that the line `repeat 4 { forward! (50); right! (0.25) }` is a kind of operational definition of what a square is: a square is four sides, four `fd` commands, with each side joined at right angles to the next, the `RT 90` commands. Notice that this code is a kind of operational definition of what a square is: a square is four sides, four `forward! ()` calls, with each side joined at right angles to the next, the `right! (0.25)` calls.
That's tidy, but it's still a bore to type two lines each time you want a size 50 box on the screen. That's tidy, but it's still a bore to type two lines each time you want a size 50 box on the screen.
After all, you may want to draw 100 boxes. After all, you may want to draw 100 boxes.
Wouldn't it be convenient to be able to "tell" Ludus your definition of a square and then to give that definition a name? Wouldn't it be convenient to be able to "tell" Ludus your definition of a square and then to give that definition a name?
### Ludus procedures group commands under a single name ### Ludus functions group commands under a single name
You can group a series of Ludus commands together under a single name by writing a Ludus procedure. You can group a series of Ludus commands together under a single name by writing a Ludus function.
The name of the procedure is a shorthand for all commands included in it. The name of the function is a shorthand for all commands included in it.
Typing the name of the procedure tells Ludus to automatically execute each line of the procedure in turn, just as if you had typed them, one after another, on the keyboard. Typing the name of the function tells Ludus to automatically execute each line of the function in turn, just as if you had typed them, one after another, on the keyboard.
You can "tell" Ludus your definition of a square by creating a procedure called `square`. You can "tell" Ludus your definition of a square by creating a function called `box!`.
Ludus will "remember" your definition until you either erase it or turn off your computer. Ludus will "remember" your definition until you either erase it or turn off your computer.
Review the defining and editing procedures in your Ludus manual. Review the defining and editing functions in your Ludus manual.
### Shapes defined and drawn by procedures > You will notice that all the function names we have used so far end with an exclamation point. These are part of the name of the function, but they don't mean anything special to Ludus. They do, however, mean something special to Ludus programmers: this function is a command. It makes something happen. Later on in this chapter, we will meet a few different kinds of functions: arithmetic functions and predicates. Stay tuned.
Let's get on with writing the necessary procedure.
### Shapes defined and drawn by functions
Let's get on with writing the necessary function.
Here it is: Here it is:
``` ```
@ -266,14 +277,14 @@ fn box50! () -> {
} }
``` ```
Ludus will add `box50` to all its other commands. Ludus will add `box50!` to all its other commands.
Each time you type `box50`, the turtle will draw a square of size 50. Each time you type `box50!`, the turtle will draw a square of size 50.
The figure will be drawn at the turtle's current position on the screen. The figure will be drawn at the turtle's current position on the screen.
Unless you move the turtle to a different starting point, each time you type `box50`, the square produced will be on top of the previously drawn figure. Unless you move the turtle to a different starting point, each time you type `box50!`, the square produced will be on top of the previously drawn figure.
So move the turtle around to new positions and draw some more boxes. So move the turtle around to new positions and draw some more boxes.
But you can certainly be more imaginative than that. But you can certainly be more imaginative than that.
Create an interesting design on the screen using only the `box50` procedure and move commands. Create an interesting design on the screen using only the `box50!` function and move commands.
If you have a color screen, you might want to investigate the effects of changing the screen's background color and the color of the pen. If you have a color screen, you might want to investigate the effects of changing the screen's background color and the color of the pen.
Keep track of what you are doing in your notebook so that you can reconstruct your successful designs. Keep track of what you are doing in your notebook so that you can reconstruct your successful designs.
@ -297,14 +308,14 @@ Is one image more pleasing than the other? Why?
{{Figures 2 & 3: Wrapped boxes. Bottom of p. 12.}} {{Figures 2 & 3: Wrapped boxes. Bottom of p. 12.}}
### Generalizing procedures ### Generalizing functions
What about boxes of different sizes? What about boxes of different sizes?
You could edit the `box50!` procedure every time you wanted it to draw a different size box. You could edit the `box50!` function every time you wanted it to draw a different size box.
You could also define many `box`-like procedures, each to draw a different size box. You could also define many `box`-like functions, each to draw a different size box.
But that doesn't seem very efficient, does it? But that doesn't seem very efficient, does it?
After all, Ludus itself doesn't have a different `forward!` command for every possible length of line that you might wish the turtle to draw. After all, Ludus itself doesn't have a different `forward!` command for every possible length of line that you might wish the turtle to draw.
There is not a `forward!-10` command for drawing lines of length 10 and a `forward!-43` command for drawing them 43 units long. There is not a `forward!10` command for drawing lines of length 10 and a `forward!43` command for drawing them 43 units long.
Ludus has a single `forward!` command. Ludus has a single `forward!` command.
Whenever `forward!` is used, an argument must be used in conjunction with it: the form is `forward!` argument. Whenever `forward!` is used, an argument must be used in conjunction with it: the form is `forward!` argument.
A single argument must be typed just after `forward!`. A single argument must be typed just after `forward!`.
@ -317,12 +328,12 @@ If we change the value of the argument, the line length changes accordingly.
Let's _generalize_ `box50!` in terms of box size as `forward!` is _general_ in terms of line length. Let's _generalize_ `box50!` in terms of box size as `forward!` is _general_ in terms of line length.
### Adding an argument to a procedure ### Adding an argument to a function
Define a new box procedure that has a size argument. Define a new box function that has a size argument.
The value of the argument will tell the box procedure how to go about its business of drawing boxes. The value of the argument will tell the box function how to go about its business of drawing boxes.
Changing the value of the argument will change the size of the box. Changing the value of the argument will change the size of the box.
You can now draw boxes of any size from, say, 1 unit to 5000 units. You can now draw boxes of any size from, say, 1 unit to 5000 units.
Use this example as a "pattern" for incorporating an argument into a procedure. Use this example as a "pattern" for incorporating an argument into a function.
``` ```
fn box! (edge) -> { fn box! (edge) -> {
@ -333,8 +344,8 @@ fn box! (edge) -> {
} }
``` ```
### Putting a demonsuation procedure together ### Putting a demonsuation function together
I am sure that by this time you have already designed some interesting patterns with various `box!` procedures. I am sure that by this time you have already designed some interesting patterns with various `box!` functions.
Some of these patterns you probably liked enough to print and glue into your notebook. Some of these patterns you probably liked enough to print and glue into your notebook.
Remember to include a few written comments on what you were trying to achieve. Remember to include a few written comments on what you were trying to achieve.
@ -345,15 +356,15 @@ How would you go about demonstrating this?
You could retype all the Ludus commands needed for your screen collage. You could retype all the Ludus commands needed for your screen collage.
What else could you do? What else could you do?
Remember that Ludus procedures can group a series of commands together under one name. Remember that Ludus functions can group a series of commands together under one name.
So let's define a new Ludus procedure that will run all the necessary steps to demonstrate your design. So let's define a new Ludus function that will run all the necessary steps to demonstrate your design.
Once defined, you will only have to type the demonstration procedure's name to have your designs redrawn on the screen. Once defined, you will only have to type the demonstration function's name to have your designs redrawn on the screen.
Your demonstration procedure will have no arguments; it will only do one thing: generate a specific design that you want to show to your friends. Your demonstration function will have no arguments; it will only do one thing: generate a specific design that you want to show to your friends.
If you wish to show off with several designs, you could design specific Ludus procedures to reproduce eachdesign. If you wish to show off with several designs, you could design specific Ludus functions to reproduce eachdesign.
Here is an example of such a demonstration procedure: Here is an example of such a demonstration function:
``` ```
& A demonstration procedure to show off a design & A demonstration function to show off a design
& produced from multiple boxes of different sizes. & produced from multiple boxes of different sizes.
fn demo! () -> { fn demo! () -> {
repeat 4 { repeat 4 {
@ -401,25 +412,25 @@ The real power, the real magic, which remains still in the hands of the elite, r
A little professorial, this. A little professorial, this.
But do you think he has a point? But do you think he has a point?
Go back to your demonstration procedures, the ones that have _no_ arguments so they do only _one_ thing. Go back to your demonstration functions, the ones that have _no_ arguments so they do only _one_ thing.
A procedure that does only one thing is like a box drawing procedure that draws only one size of box. A function that does only one thing is like a box drawing function that draws only one size of box.
One box doesn't encourage much thinking about the nature of boxes, does it? One box doesn't encourage much thinking about the nature of boxes, does it?
Can you use your demonstration procedures to explore the nature of a collage that intrigues you? Can you use your demonstration functions to explore the nature of a collage that intrigues you?
Play around with the collage demonstration procedure that draws it. Play around with the collage demonstration function that draws it.
Tinker a bit. Tinker a bit.
Maybe you could generalize the demonstration procedure by adding an argument. Maybe you could generalize the demonstration function by adding an argument.
To generalize a procedure is to stretch your thinking about what it does; and that's our appropriate work, too, because it respects the uniqueness of the Ludus art medium. To generalize a function is to stretch your thinking about what it does; and that's our appropriate work, too, because it respects the uniqueness of the Ludus art medium.
"It's the tinkering that counts, not the artiness." "It's the tinkering that counts, not the artiness."
Pin that phrase over your computer screen. Pin that phrase over your computer screen.
### Generalizing a procedure with arguments ### Generalizing a function with arguments
Let's go back to that `box!` procedure. Let's go back to that `box!` function.
Can we generalize it so that it draws triangle "boxes" as well as square ones? Can we generalize it so that it draws triangle "boxes" as well as square ones?
While we are at it, let's ask `box!` to draw boxes with any number of equal sides. While we are at it, let's ask `box!` to draw boxes with any number of equal sides.
These shapes will be regular polygons with n sides. These shapes will be regular polygons with n sides.
Why not call the generalized procedure `ngon!` for n-sided polygon? Why not call the generalized function `ngon!` for n-sided polygon?
Look again at the procedure BOX and decide what needs to be changed to turn `box!` into `ngon!`. Look again at the function BOX and decide what needs to be changed to turn `box!` into `ngon!`.
``` ```
fn box! (edge) -> { fn box! (edge) -> {
@ -436,17 +447,39 @@ We can replace the `repeat 4` with `repeat n`.
`forward! (edge)` will stay the same, but what about the angle you want the turtle to turn before drawing the next side? `forward! (edge)` will stay the same, but what about the angle you want the turtle to turn before drawing the next side?
It surely will be different for different sided polygons. It surely will be different for different sided polygons.
Generally, sketching focuses geometric thinking. Generally, sketching focuses geometric thinking.
Here are some walking plans that you might issue to the turtle to do NGON.s 7. Here are some walking plans that you might issue to the turtle to do `ngon`s.
{{Figure 5: Triangle, square, pentagon. Middle of p. 17.}} {{Figure 5: Triangle, square, pentagon. Middle of p. 17.}}
How can you calculate the angle indicated by the "?" for any n-sided polygon? How can you calculate the angle indicated by the "?" for any n-sided polygon?
Your geometric intuition should tell you that the turtle, after making `n` turns, will end up facing the same direction in which it started. Your geometric intuition should tell you that the turtle, after making `n` turns, will end up facing the same direction in which it started.
The amount of each individual turn will be 360 divided by thenumber of turns,or `360/n`. The amount of each individual turn is simply a fraction of a whole turn, or `1/n`.
(Now is the time to recall Ludus's mathematical capacities. Now is the time to understand Ludus's mathematical capacities.
Review the Ludus notation to add, subtract, multiply, and divide.) Consult the [Ludus documentation](https://alea.ludus.dev/twc/ludus/src/branch/main/prelude.md#math) for the functions to `add`, `sub`tract, `mult`iply, and `div`ide.
You are ready to write the new procedure `ngon!`: #### Angles in Ludus
Unlike high school geometry, Logo, or most other programming languages, Ludus measures its geometry in _turns_, rather than degrees or radians.
There are 360 degrees in a circle, and `2*pi` radians.
There is one single turn.
This is closer to lived geometry (turn a quarter turn to right, not 90 degrees).
It also simplifies much of the arithmetic here: we don't need to multiply or divide 360 or `2*pi` by anything.
For example, Ludus has a very useful function named `inv`, which calculates the _inverse_ of its argument: `inv (n)` returns `1/n`.
So in this case, the angle to turn is simple `inv (n)`.
#### Arithmetic in Ludus
Unlike many programming languages, Ludus does not have arithmetic operators.
In place of `2 + 2`, you will need to use the function `add`: `add (2, 2)`.
It will take some getting used to to read math expressed this way.
But it does offer a profound insight: nearly _everything_ in Ludus is a function call.
Addition isn't a special kind of thing.
In addition, notice that while we have seen `forward!` and `right!` and `box!`, `add`'s name does not end in an exclamation point.
That is because, unlike a command, which makes something happen, it instead gives something back to you: the computed value.
Commands are actually special functions; `add` is a normal function.
#### Back to `ngon!`
You are ready to write the new function `ngon!`:
``` ```
fn ngon! (n, edge) -> { fn ngon! (n, edge) -> {
@ -462,11 +495,11 @@ Notice that when `n` becomes large, the drawn figure becomes a circle (almost).
Carry out some clever visual experiments with `ngon`s. Carry out some clever visual experiments with `ngon`s.
### Some observations ### Some observations
Look back carefully at what we have done so far with procedure writing. Look back carefully at what we have done so far with function writing.
We started with a list of commands that drew a box of a single size. We started with a list of commands that drew a box of a single size.
Next, we grouped these commands into procedures that could draw boxes of several different sizes. Next, we grouped these commands into functions that could draw boxes of several different sizes.
Next, we generalized the `box!` procedure with an argument so that it could draw boxes of any size. Next, we generalized the `box!` function with an argument so that it could draw boxes of any size.
Finally, we produced a still more general procedure, `ngon!`, that can draw any regular, polygonal "box"--triangles, squares, pentagons, hexagons, and so on--of whatever size we wanted. Finally, we produced a still more general function, `ngon!`, that can draw any regular, polygonal "box"--triangles, squares, pentagons, hexagons, and so on--of whatever size we wanted.
### Making the simple more complete ### Making the simple more complete
What next? What next?
@ -506,9 +539,9 @@ I'll play with different values of `growth` to seewhat looks best.
Growth can be of two sorts: growth by a constant amount, or growth by a constant percentage. Growth can be of two sorts: growth by a constant amount, or growth by a constant percentage.
I'll try the latter. I'll try the latter.
That means that if I want polygons to grow by 10%, I define `growth` to be 1.10. That means that if I want polygons to grow by 10%, I define `growth` to be 1.10.
For a 90% shrinkage I would use `growth`=.9." For a 90% shrinkage I would use `growth`=0.9."
### A procedure to spin polygons ### A function to spin polygons
``` ```
fn spingon! (n, edge, angle, growth) -> { fn spingon! (n, edge, angle, growth) -> {
ngon! (n, edge) ngon! (n, edge)
@ -520,14 +553,15 @@ fn spingon! (n, edge, angle, growth) -> {
What is new here? What is new here?
First, there are more arguments than you have seen before. First, there are more arguments than you have seen before.
Every time you use `spingon`, you must remember to type four numbers after it. Every time you use `spingon!`, you must remember to type four numbers after it.
Second, this procedure is recursive: the last line in the `spingon` procedure asks that `spingon` be done again, but with some arguments changed. Second, this function is recursive: the last line in the `spingon!` function asks that `spingon!` be done again, but with some arguments changed.
For example, `(edge)` becomes `mult (edge, growth)` the first time recursion is called; and then `mult (edge, growth)` becomes `mult (mult (edge, growth), growth)` the For example, `edge` becomes `mult (edge, growth)` the first time recursion is called; and then `mult (edge, growth)` becomes `mult (mult (edge, growth), growth)` the second time recursion is called.
second time recursion is called. A recursive function is a function that uses itself as one of its parts.
A recursive procedure is a procedure that uses itself as one of its parts.
Will `spingon!` ever stop? Try it out. Will `spingon!` ever stop? Try it out.
> Then refresh the browser, since it will hang.
### Some spingons ### Some spingons
``` ```
spingon! (30, 2, inv (36), 1.02, 95) spingon! (30, 2, inv (36), 1.02, 95)
@ -545,7 +579,7 @@ spingon! (40, 120, 0, 0.25, 19)
{{Figure 8: Frame-ish spingons. Bottom of p. 21.}} {{Figure 8: Frame-ish spingons. Bottom of p. 21.}}
### Stopping recursive procedures ### Stopping recursive functions
One last procedural writing point to review. One last procedural writing point to review.
Having put `spingon!` into motion, how do you make it stop at a stage of your choosing? Having put `spingon!` into motion, how do you make it stop at a stage of your choosing?
You need to have a way of telling it how to stop. You need to have a way of telling it how to stop.
@ -569,23 +603,27 @@ fn spingon! (n, edge, angle, growth, times) -> {
} }
``` ```
> `lt?` is the "less than" function. It is another kind of function: a predicate. Predicates return a boolean value, either `true` or `false`. Their names, by convention, end with a question mark.
<!--
### Boring logistics ### Boring logistics
Before ending this chapter, let me give you a few more items to review from your Ludus language manual. Before ending this chapter, let me give you a few more items to review from your Ludus language manual.
The topic that gives most students the most problems is one of the most boring things to talk about: file maintenance. The topic that gives most students the most problems is one of the most boring things to talk about: file maintenance.
So I won't talk about it. So I won't talk about it.
But please review how to save text material as files, how to retrieve material from files, how to erase files, how to catalog files, and how to print files. But please review how to save text material as files, how to retrieve material from files, how to erase files, how to catalog files, and how to print files.
Do the same review for storing and retrieving graphics information. Do the same review for storing and retrieving graphics information.
-->
### A note on the procedure presentation style used in this book ### A note on the function presentation style used in this book
I have tried to make the presentation of procedures in this book as readable as I have tried to make the presentation of functions in this book as readable as
possible. possible.
Here are several of my presentation rules. Here are several of my presentation rules.
First, the _many comments_ rule. First, the _many comments_ rule.
I have included wordy explanations in some of my procedures. I have included wordy explanations in some of my functions.
These comments begin with the Ludus command "`&`". These comments begin with the Ludus comment character, `&`.
There is, of course, no need for you to include thesecomments in your own version of my procedures. There is, of course, no need for you to include thesecomments in your own version of my functions.
However, it is a good idea for you to put comments in your own procedures. However, it is a good idea for you to put comments in your own functions.
Second, the _meaningful cluster_ rule. Second, the _meaningful cluster_ rule.
I often include extra parentheses to group like elements into a cluster. I often include extra parentheses to group like elements into a cluster.
@ -608,8 +646,11 @@ fn spingon! (n, edge, angle, growth, times) -> {
``` ```
Third, the _body structuring_ rule. Third, the _body structuring_ rule.
Procedures should be laid out nicely on the page without too much information on anyone line. Functions should be laid out nicely in the editor without too much information on any one line.
Long procedure statements should be divided up between lines to make them more readable. Long function statements should be divided up between lines to make them more readable.
Code blocks--those curly braces that group lines of code together--should always come with an increase in how indented lines are.
<!--
The special character "`-`" is used to indicate when a single Ludus statement has been continued from one line to the next. The special character "`-`" is used to indicate when a single Ludus statement has been continued from one line to the next.
Here is an example. Here is an example.
Notice that the Ludus material within the [repeat brackets] would have been difficult to read if the long statement had not been divided into several short lines. Notice that the Ludus material within the [repeat brackets] would have been difficult to read if the long statement had not been divided into several short lines.
@ -627,7 +668,8 @@ fn squiggle! (a, b, n) -> {
``` ```
The symbol "`-`" indicates, of course, that the return key should not be used becausethe Ludus statement continues. The symbol "`-`" indicates, of course, that the return key should not be used becausethe Ludus statement continues.
Consult your own Ludus manual for handling the problem of procedure layout. Consult your own Ludus manual for handling the problem of function layout.
-->
### Exercises ### Exercises
There are five exercises to explore before going on to the material of chapter 2. There are five exercises to explore before going on to the material of chapter 2.
@ -644,15 +686,15 @@ Seethe diagram below.
{{Figure 9: Polygons inscribed in dotted circles. Bottom of p. 24}} {{Figure 9: Polygons inscribed in dotted circles. Bottom of p. 24}}
Call the revised procedure `cngon!` for "**c**entered **NGON**." Call the revised function `cngon!` for "**c**entered **NGON**."
Two hints: First, ask yourself what arguments `cngon!` will need. Two hints: First, ask yourself what arguments `cngon!` will need.
This is another way to ask yourself what information must be given to `cngon!` so that it can go about its business of drawing centered `ngon`s. This is another way to ask yourself what information must be given to `cngon!` so that it can go about its business of drawing centered `ngon`s.
`cngon!` needs only two pieces of information, or two arguments: the number of sides of the polygon to be drawn and the radius of that polygon. `cngon!` needs only two pieces of information, or two arguments: the number of sides of the polygon to be drawn and the radius of that polygon.
That means that the first line of the new procedure will look like this: That means that the first line of the new function will look like this:
``` ```
cngon! (n, rad) cngon! (n, radius)
``` ```
Second, imagine yourself as the turtle. Second, imagine yourself as the turtle.
@ -670,7 +712,7 @@ You, as the turtle, begin your journey from position (1), the center of the prop
You are facing straight up. You are facing straight up.
Pick up your pen and move forward by the amount of the polygon's radius. Pick up your pen and move forward by the amount of the polygon's radius.
This is `rad`. This is `radius`.
This puts you in position (2). This puts you in position (2).
You now need to turn right by an amount that is labeled (angle) on the sketch (3). You now need to turn right by an amount that is labeled (angle) on the sketch (3).
@ -691,7 +733,7 @@ Put down the pen in preparation for drawing the polygon.
Diagram B: **Drawing the polygon**. Diagram B: **Drawing the polygon**.
You are at position (4) and ready to draw an n-sided polygon. You are at position (4) and ready to draw an n-sided polygon.
You can use the procedure `ngon!`. You can use the function `ngon!`.
But what arguments will you use? But what arguments will you use?
It needs some values for `n` and `edge`. It needs some values for `n` and `edge`.
Right? Right?
@ -699,9 +741,9 @@ Right?
Yes, but wait a minute. Yes, but wait a minute.
What should the value for `edge` be? What should the value for `edge` be?
You know the value of `n`, the number of sides of the polygon. You know the value of `n`, the number of sides of the polygon.
And you know the value of the new argument, `rad`. And you know the value of the new argument, `radius`.
What must the polygon's edge dimension be so that, after it is drawn, it has a radius equal to `rad`? What must the polygon's edge dimension be so that, after it is drawn, it has a radius equal to `radius`?
In other words, we need to be able to express `edge` in terms of `n` and `rad`. In other words, we need to be able to express `edge` in terms of `n` and `radius`.
OK. OK.
We know the problem, what we have to work on, but let's not stop yet. We know the problem, what we have to work on, but let's not stop yet.
Label the edge thing that must be calculated (edge). Label the edge thing that must be calculated (edge).
@ -719,30 +761,30 @@ This leaves you in position (8), pointing straight up.
Diagram D: **Returning to the center of the polygon**. Diagram D: **Returning to the center of the polygon**.
Pick up your pen and back down, by an amount equal to `rad`, to the polygon's center. Pick up your pen and back down, by an amount equal to `radius`, to the polygon's center.
Finally, put your pen down in preparationfor whatevermight comenext. Finally, put your pen down in preparationfor whatevermight comenext.
Note that you, as the turtle, have ended in the sameposition (9) as you began (1). Note that you, as the turtle, have ended in the sameposition (9) as you began (1).
### A turtle walk transfonned into a Ludus procedure (almost) ### A turtle walk transfonned into a Ludus function (almost)
No more words are necessary. No more words are necessary.
Here it is. Here it is.
``` ```
fn cngon! (n, rad) -> { fn cngon! (n, radius) -> {
penup! () penup! ()
forward! (rad) forward! (radius)
right! (::angle::) right! (angle)
pendown! () pendown! ()
ngon! (n, ::edge::) ngon! (n, edge)
left! (::angle::) left! (angle)
penup! () penup! ()
back! (rad) back! (radius)
pendown! () pendown! ()
} }
``` ```
The procedure is sketched. The function is sketched.
And we know what we know and what we don't. And we know what we know and what we don't.
The two amounts, (angle) and (edge), are still unknown. The two amounts, `angle` and `edge`, are still unknown.
To figure these bits will require a little geometry and trigonometry. To figure these bits will require a little geometry and trigonometry.
We might as well use this opportunity to review all the bits and pieces of polygons. We might as well use this opportunity to review all the bits and pieces of polygons.
@ -751,42 +793,52 @@ Use the following two diagrams in conjunction with the word and equation descrip
{{Figure 11: Geometry of `cngon`s. Bottom of p. 28.}} {{Figure 11: Geometry of `cngon`s. Bottom of p. 28.}}
The first problem we face is to find an expression for angle d in terms of n, the number of sides of the polygon. The first problem we face is to find an expression for angle `d` in terms of `n`, the number of sides of the polygon.
The second problem is to find an expression for the length of a polygon's edge, e, in terms of its radius, R, and n, the number of sides. The second problem is to find an expression for the length of a polygon's edge, `e`, in terms of its radius, `R`, and `n`, the number of sides.
In preparation for these two acts, let's look at all the angles associated with polygons. In preparation for these two acts, let's look at all the angles associated with polygons.
The _central angles_, labeled a, are easy. The _central angles_, labeled a, are easy.
They are each equal to 360/n. They are each equal to 1/n (or `inv (n)`).
The _external angles_, labeled c, are also equal to 360/n. The _external angles_, labeled `c`, are also equal to 1/n.
The external angle is the turning angle used in `ngon!`. The external angle is the turning angle used in `ngon!`.
What about the internal angles, labeled b. What about the internal angles, labeled `b`.
We need some work here: We need some work here:
```
(1) c = 1/n, (1) c = 1/n,
(2) c + b = 1/2. (2) c + b = 1/2.
```
Putting these two equations together and solving for b gives Putting these two equations together and solving for `b` gives
```
(3) b = 1/2 - 1/n. (3) b = 1/2 - 1/n.
```
We are now ready to handle the first problem: Find d in terms of n. We are now ready to handle the first problem: Find `d` in terms of `n`.
```
(4) d + b/2 = 1/2. (4) d + b/2 = 1/2.
```
Putting (3) and (4) together and solving for d gives Putting (3) and (4) together and solving for d gives
(5) d = 1/4 + 1/2n <---**First problem solved**. ```
(5) d = 1/4 + 1/2n <-- First problem solved.
```
OK, now look at the second problem: Find e in terms of R and n. OK, now look at the second problem: Find e in terms of R and n.
```
(6) sin (a/2) = (e/2)/R, (6) sin (a/2) = (e/2)/R,
(7) a = 1/n. (7) a = 1/n.
```
Putting (7) and (6) togetherand solving for e gives Putting (7) and (6) togetherand solving for e gives
(8) e = 2\*R\*sin(1/2n) <---**Second problem solved**. ```
(8) e = 2*R*sin(1/2n) <-- Second problem solved.
```
Review the following trig functions: sine, cosine, and tangent. Review the following trig functions: sine, cosine, and tangent.
What is ani arctangent? What is ani arctangent?
@ -798,26 +850,6 @@ Here's how far we have gotten with `cngon!`:
``` ```
fn cngon! (n, rad) -> { fn cngon! (n, rad) -> {
penup! ()
forward! (rad)
right! (::angle::)
pendown! ()
ngon! (n, ::edge::)
left! (::angle::)
penup! ()
back! (rad)
pendown! ()
}
```
Now we can replace `(angle)` and `(edge)` with the needed expressions.
Here is the finished `cngon`:
```
fn cngon! (n, rad) -> {
let angle = sub (inv (2), inv (n))
let edge = mult (2, rad, sin (inv (mult (2, n))))
penup! () penup! ()
forward! (rad) forward! (rad)
right! (angle) right! (angle)
@ -830,13 +862,33 @@ fn cngon! (n, rad) -> {
} }
``` ```
Now we can use `let` bindings to give `angle` and `edge` with the needed values, by translating our equations into Ludus code.
Here is the finished `cngon!`:
```
fn cngon! (n, radius) -> {
let angle = sub (inv (2), inv (n))
let edge = mult (2, radius, sin (inv (mult (2, n))))
penup! ()
forward! (radius)
right! (angle)
pendown! ()
ngon! (n, edge)
left! (angle)
penup! ()
back! (radius)
pendown! ()
}
```
### Lessons and tips ### Lessons and tips
When solving visual problems, like this `cngon!` thing, try to break the single big problem down into several smaller problems. When solving visual problems, like this `cngon!` thing, try to break the single big problem down into several smaller problems.
Solve each of the small problems in turn, and then plug the little solutions together to form one big solution. Solve each of the small problems in turn, and then plug the little solutions together to form one big solution.
#### Exercise 1.2 #### Exercise 1.2
Put together one or more `demo!` procedures that make imaginative use of the ideas presented and reviewed in this chapter. Put together one or more `demo!` functions that make imaginative use of the ideas presented and reviewed in this chapter.
Modify every procedure in the chapter. Modify every function in the chapter.
Make them act more strangely. Make them act more strangely.
You might want to think some more about the exercise, described above, of placing simple shapes on a blank field of paper to depict different feelings of balance or emotions. You might want to think some more about the exercise, described above, of placing simple shapes on a blank field of paper to depict different feelings of balance or emotions.
@ -858,10 +910,10 @@ Here are a few visual tips for Exercises 1.3 and 1.4:
{{Figure 13: `spincngon`s. Bottom of p. 32.}} {{Figure 13: `spincngon`s. Bottom of p. 32.}}
#### Exercise 1.5 #### Exercise 1.5
Design a Ludus procedure that puts polygons on the vertices of other polygons. Design a Ludus function that puts polygons on the vertices of other polygons.
Hint: look carefully at the body of `cngon!`. Hint: look carefully at the body of `cngon!`.
When does the turtle arrive at a polygon vertex? When does the turtle arrive at a polygon vertex?
Mark the vertex arrival place in the `cngon!` procedure. Mark the vertex arrival place in the `cngon!` function.
You might consider this location as the right spot to install some recursion: when the turtle arrives at any vertex, ask it to do another `cngon!` centered on that vertex. You might consider this location as the right spot to install some recursion: when the turtle arrives at any vertex, ask it to do another `cngon!` centered on that vertex.
This recursive drawing will place polygons on the vertices of polygons on the vertices of polygons. This recursive drawing will place polygons on the vertices of polygons on the vertices of polygons.
You will need to figure out a way of stopping the recursion machinery, or it will continue forever. You will need to figure out a way of stopping the recursion machinery, or it will continue forever.
@ -881,25 +933,10 @@ research.
7. Test it out with realistic and totally outlandish argument values 7. Test it out with realistic and totally outlandish argument values
### Notes for adaptation ### Notes for adaptation
* Don't use abbreviations everywhere!
* Stopping recursion looks different.
- This will be different once we get actors and Ludus runs in a different thread. Is this a prerequisite?
* Math is harder, since we don't have familiar arithmetic operators.
* A few places there are arbitrary degrees; figure out how to make this friendlier. * A few places there are arbitrary degrees; figure out how to make this friendlier.
- Throughout, replace degrees with turns.
* Consider a helper function, `double`, to simplify the math for `cngon!`.
* Procedure -> function, throughout.
* The canvas doesn't (currently) wrap, so the example of many squares with wrapping needs to be a bit different. * The canvas doesn't (currently) wrap, so the example of many squares with wrapping needs to be a bit different.
* Prepping the annotated SVGs will be a thing. * Prepping the annotated SVGs will be a thing.
- Do we want hand-drawn stuff? Consider using the iPad. - Do we want hand-drawn stuff? Consider using the iPad.
* This we do not need here:
- Appeals to a manual
- The `-` character to continue a line
- The discussion of x-y coordinates
* Things we do need that are absent (in no particular order): * Things we do need that are absent (in no particular order):
- `let` bindings
- M-expression math - M-expression math
- A discussion of turns instead of degrees
- A discussion of empty parens/function calls - A discussion of empty parens/function calls
- A discussion of bangs in names
- A discussion of question marks in names