Archive for October, 2009

List recursion code from class

Thursday, October 29th, 2009

Here is the list recursion code from class today.

Using the git DVCS with code-immersion

Thursday, October 29th, 2009

Note: This is totally unnecessary but potentially convenient in most situations. The only situation in which you really need to understand git is if you’d like to contribute code to the code-immersion package – which I’d love it if you did.

As you all probably know, code-immersion is hosted on a service called GitHub. This, contrary to potential expectations, is not simply a funny-sounding name for yet another web service. Rather, it’s a  funny-sounding name with some level of reason for yet another web service. The name comes from the distributed version control system (DVCS) the site is rooted in, called git. If you haven’t done much work with programming, you may not know what a version control system is; essentially, it’s a place to keep all the code so that it’s convenient for any number of programmers to grab and play with, without breaking anything permanently. It keeps track of changes and history and makes it easy to get, play with, and update code.

You can read about git at its own site, or ask me about it (in comments or by email or in person); the point of this post is really to say that, should you be interested, code-immersion is hosted in a git repository; if you have git, you can get it (clone, in git terminology) from git://github.com/ianmcorvidae/code-immersion.git and play with it in the usual ways (other than pushing back to github – to do that, talk to me or read up on how github itself  works!).

Simple file I/O

Wednesday, October 28th, 2009

If you want to read things from files into Scheme, or to write things to files from Scheme, there are a lot of built in procedures to use and a lot of approaches you could follow, but the simplest idea is to read and write single Scheme objects, which could be arbitrarily big things if you use nested lists. Here’s an example:

(define data
  '((here are some symbols (and also "a string"))
    ((2009 10 20 11 34)
     "Numbers in the car of the list of which I'm the cadr.")
    (more stuff)))

