Coder Social home page Coder Social logo

clojure-turtle's Introduction

clojure-turtle

clojure-turtle is a Clojure library that implements the Logo programming language in a Clojure context. Quil is used for rendering.

Logo is a simple language that is useful in introducing programming to beginners, especially young ones. Logo also happens to be a dialect of Lisp. clojure-turtle tries to maintain those beneficial aspects of Logo while using Clojure and Clojure syntax. The goal is to make learning programming and/or Clojure easier by disguising powerful concepts with fun!

Artifacts

clojure-turtle artifacts are released to Clojars.

If you are using Maven, add the following repository definition to your pom.xml:

<repository>
  <id>clojars.org</id>
  <url>http://clojars.org/repo</url>
</repository>

The Most Recent Release

With Leiningen:

[com.google/clojure-turtle "0.3.0"]

With Maven:

<dependency>
  <groupId>com.google</groupId>
  <artifactId>clojure-turtle</artifactId>
  <version>0.3.0</version>
</dependency>

Installation

First, install Leiningen.

Second, run a REPL session that has clojure-turtle loaded inside it. This can be done in a couple of ways:

Usage

Load the clojure-turtle.core namespace.

(use 'clojure-turtle.core)
; WARNING: repeat already refers to: #'clojure.core/repeat in namespace: user, being replaced by: #'clojure-turtle.core/repeat
;=> nil

The symbol repeat is overridden to behave more like the Logo function, but the Clojure core function is still available as clojure.core/repeat.

Now load a new window that shows our Quil sketch using the new-window form. The sketch is where our turtle lives and operates.

user=> (new-window {:size [300 480]})
;=> #'user/example

forward, back, right, left

It's forward, back, right, and left as in Logo. Go forward and back by a length (in pixels). Right and left turn the turtle by an angle, in degrees. It's Clojure syntax, so 'executing commands' (function calls) are done within parentheses.

(forward 30)
;=> #<Atom@4c8829b7: {:y 29.99999999999997, :angle 90, :pen true, :x -1.3113417000558723E-6}>

(right 90)
; #<Atom@4c8829b7: {:y 29.99999999999997, :angle 0, :pen true, :x -1.3113417000558723E-6}>

repeat, all

repeat is like the Logo function, or like Clojure's repeatedly. Going from the Logo syntax to clojure-turtle's syntax for repeat, commands that are being repeated are put within parentheses notation. The square brackets that group the repeated commands are replaced with (all ... ). The equivalent of the Logo REPEAT 3 [FORWARD 30 RIGHT 90] would be

(repeat 3 (all (forward 30) (right 90)))
;=> #<Atom@4c8829b7: {:y -2.6226834249807383E-6, :angle 90, :pen true, :x -9.535951726036274E-7}>

Let's see how we can simplify this.

(def side (all (forward 30) (right 90)))
;=> #'user/side
(left 90)
;=> #<Atom@4c8829b7: {:y -2.6226834249807383E-6, :angle 180, :pen true, :x -9.535951726036274E-7}>

(repeat 4 side)
;=> #<Atom@4c8829b7: {:y -1.311341712550984E-5, :angle 180, :pen true, :x -4.76797586142362E-6}>

As you just saw above, we can take the instructions that we pass into repeat, give them a single name, and refer to that name to get the same effect.

Let's simplify further.

(def square (all (repeat 4 side)))
(left 90)
(square)

So given a named set of instructions, we can invoke the instructions by putting the name in parentheses just like we do for functions like forward, left, and repeat

(def square-and-turn (all (square) (left 90)))
(left 90)
(square-and-turn)

(left 45)
(repeat 4 square-and-turn)

penup, pendown, setxy, setheading

The turtle has a pen that it drags along where it goes, creating a drawing. We can pick the pen up and put the pen down when we need to draw unconnected lines. setxy also teleports the turtle without drawing. setheading turns the turtle in an exact direction.

(penup)
(forward 113)
(right 135)

(pendown)
(repeat 4 (all (forward 160) (right 90)))

(setxy -100 0)

(setheading 225)

clean, home

clean erases all drawing. home brings the turtle to its original position and direction.

(clean)

(home)

color

Color can be set for the turtle. A color is specified by a vector of size 1, 3, or 4.

A three-element color vector has 3 integers for the red, green, and blue components of the color (in that order) in the range 0 - 255. (See this page for examples of specifying color in terms of RGB values.)

(def octagon (all (repeat 8 (all (forward 30) (right 45))))) 
(color [0 0 255])
(octagon)

The turtle sprite (the triangle representing the turtle) will be drawn in the same color as the turtle's pen.

(repeat 12 (all (octagon) (right 30)))

We can also use our color value to fill the interior of shapes that we draw. To draw shapes will a fill color, we first have to indicate when we start and when we end drawing the shape. For that, we use the start-fill and end-fill commands. Every line segment that the turtle draws in between start-fill and end-fill is assumed to form the perimeter of the shape.

Let us define filled-octagon as the combination of commands to draw a filled octagon. In between the start-fill and end-fill that demarcate our fill shape, we will use our octagon function to draw the perimeter of the octagon that we want filled.

(def filled-octagon (all (start-fill) (octagon) (end-fill))) 

If a four-element color vector is given for a color, then the 4th value is known as the "alpha" value. In clojure-turtle, the alpha value is also an integer that ranges from 0 to 255. The value 0 represents full transparency, and 255 represents full opacity.

(color [255 255 0 100]) 

We will want to draw 4 octagons that overlap, so we will create a points vector of 4 x,y-coordinates from which we will start drawing each octagon.

(def points [[-11 -11] [-62 -11] [-36 14] [-36 -36]])

For now, let's retrieve only the first of the four points, set our position to that first point, and then draw our first octagon from there.

(let [point-1 (first points)
      x (first point-1)
      y (second point-1)]
  (setxy x y)
  (filled-octagon))

Next, we will draw our the remaining 3 octagons. Since we will perform similar actions in repetition, let's create a function to store the behavior we want to repeat.

(defn filled-octagon-from-point
  [point]
  (let [x (first point)
        y (second point)]
    (setxy x y)
    (filled-octagon)))

Given a point in the form [x y], the function filled-octagon-from-point will draw a filled octagon starting at (x,y). We label the positions (indices) of a vector starting from 0, so the 1st element is as position 0, the 3rd element is at position 2, and the 4th element is at position 3.

;; octagon starting from 2nd point:
(filled-octagon-from-point (second points))
;; ... from 3rd point:
(filled-octagon-from-point (nth points 2))
;; ... from 4th point:
(filled-octagon-from-point (nth points 3))

A color vector of size 1 creates a grayscale color ranging from black to white. The grayscale color is equivalent to using a 3-element RGB color vector where the values for red, green, and blue are the same.

(color [0])
(home)

wait and animation

We can use wait to make the turtle pause. The number passed to wait indicates how many milliseconds the turtle should wait (1 millisecond = 0.001 seconds = 1 / 1000 seconds).

(clean)
(home)
(def stop-and-go (all (forward 30) (wait 2000) (right 90) (forward 30)))
(stop-and-go)

Computers today are fast. If we use wait to slow them down, we can watch the turtle move and perceive motion.

(clean)
(home)

(defn slower-octagon
  []
  (repeat 8 (fn []
              (forward 30)
              (right 45)
              (wait 100))))
(repeat 12 (all (slower-octagon) (right 30)))

What happens when you combine wait with clean? If we repeatedly draw, wait, and clean images in a loop, we can create the effect of motion! See the Animation page for more information and examples.

What next?

clojure-turtle uses Quil, which uses Processing. clojure-turtle also has the full power and fun of Clojure available to it, too.

What do you get when you enter the following?

(defn square-by-length
  [side-length]
  (repeat 4 (all (forward side-length) (right 90))))

(square-by-length 10)
(square-by-length 20)
(def lengths [40 50 60])
(map square-by-length lengths)
(defn times-2
  [x]
  (* 2 x))

(right 90)
(map square-by-length (map times-2 lengths))

(right 90)
(->> lengths
     (map times-2)
     (map square-by-length))
(defn polygon-side
  [num-sides side-length]
  (forward side-length)
  (right (/ 360 num-sides)))

(defn polygon
  [num-sides side-length]
  (repeat num-sides (all (polygon-side num-sides side-length))))

(clean)
(right 180)
(polygon 5 20)

(def side-counts [6 7 8 10 12])
(def lengths (reverse [30 40 50 60 70]))
(map polygon side-counts lengths)
(defn rand-side
  []
  (forward (rand-int 50))
  (setheading (rand-int 360)))

(fn? rand-side)
(fn? side)

(clean)
(home)
(repeat 4 side)
(repeat 100 rand-side)

What possibilities exist when you incorporate the full power of Clojure? What can you create?

Using the ClojureScript Version

The same codebase in clojure-turtle can be compiled to JS and used in a JS runtime in addition to JVM bytecode. A demo of the JS version can be executed by first running the command:

lein figwheel

Where the output may look like:

$ lein figwheel
Figwheel: Starting server at http://localhost:3449
Figwheel: Watching build - dev
Compiling "demo/public/js/main.js" from ["src" "demo/src"]...
Successfully compiled "demo/public/js/main.js" in 16.311 seconds.
Launching ClojureScript REPL for build: dev
...

Then, in your browser, visit the URL in the terminal output from the command -- in this example, it is http://localhost:3449. You will see a webpage load with the Quil canvas containing the turtle. Back in your terminal, Figwheel will load a ClojureScript REPL that is connected to the webpage (more precisely, the browser REPL running in the webpage). In the ClojureScript REPL, run:

cljs.user=> (ns clojure-turtle.core)
cljs.user=> (require '[clojure-turtle.macros :refer-macros [repeat all]])

Now, the above Logo/clojure-turtle commands can be issued in the CLJS REPL as described above, with the result visible in the Figwheel-connected browser page.

Mailing List

Join the clojure-turtle mailing list to post questions and receive announcements.

How to Contribute

Interested in contributing code to the project? We would love to have your help!

Before you can contribute, you should first read the page on contributing and agree to the Contributor License Agreement. Signing the CLA can be done online and is fast. This is a one-time process.

Thereafter, contributions can be initiated through a pull request.

License

Distributed under the Apache 2 license.

Disclaimer

This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google.

Dependencies

Quil is distributed under the Eclipse Public License either version 1.0 (or at your option) any later version.

The official Processing.org's jars, used as dependencies of Quil, are distributed under LGPL and their code can be found on http://processing.org/

clojure-turtle's People

Contributors

atrus159 avatar austinschwartz avatar echeran avatar hairybreeches avatar nikai3d avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clojure-turtle's Issues

add recursion example

Add the typical Logo recursion example of a stick -> tree. Remember that you should "stop the recursion" (that is, have a no-op base case) when the size gets too small.

For fun, also try and make it brown and green!

add Leiningen plugin for new proj. template

It would be beneficial to have a Leiningen plugin that would create a new clojure-turtle project with all the correct dependencies and versions.

It's one less thing that the user has to think about. Quil itself and many other projects benefit from having an associated Leiningen template for a new project.

examples using core.async

Something that could show off the capabilities of Clojure to learners is core.async, which would give a taste of how Clojure makes concurrency easier.

It should be possible to have multiple turtles acting independently in a canvas, similar Rich Hickey's ants demo (https://youtu.be/hb3rurFxrZ8?t=49m50s), although we only have atoms (no refs) in clojure-turtle because it is preferable to have the same code work the same in CLJS and Java Clojure.

This concept is very much like NetLogo, for which there is already a set of materials built up around the concept.

Regardless of whether we attempt to create teaching materials that correspond to NetLogo, at least NetLogo would contain some nifty examples that are worth mimicking.

add doc on color

The main Readme should have screenshots and text to show the use of color to change the line stroke color and shape fill color.

Color is handled by Quil in different ways. As it's used by clojure-turtle, the user can either provide a grayscale value, RGB values, or RGBA values. All values are 0-255 (even the alpha value in RGBA). clojure-turtle takes in the color value as a vector.

event loop discrepancies between CLJ and CLJS

Based on work for issue #6, we have a wait fn that does what you would expect. But only in the CLJS REPL, and only when you try to mix wait and turtle commands, all of the waiting happens first, and all of the rendering happens at the end. As an example, see the difference in the following at the CLJS REPL:

(do (wait 3000) (forward 30) (wait 3000))
clojure-turtle.core=> (do (wait 3000) (println "hello") (wait 3000))

Perhaps the issue is due to how the rendering event loop in either Processing.js or the CLJS version of Quil is implemented. But for whatever reason, the issue is happening. It would be great to identify the problem and fix it if possible.

Doesn't work with deps.edn/clj toolchain?

Having trouble getting it to work with the official clj/clojure CLI.

% clj -Sdeps '{:deps {com.google/clojure-turtle {:mvn/version "0.3.0"}}}'                                                                                                                                                            20-04-10 - 16:43:22
Downloading: com/google/clojure-turtle/0.3.0/clojure-turtle-0.3.0.pom from clojars
Downloading: quil/quil/2.2.6/quil-2.2.6.pom from clojars
Downloading: quil/processing-core/2.2.1/processing-core-2.2.1.pom from clojars
Downloading: quil/processing-dxf/2.2.1/processing-dxf-2.2.1.pom from clojars
Downloading: quil/processing-pdf/2.2.1/processing-pdf-2.2.1.pom from clojars
Downloading: quil/jogl-all-fat/2.1.5/jogl-all-fat-2.1.5.pom from clojars
Downloading: quil/processing-js/1.4.8.2/processing-js-1.4.8.2.pom from clojars
Downloading: quil/gluegen-rt-fat/2.1.5/gluegen-rt-fat-2.1.5.pom from clojars
Downloading: quil/processing-dxf/2.2.1/processing-dxf-2.2.1.jar from clojars
Downloading: quil/gluegen-rt-fat/2.1.5/gluegen-rt-fat-2.1.5.jar from clojars
Downloading: quil/processing-js/1.4.8.2/processing-js-1.4.8.2.jar from clojars
Downloading: quil/jogl-all-fat/2.1.5/jogl-all-fat-2.1.5.jar from clojars
Downloading: com/google/clojure-turtle/0.3.0/clojure-turtle-0.3.0.jar from clojars
Downloading: quil/processing-pdf/2.2.1/processing-pdf-2.2.1.jar from clojars
Downloading: quil/processing-core/2.2.1/processing-core-2.2.1.jar from clojars
Downloading: quil/quil/2.2.6/quil-2.2.6.jar from clojars
Error building classpath. Could not find artifact bouncycastle:bctsp-jdk14:jar:138 in central (https://repo1.maven.org/maven2/)

add speak command?

I'm undecided on whether this functionality would be useful and in line with the simplicity of Logo, but here's the idea:

Have the turtle be able to print text to the screen.

Follow-on considerations for a such a feature include: enable configuring font type & size

use Quill.js for a CLJS REPL

Not to be confused with Quil is Quill.js, a JavaScript widget designed to be cross-platform and take advantage of native OS support for rendering.

Quill.js, at least on Mac OS X, supports some Unicode character sets well that other text area / REPL widgets do not support well.

It would be nice to swap in Quill.js for the REPL box once a webpage can be created that has the REPL widget for a CLJS REPL next to the Quil canvas that it controls.

round decimals to 2 places

When printing the turtle position in the REPL, we get full precision of the floating point. We only need 2 decimal places at most.

embed REPL & canvas into teaching materials

Because CLJS is self-hosted (you can compile CLJS code using CLJS -- no JVM required), it is possible to have a webpage that runs its own REPL. Also, it is possible to embed Quil sketches in a webpage. So it should be possible to have a webpage with a REPL next to the Quil canvas that it controls.

The Quil homepage contains examples of sketches that run. You can edit and run your own sketches online, too.

The Quil creator has also written about understanding the CLJS self-hosting features:
http://nbeloglazov.com/2016/03/05/getting-started-with-self-hosted-cljs-part-1.html
http://nbeloglazov.com/2016/03/07/getting-started-with-self-hosted-cljs-part-2.html
(a third part hasn't yet been published)

Examples of webpages that include their own CLJS REPL:
https://github.com/Lambda-X/replumb
https://github.com/yetanalytics/re-pl

Bug with the (clean) function

This may only manifest on my setup, so I need someone to confirm this, but when I use the (clean) function in the in the CLJC repl the drawing position is reset to HOME. The turtle icon remains in its position and will respond to commands normally, but the line drawn behind the turtle will be disconnected from the turtle, drawn as if I had used the (home) command. Below are screenshots:

1
2
3
4
5
6

I believe I did a clean download before running this so it should be in the most recent version

create a Java GUI with a REPL and canvas window

Create a Java GUI that contains a REPL but can also spawn a turtle graphics canvas.

This issue represents the Java version of the the issue in #11, which targets JavaScript.

There is a library for creating a REPL in a Java Swing GUI: https://github.com/alandipert/clj-swingrepl
And Seesaw makes Swing programming actually fun: https://github.com/daveray/seesaw

Creating a JS-targeted REPL as in #11 obviously has more relevance and reach, but having a Java version is better than not having one, all things being equal. At the time of this writing, neither exists, so deployment of clojure-turtle is still a bit 'manual'.

add animation examples

Come up with examples where you can create animations.

Once there is a wait fn, an animation in Logo can created by drawing a picture, calling wait, calling clean, and doing it over again with another picture.

An animation using Logo functions will need to handle looping, termination, and loop state that each loop's picture can use. The easiest way is probably (dotimes [i MAX-FRAMES] ...)

ensure turtle is opaque

Currently, the turtle sprite that represents the turtle is drawn in the same color as the currently-set color. It's good to get feedback on the hue of the color, but because opacity determined by the alpha value should be ignored so that the turtle always remains easy to see.

It would be nice to have a method that takes a color vector of size 1, 3, or 4 and returns a vector [r g b 255], maybe called make-opaque.

Then, the get-turtle-sprite can be modified so that the opaque version of the current color can be used.

create intro Clojure material using Logo

The following idea is on the basis that I've previously created a set of lessons in the style of a textbook and a 2 hr basic Clojure workshop among other teaching experiences...

When trying to introduce new people to Clojure (students new to programming, curious/interested experienced coworkers), they stop learning when they reach a point where the concept is too difficult/unfamiliar.

So far, there seem to be 2 groups I can think of: beginners in programming, and experienced programmers.

For the first group, Logo is a great way to learn. The key to engage such students once they reach mastery of basic Logo concepts and teach them more / more advanced programming concepts. Doing so in a gradual way, so as not to lose these learners, is one of the original motivating reasons for clojure-turtle. An approach that works for beginners should work for anyone.

For the second group, they look for an approach that makes them feeling like they're learning faster than average. They expect that their programming experience gives them a basis of comparison that they can use to intuit a new language's concepts, syntax, etc. as they bypass "beginner" material. Currently, if there is a stumbling block, it is that most programmers' experience currently does not yet include languages the look or behave like Clojure. The perceived gap here is a gentle intro to Clojure syntax and FP at a pace that assumes knowledge of basic programming concepts. One way to do this is to create a set of materials designed as, "Here's some concept implemented in Python, now here is the equivalent in Clojure".

Although the materials for the groups outline above would be different in nature, the structure of the lessons should be able to achieve convergence -- over time, the learners in the first group should eventually be able to reach the same mastery of Clojure as in the second group, and everyone should be equally satisfied.

add undo functionality

add a function that can pop off the last commmand given to a turtle

ex: (clean) (forward 10) (undo) would be functionally equivalent to (clean)

make turtle sprite centered over position

Instead of having the turtle sprite drawn exactly from the current position (running forward 10 creates an "arrow"), it provides more clarity to have the current position visible from inside the boundaries of the sprite.

add wait fn

Add a wait function that pauses for a given number of milliseconds. If the syntax for sleep in CLJS is different than it is in Java Clojure, then reader conditionals will need to be used.

Because Quil/Processing animates drawings on a loop and repeatedly calls the draw function, the current way that clojure-turtle does drawing may need to be made more intelligent as well. I currently don't foresee that extra work, nor any need to update a turtle's saved state of commands, which means the work here should be straightforward.

save the window contents to a file

It would nice to have a save fn that stores the screen contents to a file.

Trying to require quil.core and use the image output API wasn't sufficient. Or perhaps I'm missing something.

If Quil's save fns only work within sketch fns, it may mean clojure-turtle would need to wrap that behavior such that save only executes once, not every time Quil draws a new frame (ex: 30 or 60 times / second).

If this functionality is feasible, it should be feasible in Java Clojure. It may be possible in CLJS too, but I'm not sure what the differences would be between the standard REPL from a CLJ-bundled Jar and a npm-based CLJS REPL.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.