(define save-data
  (lambda ()
    (with-output-to-file "myData.txt"
      (lambda ()
        (print data))
      #:exists 'replace)))

(define read-data
  (lambda ()
    (with-input-from-file "myData.txt"
      (lambda ()
        (set! data (read))))))

Turtle graphics and list manipulation

Monday, October 26th, 2009

I’ve written a version of “turtle graphics” that is simpler and different than the versions built in to PLT Scheme, with the intention that it serve as a base for some list manipulation exercises. We will work with this in class soon. The code is linked here.

-Lee

Logic Function

Sunday, October 25th, 2009

Here’s the function I tried to show in class; I had put in a couple last minute fixes that actually ended up making it break more often, but now as far as I can tell it corresponds with sentential logic exactly, except that for coding reasons it requires parentheses around negated clauses, which sentential does not. The function is based on the more rigorous definition of sentential, which requires parentheses inserted with every connective (in practice, logicians often leave out the outermost parentheses).


;Determines if the argument is a well-formed formula of sentential logic with basic letters P-S.
;Example calls: (wff? 'P) (wff? '(P v Q)) (wff? '(~ (~ (P & (Q (R v S))))) all return #t
; (wff? 23) (wff? '(P Q v)) (wff? '(P v Q v R)) return #f


(define letters '(P Q R S))
(define connectives '(v & => ))
(define negated '(~P ~Q ~R ~S))


(define wff?
(lambda (formula)
(let ((letter? (lambda (a)
;asks if the argument is a basic letter of sentential
(if (or (member a letters)
(member a negated))
#t
#f))))
(cond
;these conditions check syntactic rules
((letter? formula)
#t)
((list? formula)
(cond
((equal? (cdr formula) '())
#f)
((equal? (cddr formula) '())
#f)
((if (or (and (and (wff? (car formula)) (and (wff? (third formula)) (eq? (cdddr formula) '())))
(member (second formula) connectives))
(and (equal? (car formula) '~) (and (wff? (second formula)) (eq? (cddr formula) '()))))
#t
#f))
(else #f)))
(else #f)))))

Animating several things at once

Saturday, October 24th, 2009

Now that several of you are making animated characters I’ve received a lot of questions about how to make several characters move at the same time. There are several ways to approach this, but one of the simplest and most popular is to think in terms of complete frames. The idea is to break up the animation process as follows:

loop for each time step:
  erase the whole screen
  draw everything where it should be for this time step
  delay for a bit, to let the viewer see the current frame
  change the positions of everything for the next time step

This means you have to keep track of the positions of everything somewhere (maybe in global variables), that you have to rewrite your character-drawing code to draw a single instance of the character in a single position (which should be easy), and that you have to separate out the code for changing the position of your character from step to step.

That main loop, by the way could be an iterative loop (maybe created with “for” or “do” or “while“) or it could be implemented with a recursive call.

Note that this “erase the whole screen” idea doesn’t play very nicely with the idea of having all of our characters animate at the same time on the same screen in class. That’s okay for now, but with a little more effort you could change your system to do this:

erase the whole screen
loop for each time step:
  draw everything where it should be for this time step
  delay for a bit, to let the viewer see the current frame
  erase all of the individual characters, based on where things are this time step
  change the positions of everything for the next time step

If you do this then you could later change your calls to “ellipse,” “rectangle,” “line,” etc. to calls to “send-code” that tell the server to call ellipse, rectangle, line, etc. And since you’d only be erasing the place where your last drawing was made there wouldn’t be any conflicts except when things actually overlap.

lissajous figures

Thursday, October 22nd, 2009

enter the x and y values (ratio is important), then phase, the RGB values
call: (lissajous x y phase R G B)

After the “better draw”, place this!

(define lissajous
  (lambda (Horizontal Vertical phase (Red 0) (Green 0) (Blue 0))
    (show-window)
    (for ((t (in-range 0 1000)))
      (let ((y (+ 230 (* 225 (sin (/ t Vertical)))))
            (x (+ 230 (* 225 (sin (/ (+ t phase ) Horizontal))))))
        (ellipse x y 12 12 Red Green Blue 1)
        (sleep/yield .00001)))))

Haz movement :3

Thursday, October 22nd, 2009

You *must* click on the new window before attempting to move, or it won’t move.

Have fun finding the rest of the keycodes.

touhou-scheme

luls, I has a arow kees.

Recursion for a certain amount of time

Tuesday, October 20th, 2009

I was asked about whether it was possible to use the time to terminate an otherwise endless recursion, and I thought the answer might interest other people as well:


Sure. There are a couple of ways.

If you are flexible enough in your interpretation of “time” and “how long it’s been running” then you could do something very simple by setting up a step counter, something like this:

(define ticks 0)

(define my-function
 (lambda ()
   (unless (>= ticks 40)
     (print '*) ;; or whatever else you want to do
     (set! ticks (+ ticks 1))
     (my-function))))

(my-function)

If you really mean clock time then you can use the function current-seconds. This takes no arguments and it “Returns the current time in seconds. This time is always an exact integer based on a platform-specific starting date (with a platform-specific minimum and maximum value).”

The upshot of this is that (current-seconds) will return a big number but the differences between its values in subsequent calls will reflect the number of seconds called. So you could do something like this:

(define starting-time (current-seconds))

(define print-stuff-for-5-seconds
 (lambda ()
   (print '*)
   (unless (> (- (current-seconds) starting-time) 4)
     (print-stuff-for-5-seconds))))

(print-stuff-for-5-seconds)

If you need more resolution there’s also (current-milliseconds).

Simple animation

Friday, October 16th, 2009

Once you have defined the better-draw stuff (see this post) you can do some simple animation by first doing some drawing, then erasing, then drawing again, etc. You should call sleep/yield between each draw and the next erase, both to allow the OS to actually draw the image and to make it stay visible for a bit before you erase it and redraw it elsewhere. Something like (sleep/yield 0.001) might be a good first stab (that’s supposed to sleep for 1/1000 of a second). There are of course fancier ways to make animations that will be smoother, etc., but this is simple and can be fun.

As an example, let’s first define a procedure that draws a guy:

(define draw-guy
  (lambda (x y)
    (ellipse x y 50 50 88 156 174 1.0)
    (ellipse (+ x 15) (+ y 10) 10 10 20 50 150 1.0)
    (ellipse (+ x 30) (+ y 10) 10 10 20 50 150 1.0)
    (ellipse (+ x 12) (+ y 25) 30 15 220 50 50 1.0)))

To run this you first want to show the window — (show-window) — and if you’ve previously drawn in it clear it — (clear). Then call (draw-guy).

Now let’s write a procedure to erase the guy. Notice that I make this circle a little bigger, because the “smoothing” in the drawing code, which gets rid of jaggies around circles, etc., “leaks” a little bit of color into adjacent pixels:

(define erase-guy
  (lambda (x y)
    (ellipse (- x 5) (- y 5) 60 60 255 255 255 1.0)))

Now I can make a guy move in a diagonal line using a “for” loop like this:

(define move-guy
  (lambda ()
    (for ((n (in-range 0 100)))
      (draw-guy (* n 2) (* n 3))
      (sleep/yield 0.01)
      (unless (>= n 99)
        (erase-guy (* n 2) (* n 3))))))

Again, you should show and clear the window, and then call (move-guy).

Of course we can move him in fancier ways too, by doing something like this:

(define wavy-guy
  (lambda ()
    (for ((x (in-range 0 500)))
      (let ((y (+ 200 (* 200 (sin (/ x 50.0))))))
      (draw-guy x y)
      (sleep/yield 0.0005)
      (unless (>= x 499)
        (erase-guy x y))))))