diff --git a/ClassMaterials/Module11/complex.java b/ClassMaterials/Module11/complex.java new file mode 100644 index 0000000..8193139 --- /dev/null +++ b/ClassMaterials/Module11/complex.java @@ -0,0 +1,129 @@ +// more complicated examples of inheritance and fields + +interface I { + int f (); + int g (); + int h (); +} + +class A implements I { + int i = 15; + int j = 20; + + A () { + System.out.println("calling constructor for A"); + show("i", i); show("j", j); + } + + // EFFECT: increments i + // RETURNS: the new value of i + j + + public int f () { + System.out.println("calling method f of class A"); + i = i + 1; + return (i + j); + } + + // RETURNS: mystery!! + + public int g () { + System.out.println("calling method g of class A"); + return (this.f() + 1); + } + + public int h () { + System.out.println("calling method g of class A"); + j = j + 10; + return (i - j); + } + + public void show (String str, int n) { + System.out.println(str + "=" + n); + } + + +} + +class B extends A implements I { + int k = 200; + + B () { + System.out.println("calling constructor for B"); + j = 100; + int n = this.h(); + show("i", i); show("j", j); show("k", k); + } + + public int g () { + System.out.println("calling method g of class B"); + return (i + j + k); + } + + public int h () { + System.out.println("calling method h of class B"); + j = j + 100; + return (super.g() + 30); + } + +} + + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + show("i", i); show("j", j); show("k", k); + } + + public int f () { + System.out.println("calling method f of class C"); + return (j - k); + } + + public int g () { + System.out.println("calling method g of class C"); + return (super.h() + 20); + } + + public int h () { + System.out.println("calling method h of class C"); + k = k + 20; + return (j + k); + } +} +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.h()", c1.h()); + + + } + + public static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} diff --git a/ClassMaterials/Module11/module11.zip b/ClassMaterials/Module11/module11.zip new file mode 100644 index 0000000..4821474 Binary files /dev/null and b/ClassMaterials/Module11/module11.zip differ diff --git a/ClassMaterials/Module11/simple.java b/ClassMaterials/Module11/simple.java new file mode 100644 index 0000000..7040627 --- /dev/null +++ b/ClassMaterials/Module11/simple.java @@ -0,0 +1,129 @@ +// simple example of inheritance of methods and fields + +interface I { + + // no purpose; these are just for illustration + int f (); + int g (); + int g1 (); + int h (); +} + +class A implements I { + int i; + int j; + + A () { + System.out.println("calling constructor for A"); + this.i = 15; + this.j = 20; + System.out.println("i = " + i + " j = " + j); + System.out.println(""); + } + + public int f () { + System.out.println("calling method f of class A"); + return (i + j); + } + + public int g () { + System.out.println("calling method g of class A"); + return (i + this.f()); + } + + public int g1 () { + System.out.println("calling method g1 of class A"); + return (i + f()); + } + + public int h () { + System.out.println("calling method h of class A"); + return (i - j); + } +} + +class B extends A implements I { + int k; + + B () { + System.out.println("calling constructor for B"); + k = 200; + System.out.println("i = " + i + " j = " + j + " k = " + k); + System.out.println(""); + } + + public int f (){ + return 1000; + } + + public int h () { + System.out.println("calling method h of class B"); + return (30 + super.g()); + } +} + +class C extends B implements I { + + C () { + System.out.println("calling constructor for C"); + j = 100; + } + + public int f () { + return (j - k); + } + + public int g () { + return (super.h() + 20); + } + + public int h () { + return (j + k); + } +} + +class Tests { + + public static void main (String[] args) { + + System.out.println("***Starting tests for class A***"); + + I a1 = new A(); + + show("a1.f()", a1.f()); + show("a1.g()", a1.g()); + show("a1.g1()", a1.g1()); + show("a1.h()", a1.h()); + + System.out.println("\n***Starting tests for class B***"); + + I b1 = new B(); + + show("b1.f()", b1.f()); + show("b1.g()", b1.g()); + show("b1.g1()", b1.g1()); + show("b1.h()", b1.h()); + + System.out.println("\n***Starting tests for class C***"); + + I c1 = new C(); + + show("c1.f()", c1.f()); + show("c1.g()", c1.g()); + show("c1.g1()", c1.g1()); + show("c1.h()", c1.h()); + + + } + + static void show (String str, int n) { + System.out.println(str + "=" + n + "\n"); + } + +} + + + + + + diff --git a/CourseMaps/module10.jpg b/CourseMaps/module10.jpg index f1de4e8..72c56e0 100644 Binary files a/CourseMaps/module10.jpg and b/CourseMaps/module10.jpg differ diff --git a/CourseMaps/module11.jpg b/CourseMaps/module11.jpg index 5b1e542..7de5016 100644 Binary files a/CourseMaps/module11.jpg and b/CourseMaps/module11.jpg differ diff --git a/CourseMaps/module12.jpg b/CourseMaps/module12.jpg index 9755504..63f551d 100644 Binary files a/CourseMaps/module12.jpg and b/CourseMaps/module12.jpg differ diff --git a/Efficiency2/ackermann3.html b/Efficiency2/ackermann3.html index 64c4728..665bc9d 100644 --- a/Efficiency2/ackermann3.html +++ b/Efficiency2/ackermann3.html @@ -9,7 +9,7 @@
ps11 was a small language that was used as an example in CS 5010 in + Spring 2017. As you will see in an upcoming slide, it had an +interpreter and two compilers. +
+ack (m, n) if m = 0 diff --git a/Efficiency2/gcPSZero.html b/Efficiency2/gcPSZero.html index b497f16..5245063 100644 --- a/Efficiency2/gcPSZero.html +++ b/Efficiency2/gcPSZero.html @@ -33,7 +33,7 @@need a more typical benchmark.
- The flight-scheduling problem posed by Problem Set 00, + The flight-scheduling problem posed as Problem Set 00 in Spring 2017, at the beginning of the semester, gives us a more typical benchmark. Because this is not a course on algorithms, diff --git a/Efficiency2/gcSpecialPleading.html b/Efficiency2/gcSpecialPleading.html index 4402cb6..623cae0 100644 --- a/Efficiency2/gcSpecialPleading.html +++ b/Efficiency2/gcSpecialPleading.html @@ -43,7 +43,7 @@
Many programmers take pride in their knowledge and skillful use of the programming language they know best. When confronted with empirical evidence showing their - favorite language do not always perform as well as + favorite language does not always perform as well as other languages, they may become defensive and resort to special pleading. diff --git a/Examples/09-1-UTCv1/UTC.java b/Examples/09-1-UTC/UTC.java similarity index 100% rename from Examples/09-1-UTCv1/UTC.java rename to Examples/09-1-UTC/UTC.java diff --git a/Examples/09-1-UTCv1/UTC1.java b/Examples/09-1-UTC/UTC1.java similarity index 100% rename from Examples/09-1-UTCv1/UTC1.java rename to Examples/09-1-UTC/UTC1.java diff --git a/Examples/09-1-UTCv1/UTC2.java b/Examples/09-1-UTC/UTC2.java similarity index 100% rename from Examples/09-1-UTCv1/UTC2.java rename to Examples/09-1-UTC/UTC2.java diff --git a/Examples/09-1-UTCv1/UTCs.java b/Examples/09-1-UTC/UTCs.java similarity index 100% rename from Examples/09-1-UTCv1/UTCs.java rename to Examples/09-1-UTC/UTCs.java diff --git a/Examples/09-1-basics.rkt b/Examples/09-1-basics.rkt deleted file mode 100644 index 25293e6..0000000 --- a/Examples/09-1-basics.rkt +++ /dev/null @@ -1,105 +0,0 @@ -#lang racket - -(require "extras.rkt") -(require rackunit) - -;; examples from Lesson 9.1 - -(define Interface1<%> - (interface () - foo ; -> Int - bar ; Int -> Int - baz ; Int -> Int - )) - - - -(define Class1% - (class* object% (Interface1<%>) - - (init-field x y r) ;; x,y,r : Int - - (super-new) ;; required magic - - ;; foo : -> Int - (define/public (foo) (+ x y)) - - ;; bar : Int -> Int - (define/public (bar n) (+ r n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - -(define Class2% - (class* object% (Interface1<%>) - - (init-field a b c) ; a, b, c : Int - - (super-new) - - ;; foo : -> Int - (define/public (foo) (+ a b)) - - ;; bar : Int -> Int - (define/public (bar n) (* c n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - -(define Class2a% - (class* object% (Interface1<%>) - - (init-field a b c) ; a, b, c : Int - - (field [a1 (- a)]) ; add a new field, initialized to -a - - (super-new) - - ;; foo : -> Int - ; (define/public (foo) (+ a b)) - (define/public (foo) (- b a1)) - - ;; bar : Int -> Int - (define/public (bar n) (* c n)) - - ;; baz : Int -> Int - (define/public (baz n) - (+ (send this foo) n)) - - )) - - - -(define obj1 (new Class1% [x 10][y 20][r 10])) -(define obj2 (new Class1% [x 15][y 35][r 5])) -(define obj3 (new Class2% [a 15][b 35][c 5])) -(define obj3a (new Class2a% [a 15][b 35][c 5])) - -(begin-for-test - - (check-equal? (send obj1 foo) 30) - (check-equal? (send obj2 foo) 50) - - (check-equal? (send obj1 bar 8) 18) - (check-equal? (send obj2 bar 8) 13) - - (check-equal? (send obj1 baz 20) 50) - (check-equal? (send obj2 baz 20) 70) - - (check-equal? (send obj2 bar 8) 13) - (check-equal? (send obj3 bar 8) 40) - - ;; foo is the only method that is different in Class2% and Class2a%. - (check-equal? (send obj3 foo) (send obj3a foo)) - - - ) - - - diff --git a/Examples/09-2-1-space-invaders-1.rkt b/Examples/09-2-1-space-invaders-1.rkt deleted file mode 100644 index 94f6b9f..0000000 --- a/Examples/09-2-1-space-invaders-1.rkt +++ /dev/null @@ -1,432 +0,0 @@ -#lang racket - -;; space-invaders-1.rkt - -;; the world will consist of a list of Widget<%>'s, and a tick -;; counter to indicate the current time. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; start with (run framerate). Typically: (run 0.25) - -;; Press "b" to drop a new bomb. -;; Bombs fall at a constant rate. - -;; Helicopter rises at a constant rate. -;; the helicopter is smoothly draggable - -;; there is no interaction between the helicopter and the bombs. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -;;; CONSTANTS - -(define CANVAS-WIDTH 200) -(define CANVAS-HEIGHT 400) - -(define EMPTY-CANVAS (empty-scene 200 400)) - -;; some arbitrary choices -(define BOMB-INITIAL-X 75) -(define BOMB-INITIAL-Y 0) -(define BOMB-INITIAL-RADIUS 10) - -(define HELI-INITIAL-X 100) -(define HELI-INITIAL-Y 300) - -(define NEW-BOMB-EVENT "b") -(define NEW-HELI-EVENT "h") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Data Definitions - -;; A Time is a NonNegative Integer - -;; A Widget is an object whose class implements the Widget<%> -;; interface. - -(define-struct world (widgets time)) - -;; A World is a (make-world ListOfWidget Time) -;; INTERP: (make-world lst t) represents a world containing the -;; widgets in lst at time t (in ticks). - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACEs - -;; Every object that lives in the world must implement the Widget<%> -;; interface. - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; initial-world : -> World -;; RETURNS: a world with a helicopter and no bombs -(define (initial-world) - (make-world - (list (new-heli)) - 0)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick world-after-tick rate) - (on-draw world-to-scene) - (on-key world-after-key-event) - (on-mouse world-after-mouse-event))) - -;; GP: Let's say the world should launch a new helicopter every 10 -;; ticks. How could we accomplish that? - -;; world-after-tick : World -> World -;; Use HOFC map on the Widget's in w -(define (world-after-tick w) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs) - (+ 1 t)))) - -;; world-to-scene : World -> Scene -;; Use HOFC foldr on the Widgets in w -(define (world-to-scene w) - (foldr - ;; Widget Scene -> Scene - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - (world-widgets w))) - - -;; world-after-key-event : World KeyEvent -> World -;; STRATEGY: Cases on kev -;; "b" creates a new bomb -;; "h" creates a new heli -;; other keystrokes are passed on to the widgets in the world. - -(define (world-after-key-event w kev) - (let ((objs (world-widgets w)) - (t (world-time w))) - (cond - [(key=? kev NEW-BOMB-EVENT) - (make-world - (cons (new-bomb t) objs) - t)] - [(key=? kev NEW-HELI-EVENT) - (make-world - (cons (new-heli) objs) - t)] - [else - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - (world-widgets w)) - t)]))) - -;; world-after-mouse-event : World Nat Nat MouseEvent -> World -;; STRATGY: Cases on mev -(define (world-after-mouse-event w mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down w mx my)] - [(mouse=? mev "drag") - (world-after-drag w mx my)] - [(mouse=? mev "button-up") - (world-after-button-up w mx my)] - [else w])) - -; World Nat Nat -> World -; STRATEGY: Use HOF map on the widgets in w -(define (world-after-button-down w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs) - t))) - - -(define (world-after-button-up w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs) - t))) - -(define (world-after-drag w mx my) - (let ((objs (world-widgets w)) - (t (world-time w))) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs) - t))) - -;; Challenge question: Could these 3 functions be generalized? - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Here's what a class definition looks like: - -;; classes are like data definitions. They should have a purpose statement -;; describing what information they are supposed to represent, and -;; interpretations of the fields describing the meaning of each piece of data. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We have two classes that implement Widget<%>: Heli% and Bomb% - -;; Helicopters start near the bottom of the screen and rise slowly. -;; They are selectable and draggable. - -;; Constructor template for Heli%: -;; (new Heli% [x Integer][y Integer] -;; [selected? Boolean][mx Integer][my Integer]) -;; the last 3 arguments are optional -;; Interpretation: An object of class Heli% represents a helicopter. - -(define Heli% - (class* object% (Widget<%>) - - ;; the init-fields are the values that may vary from one helicopter to - ;; the next. - - ; the x and y position of the center of the helicopter - (init-field x y) - - ; is the helicopter selected? Default is false. - (init-field [selected? false]) - - ;; if the helicopter is selected, the position of - ;; the last button-down event inside the helicopter, relative to the - ;; helicopter's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ; the helicopter's radius - (field [r 15]) - - ; image for displaying the helicopter - (field [HELI-IMG (circle r "outline" "blue")]) - ; the helicopter's speed, in pixels/tick - (field [HELISPEED -4]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after a tick - ;; a selected helicopter doesn't move. - ;; STRATEGY: Cases on selected? - (define/public (after-tick) - (if selected? - this - (new Heli% - [x x] - [y (+ y HELISPEED)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my]))) - - ;; after-key-event : KeyEvent -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after the - ;; given key event. - ;; DETAILS: a helicopter ignores key events - (define/public (after-key-event kev) - this) - - ; after-button-down : Integer Integer -> Widget - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in the helicopter - (define/public (after-button-down mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)]) - this)) - - ; after-button-up : Integer Integer -> Widget - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in the helicopter. - ; If the helicopter is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? false] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - ; after-drag : Integer Integer -> Widget - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the helicopter is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Heli% - [x (- mx saved-mx)] - [y (- my saved-my)] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this helicopter painted - ;; on it. - (define/public (add-to-scene scene) - (place-image HELI-IMG x y scene)) - - ;; in-heli? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this helicopter. - (define (in-heli? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr r))) - - ;; test methods, to probe the helicopter state. Note that we don't have - ;; a probe for radius. - ;; -> Int - (define/public (for-test:x) x) - ;; -> Int - (define/public (for-test:y) y) - ;; -> Boolean - (define/public (for-test:selected?) selected?) - - ;; -> (list Int Int Boolean) - (define/public (for-test:heli-state) (list x y selected?)) - - )) - -;; make-heli: -> Widget -;; GIVEN: no arguments -;; RETURNS: a new object of class Heli% near the bottom of the screen. - -;; NOTE: the contract says Widget, because our contracts are ALWAYS in -;; terms of interfaces (remember, a Widget is an object that -;; implements Widget<%>). The purpose statement gives the additional -;; information that the Widget returned by make-heli happens to be an -;; object of class Heli%. - -(define (new-heli) - (new Heli% [x HELI-INITIAL-X][y HELI-INITIAL-Y])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Bombs start near the top of the screen. They just fall. - -;; Constructor template for Bomb%: -;; (new Bomb% [x Integer][y Integer]) -;; Interpretation: An object of class Bomb% represents a bomb. - -;; make-bomb : Time -> Widget -;; GIVEN: A time t -;; RETURNS: a new object of class Bomb% near the top of the screen. -;; The time argument is ignored. - -;; SEE NOTE ABOVE ABOUT THIS CONTRACT - -(define (new-bomb t) - (new Bomb% [x BOMB-INITIAL-X][y BOMB-INITIAL-Y])) - -(define Bomb% - - (class* object% (Widget<%>) - (init-field x y) ; the bomb's x and y position - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ;; image for displaying the bomb - (field [BOMB-IMG (circle 10 "solid" "red")]) - ; the bomb's speed, in pixels/tick - (field [BOMB-SPEED 8]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A bomb like this one, but as it should be after a tick - ;; DETAILS: the bomb moves vertically by BOMB-SPEED - (define/public (after-tick) - (new Bomb% [x x][y (+ y BOMB-SPEED)])) - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this bomb painted - ;; on it. - (define/public (add-to-scene scene) - (place-image BOMB-IMG x y scene)) - - ;; the bomb doesn't have any other behaviors - (define/public (after-button-down mx my) this) - (define/public (after-drag mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-key-event kev) this) - - ;; test methods, to probe the bomb state. - (define/public (for-test:x) x) - (define/public (for-test:y) y) - - )) - - - - - - - - diff --git a/Examples/09-2-2-space-invaders-2.rkt b/Examples/09-2-2-space-invaders-2.rkt deleted file mode 100644 index 9cb1ed5..0000000 --- a/Examples/09-2-2-space-invaders-2.rkt +++ /dev/null @@ -1,472 +0,0 @@ -#lang racket - -;; space-invaders-2.rkt - -;; just like space-invaders-1, but in this version, the world will be an object - -;; the world will consist of a list of Widget<%>'s, and a tick -;; counter to indicate the current time. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; start with (run framerate). Typically: (run 0.25) - -;; Press "b" to drop a new bomb. -;; Bombs fall at a constant rate. - -;; Press "h" to start a new helicopter -;; Helicopter rises at a constant rate. -;; the helicopter is smoothly draggable - -;; there is no interaction between the helicopter and the bombs. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - -;;; CONSTANTS - -(define CANVAS-WIDTH 200) -(define CANVAS-HEIGHT 400) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - -;; some arbitrary choices -(define BOMB-INITIAL-X 75) -(define BOMB-INITIAL-Y 0) -(define BOMB-INITIAL-RADIUS 10) - -(define HELI-INITIAL-X 100) -(define HELI-INITIAL-Y 300) - -(define NEW-BOMB-EVENT "b") -(define NEW-HELI-EVENT "h") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Data Definitions - -;; A Time is a NonNegative Integer - -;; A Widget is an object whose class implements the Widget<%> -;; interface. - -;; A World is an object whose class implements the World<%> -;; interface. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; big-bang will communicate with the world through the World<%> -;; interface. - -(define World<%> - (interface () - - ; -> World - ; GIVEN: no arguments - ; RETURNS: the state of the world at the next tick - after-tick - - ; Integer Integer MouseEvent-> World - ; GIVEN: a location - ; RETURNS: the state of the world that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> World - ; GIVEN: a key event - ; RETURNS: the state of the world that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - )) - - -;; Every object that lives in the world must implement the Widget<%> -;; interface. - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; initial-world : -> World -;; RETURNS: a world with a helicopter and no bombs -(define (initial-world) - (make-world - (list (new-heli)) - 0)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (send w after-tick)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (send w after-key-event kev))) - (on-mouse - (lambda (w mx my mev) - (send w after-mouse-event mx my mev))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The World% class - -;; We will have only one class that implements World<%>: World% - -;; Constructor template for World%: -;; (new World% [objs ListOfWidget][t Time]) -;; Interpretation: An object of class World% takes signals from -;; big-bang and distributes them to its objects as appropriate. - - -;; make-world : ListOfWidget Time -> World -;; GIVEN: a list of widgets and a time -;; RETURNS: an object of class World% containing the given list of -;; widgets and time. -(define (make-world objs t) - (new World% [objs objs][t t])) - -(define World% - (class* object% (World<%>) - - (init-field objs) ; ListOfWidget - (init-field t) ; Time - - (super-new) - - ;; after-tick : -> World - ;; Use HOFC map on the Widget's in this World - - (define/public (after-tick) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs) - (+ 1 t))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets in this World - - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - objs)) - - - ;; after-key-event : KeyEvent -> World - ;; STRATEGY: Cases on kev - ;; "b" and "h" create new bomb and new helicopter; - ;; other keystrokes are passed on to the objects in the world. - - (define/public (after-key-event kev) - (cond - [(key=? kev NEW-BOMB-EVENT) - (make-world - (cons (new-bomb t) objs) - t)] - [(key=? kev NEW-HELI-EVENT) - (make-world - (cons (new-heli) objs) - t)] - [else - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - objs) - t)])) - - ;; after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATEGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs) - t)) - - - (define (world-after-button-up mx my) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs) - t)) - - (define (world-after-drag mx my) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs) - t)) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We have two classes of Widgets: Helicopters and Bombs - -;; Helicopters start near the bottom of the screen and rise slowly. -;; They are selectable and draggable. - -;; Constructor template for Heli%: -;; (new Heli% [x Integer][y Integer] -;; [selected? Boolean][mx Integer][my Integer]) -;; the last 3 arguments are optional -;; Interpretation: An object of class Heli% represents a helicopter. - - -;; unchanged from 09-2-1. -(define Heli% - (class* object% (Widget<%>) - - ;; the init-fields are the values that may vary from one helicopter to - ;; the next. - - ; the x and y position of the center of the helicopter - (init-field x y) - - ; is the helicopter selected? Default is false. - (init-field [selected? false]) - - ;; if the helicopter is selected, the position of - ;; the last button-down event inside the helicopter, relative to the - ;; helicopter's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ; the helicopter's radius - (field [r 15]) - - ; image for displaying the helicopter - (field [HELI-IMG (circle r "outline" "blue")]) - ; the helicopter's speed, in pixels/tick - (field [HELISPEED -4]) - - (super-new) - - ;; after-tick : Time -> Widget - ;; RETURNS: A helicopter like this one, but as it should be after a tick - ;; a selected helicopter doesn't move. - ;; STRATEGY: Cases on selected? - (define/public (after-tick) - (if selected? - this - (new Heli% - [x x] - [y (+ y HELISPEED)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my]))) - - ;; after-key-event : KeyEvent -> Widget - ;; RETURNS: A world like this one, but as it should be after the - ;; given key event. - ;; DETAILS: a helicopter ignores key events - (define/public (after-key-event kev) - this) - - ; after-button-down : Integer Integer -> Widget - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in the helicopter - (define/public (after-button-down mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)]) - this)) - - ; after-button-up : Integer Integer -> Widget - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in the helicopter. - ; If the helicopter is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-heli? mx my) - (new Heli% - [x x][y y] - [selected? false] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - ; after-drag : Integer Integer -> Widget - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the helicopter is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Heli% - [x (- mx saved-mx)] - [y (- my saved-my)] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my]) - this)) - - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this helicopter painted - ;; on it. - (define/public (add-to-scene scene) - (place-image HELI-IMG x y scene)) - - ;; in-heli? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this helicopter. - (define (in-heli? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr r))) - - ;; test methods, to probe the helicopter state. Note that we don't have - ;; a probe for radius. - ;; -> Int - (define/public (for-test:x) x) - ;; -> Int - (define/public (for-test:y) y) - ;; -> Boolean - (define/public (for-test:selected?) selected?) - - ;; -> (list Int Int Boolean) - (define/public (for-test:heli-state) (list x y selected?)) - - )) - -;; make-heli: -> Widget -;; GIVEN: no arguments -;; RETURNS: a new object of class Heli% near the bottom of the screen. - -;; NOTE: the contract says Widget, because our contracts are ALWAYS in -;; terms of interfaces (remember, a Widget is an object that -;; implements Widget<%>). The purpose statement gives the additional -;; information that the Widget returned by make-heli happens to be an -;; object of class Heli%. - -(define (new-heli) - (new Heli% [x HELI-INITIAL-X][y HELI-INITIAL-Y])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Bombs start near the top of the screen. They just fall. - -;; Constructor template for Bomb%: -;; (new Bomb% [x Integer][y Integer]) -;; Interpretation: An object of class Bomb% represents a bomb. - -;; make-bomb : Time -> Widget -;; GIVEN: A time t -;; RETURNS: a new object of class Bomb% near the top of the screen. -;; The time argument is ignored. - -;; SEE NOTE ABOVE ABOUT THIS CONTRACT - -(define (new-bomb t) - (new Bomb% [x BOMB-INITIAL-X][y BOMB-INITIAL-Y])) - -(define Bomb% - (class* object% (Widget<%>) - (init-field x y) ; the bomb's x and y position - - ;; private data for objects of this class. - ;; these can depend on the init-fields. - - ;; image for displaying the bomb - (field [BOMB-IMG (circle 10 "solid" "red")]) - ; the bomb's speed, in pixels/tick - (field [BOMB-SPEED 8]) - - (super-new) - - ;; after-tick : -> Widget - ;; RETURNS: A bomb like this one, but as it should be after a tick - ;; DETAILS: the bombcopter moves vertically by BOMB-SPEED - (define/public (after-tick) - (new Bomb% [x x][y (+ y BOMB-SPEED)])) - - ;; to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this bomb painted - ;; on it. - (define/public (add-to-scene scene) - (place-image BOMB-IMG x y scene)) - - ;; the bomb doesn't have any other behaviors - (define/public (after-button-down mx my) this) - (define/public (after-drag mx my) this) - (define/public (after-button-up mx my) this) - (define/public (after-key-event kev) this) - - ;; test methods, to probe the bomb state. - (define/public (for-test:x) x) - (define/public (for-test:y) y) - - )) - - - - diff --git a/Examples/09-2-AList-v1/AList.java b/Examples/09-2-AList-v1/AList.java new file mode 100644 index 0000000..c2ac4c4 --- /dev/null +++ b/Examples/09-2-AList-v1/AList.java @@ -0,0 +1,21 @@ +// An AList
is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/09-2-AList-v1/AList1.java b/Examples/09-2-AList-v1/AList1.java new file mode 100644 index 0000000..a16c9c9 --- /dev/null +++ b/Examples/09-2-AList-v1/AList1.java @@ -0,0 +1,73 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } +} + +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else + return rest.contains (key); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + +} diff --git a/Examples/09-2-AList-v1/AListTests.java b/Examples/09-2-AList-v1/AListTests.java new file mode 100644 index 0000000..9a25392 --- /dev/null +++ b/Examples/09-2-AList-v1/AListTests.java @@ -0,0 +1,86 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class AListTests { + + public static void main (String[] args) { + AList a0 = new EmptyAList (); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) + testsPassed = testsPassed + 1; + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (testsFailed > 0) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/09-2-UTCv2/UTC.java b/Examples/09-2-UTCv2/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/09-2-UTCv2/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/09-2-UTCv2/UTC1.java b/Examples/09-2-UTCv2/UTC1.java deleted file mode 100644 index df3be8a..0000000 --- a/Examples/09-2-UTCv2/UTC1.java +++ /dev/null @@ -1,80 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/09-2-UTCv2/UTC2.java b/Examples/09-2-UTCv2/UTC2.java deleted file mode 100644 index d0afb41..0000000 --- a/Examples/09-2-UTCv2/UTC2.java +++ /dev/null @@ -1,88 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 implements UTC { - - int h; // the hour in EST, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC2 (int h, int m) { - this.h = (h >= 5) ? (h - 5) : h + 19; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/09-2-UTCv2/UTCs.java b/Examples/09-2-UTCv2/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/09-2-UTCv2/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/09-3-1-shapes-functional.rkt b/Examples/09-3-1-shapes-functional.rkt deleted file mode 100644 index a310c6e..0000000 --- a/Examples/09-3-1-shapes-functional.rkt +++ /dev/null @@ -1,98 +0,0 @@ -#lang racket - -;; 09-3-shapes-functional.rkt - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -(define-struct my-circle (x y r color) #:transparent) -(define-struct my-square (x y l color) #:transparent) -(define-struct my-composite (front back) #:transparent) - -;; The #;transparent makes the fields of the structs visible for -;; printing and to equal? - -;; A Shape is one of -;; -- (make-my-circle Number Number Number ColorString) -;; -- (make-my-square Number Number Number ColorString) -;; -- (make-my-composite Shape Shape) - -;; interp: -;; (x,y) is position in pixels (of center of shape) -;; r is radius of circle in pixels -;; l is length of side of square, in pixels -;; c is color, expressed as a ColorString. -;; in my-composite, front is the shape in front, back is the shape in back. - -;; TEMPLATE -;; shape-fn : Shape -> ?? -#; -(define (shape-fn s) - (cond - [(my-circle? s) (... - (my-circle-x s) - (my-circle-y s) - (my-circle-r s) - (my-circle-color s))] - [(my-square? s) (... - (my-square-x s) - (my-square-y s) - (my-square-r s) - (my-square-color s))] - [(my-composite? s) (... - (shape-fn (my-composite-front s)) - (shape-fn (my-composite-back s)))])) - -;; weight : Shape -> Number -;; GIVEN: a shape -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. -;; STRATEGY: Structural Decomposition on s : Shape -(define (weight s) - (cond - [(my-circle? s) (* pi (my-circle-r s) (my-circle-r s))] - [(my-square? s) (* (my-square-l s) (my-square-l s))] - [(my-composite? s) (+ (weight (my-composite-front s)) - (weight (my-composite-back s)))])) - -;; add-to-scene : Shape Scene -> Scene -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. -;; STRATEGY: Structural Decomposition on s : Shape -(define (add-to-scene s scene) - (cond - [(my-circle? s) - (local - ((define IMG (circle (my-circle-r s) "solid" (my-circle-color s)))) - (place-image IMG - (my-circle-x s) - (my-circle-y s) - scene))] - [(my-square? s) - (local - ((define IMG (square (my-square-l s) "solid" (my-square-color s)))) - (place-image IMG - (my-square-x s) - (my-square-y s) - scene))] - [(my-composite? s) - ;; paint the back image first, then the front image - (add-to-scene (my-composite-front s) - (add-to-scene (my-composite-back s) - scene))])) - -(define EMPTY-CANVAS (empty-scene 200 100)) - - -(define s1 (make-my-circle 50 20 40 "red")) -(define s2 (make-my-square 80 70 40 "blue")) -(define s3 (make-my-composite s1 s2)) - -(begin-for-test - (check-= (weight s1) (* pi 1600) .1) - (check-equal? (weight s2) 1600) - (check-= (weight s3) (+ (* pi 1600) 1600) .1)) - - - diff --git a/Examples/09-3-2-shapes-separate-functions.rkt b/Examples/09-3-2-shapes-separate-functions.rkt deleted file mode 100644 index eecc62e..0000000 --- a/Examples/09-3-2-shapes-separate-functions.rkt +++ /dev/null @@ -1,102 +0,0 @@ -#lang scheme - -;; 09-4-shapes-separate-functions.rkt - -;; this version uses separate functions for dispatch and operation - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -(define-struct my-circle (x y r color) #:transparent) -(define-struct my-square (x y l color) #:transparent) -(define-struct my-composite (front back) #:transparent) - -;; A Shape is one of -;; -- (make-my-circle Number Number Number ColorString) -;; -- (make-my-square Number Number Number ColorString) -;; -- (make-my-composite Shape Shape) - -;; interp: -;; (x,y) is position in pixels (of center for circle, of UL corner for square) -;; r is radius of circle in pixels -;; l is length of side of square, in pixels -;; c is color, expressed as a ColorString. -;; in my-composite, front is the shape in front, back is the shape in back. - -;; weight : Shape -> Number -;; GIVEN: a shape -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. -;; STRATEGY: Use template for Shape -(define (weight s) - (cond - [(my-circle? s) (my-circle-weight s)] - [(my-square? s) (my-square-weight s)] - [(my-composite? s) (my-composite-weight s)])) - -;; my-circle-weight, my-square-weight, my-composite-weight : Shape -> Number -;; GIVEN: a shape -;; WHERE: the shape is of the specified variant -;; RETURNS: the weight of the shape, assuming that each shape weighs 1 -;; gram per pixel of area. - -(define (my-circle-weight s) (* pi (my-circle-r s) (my-circle-r s))) -(define (my-square-weight s) (* (my-square-l s) (my-square-l s))) -(define (my-composite-weight s) (+ (weight (my-composite-front s)) - (weight (my-composite-back s)))) - -;; add-to-scene : Shape Scene -> Scene -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. - -(define (add-to-scene s scene) - (cond - [(my-circle? s) (my-circle-add-to-scene s scene)] - [(my-square? s) (my-square-add-to-scene s scene)] - [(my-composite? s) (my-composite-add-to-scene s scene)])) - - -;; my-circle-add-to-scene, my-square-add-to-scene, -;; my-composite-add-to-scene : Shape Scene -;; GIVEN: A shape and a scene -;; WHERE: the shape is of the specified variant -;; RETURNS: a scene like the given one, but with the given shape -;; painted on it. -;; STRATEGY: Structural Decomposition on each struct -(define (my-circle-add-to-scene s scene) - (local - ((define IMG (circle (my-circle-r s) "solid" (my-circle-color s)))) - (place-image IMG - (my-circle-x s) - (my-circle-y s) - scene))) - -(define (my-square-add-to-scene s scene) - (local - ((define IMG (square (my-square-l s) "solid" (my-square-color s)))) - (place-image IMG - (my-square-x s) - (my-square-y s) - scene))) - -(define (my-composite-add-to-scene s scene) - ;; paint the back image first, then the front image - (add-to-scene (my-composite-front s) - (add-to-scene (my-composite-back s) - scene))) - -(define EMPTY-CANVAS (empty-scene 200 100)) - -(define s1 (make-my-circle 50 20 40 "red")) -(define s2 (make-my-square 80 70 40 "blue")) -(define s3 (make-my-composite s1 s2)) - -(begin-for-test - (check-= (weight s1) (* pi 1600) .1) - (check-equal? (weight s2) 1600) - (check-= (weight s3) (+ (* pi 1600) 1600) .1)) - - - - diff --git a/Examples/09-3-3-shapes-with-interfaces.rkt b/Examples/09-3-3-shapes-with-interfaces.rkt deleted file mode 100644 index 9eb7e0e..0000000 --- a/Examples/09-3-3-shapes-with-interfaces.rkt +++ /dev/null @@ -1,163 +0,0 @@ -#lang racket - -;; 09-3-shapes.rkt - -(require rackunit) -(require "extras.rkt") -(require 2htdp/image) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; A Tiny System for creating and drawing shapes on a canvas. - -;;; demo with (demo) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; We don't know what shapes there will be, but we know what -;; operations we will want on shapes. This is the shape interface: - -;;; INTERFACE: - -;; a Shape is an object of a class that implements Shape<%>. - -(define Shape<%> - (interface () - - ;; weight : -> Number - ;; RETURNS: the weight of this shape - weight - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - add-to-scene - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Classes -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; We will have a class for each kind of shape - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Circles - -;; Constructor Template for Circle%: -;; (new Circle% [x Integer][y Integer][r Integer][c ColorString]) -;; Interpretation: a circle on the canvas. - -(define Circle% - (class* object% (Shape<%>) - (init-field - x ; Integer, x pixels of center from left - y ; Integer, y pixels of center from top - r ; Integer, radius - c) ; ColorString - - (field [IMG (circle r "solid" c)]) - - (super-new) - - ;; for each method, we copy down the contract and purpose - ;; statement from the interface, with perhaps additional details - ;; relating to this class. - - ;; weight : -> Integer - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a circle - ;; STRATEGY: combine simpler functions - (define/public (weight) (* pi r r)) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a circle - ;; STRATEGY: call a more general function - (define/public (add-to-scene s) (place-image IMG x y s)) - - )) - -;; Constructor Template for Square%: -;; (new Square% [x Integer][y Integer][l Integer][c ColorString]) -;; Interpretation: a square parallel to sides of canvas - - -(define Square% - (class* object% (Shape<%>) - (init-field x ; Integer, x pixels of center from left - y ; Integer, y pixels of center from top - l ; Integer, length of one side - c) ; ColorString - - (field [IMG (rectangle l l "solid" c)]) - - (super-new) - - ;; weight : -> Real - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a square - ;; STRATEGY: combine simpler functions - (define/public (weight) (* l l)) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a square - ;; STRATEGY: call a more general function - (define/public (add-to-scene s) (place-image IMG x y s)) - - )) - -;; Constructor Template for Composite%: -;; a (new Composite% [front Shape][back Shape]) -;; Interpretation: a composite of front and back shapes - -(define Composite% - (class* object% (Shape<%>) - (init-field - front ; Shape, the shape in front - back ; Shape, the shape in back - ) - - (super-new) - - ;; all we know here is that front and back implement Shape<%>. - ;; we don't know if they are circles, squares, or other composites! - - ;; weight : -> Number - ;; RETURNS: the weight of this shape - ;; DETAILS: this shape is a composite - ;; STRATEGY: recur on the components - (define/public (weight) (+ (send front weight) - (send back weight))) - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this shape - ;; painted on it. - ;; DETAILS: this shape is a composite - ;; strategy: recur on the components - (define/public (add-to-scene scene) - (send front add-to-scene - (send back add-to-scene scene))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define EMPTY-CANVAS (empty-scene 200 100)) - -(define s1 (new Circle% [x 50][y 20][r 40][c "red"])) -(define s2 (new Square% [x 80][y 70][l 40][c "blue"])) -(define s3 (new Composite% [front s1][back s2])) - - -(begin-for-test - (check-= (send s1 weight) (* pi 1600) .1) - (check-equal? (send s2 weight) 1600) - (check-= (send s3 weight) (+ (* pi 1600) 1600) .1)) - -(define (demo) - (send s3 add-to-scene EMPTY-CANVAS)) diff --git a/Examples/09-4-testing.rkt b/Examples/09-4-testing.rkt deleted file mode 100644 index b6b5401..0000000 --- a/Examples/09-4-testing.rkt +++ /dev/null @@ -1,178 +0,0 @@ -#lang racket - -(require "extras.rkt") -(require rackunit) - -;; A StupidRobot is an object of any class that implements -;; StupidRobot<%> - -;; Interpretation: A StupidRobot represents a robot moving along a -;; one-dimensional line, starting at position 0. - -(define StupidRobot<%> - (interface () - - ;; a new StupidRobot<%> is required to start at position 0 - - ;; -> StupidRobot - ;; RETURNS: a Robot just like this one, except moved one - ;; position to the right - move-right - - ;; -> Integer - ;; RETURNS: the current x-position of this robot - get-pos - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Client Code of Interface - -;; move-right-by-distance : Robot<%> Nat -> Robot<%> -(define (move-right-by-distance r n) - (cond - [(zero? n) r] - [else (move-right-by-distance - (send r move-right) - (- n 1))])) - -;;; tests - -(begin-for-test - (local - ((define r0 (new-robot)) - ;; move r0 right twice - (define r1 (send (send r0 move-right) move-right))) - ;; get-pos should then return 2 - (check-equal? - (send r1 get-pos) - 2))) - -(begin-for-test - (local - ((define r0 (new-robot)) - (define r1 (move-right-by-distance r0 3))) - (check-equal? - (send r1 get-pos) - 3))) - -;; let's create a bunch of robots and see if our tests pass for all of them -(begin-for-test - (let ((the-robots (map (lambda (n) (new-robot)) '(1 2 3 4 5 6 7 8 9 10)))) - (map - (lambda (r) (let ((r1 (move-right-by-distance r 13))) - (check-equal? - (send r1 get-pos) - 13))) - the-robots))) - - -(begin-for-test - (let ((r1 (new Robot1%)) - (r2 (new Robot1%))) - (check-equal? r1 r2 "This is an expected failure"))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; Implementations - -;; Constructor Template for Robot1%: -;; (new Robot1% [x NonNegInt]) -;; x is optional; default is 0 - -(define Robot1% - (class* object% (StupidRobot<%>) - - (init-field [x 0]) - ;; interp: the position of the robot, initially 0 - - (super-new) - - (define/public (move-right) - (new Robot1% [x (+ x 1)])) - - (define/public (get-pos) - x) - - )) - -;; Constructor Template for Robot2%: -;; (new Robot2% [blerch NonNegInt]) -;; blerch is optional; default is 0 - -(define Robot2% - (class* object% (StupidRobot<%>) - - (init-field [blerch 0]) - ;; interp: the position of the robot. - - (super-new) - - (define/public (move-right) - (new Robot2% [blerch (+ blerch 1)])) - - (define/public (get-pos) - blerch) - - )) - -;; Constructor Template for Robot3%: -;; (new Robot3% [y NonNegInt]) -;; y is the negative of the position of the robot -;; y is optional; default is 0 - -(define Robot3% - (class* object% (StupidRobot<%>) - - (init-field [y 0]) - ;; interp: the negative of the position of the robot. - - (super-new) - - (define/public (move-right) - (new Robot3% [y (- y 1)])) - - ;; RETURNS: the x-position of the robot - (define/public (get-pos) - (- y)) - - )) - -;; Constructor Template for Robot4%: -;; (new Robot4% [y ListOfRacketValue]) -;; x is any Racket list whose length is equal to the position of the -;; robot. -;; x is optional; default is 0 - -(define Robot4% - (class* object% (StupidRobot<%>) - - (init-field [x empty]) - ;; Interp: - ;; a list whose length is equal to the position of the robot - - (super-new) - - (define/public (move-right) - (new Robot4% [x (cons 99 x)])) - - ;; RETURNS: the x-position of the robot - (define/public (get-pos) - (length x)) - - )) - -;; -> StupidRobot<%> -(define (new-robot) - (local - ((define i (random 3))) - (cond - [(= i 0) (new Robot1%)] - [(= i 1) (new Robot2%)] - [(= i 2) (new Robot3%)] - [(= i 3) (new Robot4%)]))) - - - - diff --git a/Examples/09-7-coding-standards.rkt b/Examples/09-7-coding-standards.rkt deleted file mode 100644 index 540e349..0000000 --- a/Examples/09-7-coding-standards.rkt +++ /dev/null @@ -1,40 +0,0 @@ -#lang racket - -;; illustrations for coding examples - -(define Foo<%> - (interface () - - ; -> Integer - ; purpose statement omitted... - m1 - - ; Bar -> Foo - ; purpose statement omitted... - add-bar)) - -(define Class1% - (class* object% (Foo<%>) - - (init-field ...) - (field [LOCAL-CONSTANT ...]) - (super-new) - - ; m1 : -> Integer - ; purpose statement omitted... - (define/public (m1) ...) - - ; add-bar : Bar -> Foo - (define/public (add-bar b) ...) - - ;; (define/public (method-not-in-interface ...) ...) - - - (define (private-function1 ...) ...) - (define (private-function2 ...) ...) - - ;; for-test:... methods don't need to be in the interface - - (define/public (for-test:test-fcn1 ...) ...) - - )) \ No newline at end of file diff --git a/Examples/10-1-Alist-v2-spec/AList.java b/Examples/10-1-Alist-v2-spec/AList.java new file mode 100644 index 0000000..a86e01b --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-1-Alist-v2-spec/ALists.java b/Examples/10-1-Alist-v2-spec/ALists.java new file mode 100644 index 0000000..547325f --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/ALists.java @@ -0,0 +1,25 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + // this generates a new EmptyAList object every time it is called. + public static AList empty () { + return new EmptyAList (); + } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-1-Alist-v2-spec/EmptyAlist.java b/Examples/10-1-Alist-v2-spec/EmptyAlist.java new file mode 100644 index 0000000..3170ec6 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString() { return "%"; } + +} diff --git a/Examples/10-1-Alist-v2-spec/NonEmptyAList.java b/Examples/10-1-Alist-v2-spec/NonEmptyAList.java new file mode 100644 index 0000000..08c6659 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/NonEmptyAList.java @@ -0,0 +1,54 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K otherKey) { + if (otherKey.equals (this.key)) + return true; + else + return rest.contains (otherKey); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () { + return ("[" + + this.key.toString() +":" + this.val.toString() + + "]" + this.rest.toString() + ); + } + + + +} diff --git a/Examples/10-1-Alist-v2-spec/README b/Examples/10-1-Alist-v2-spec/README new file mode 100644 index 0000000..25b7f4e --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/README @@ -0,0 +1,4 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist + diff --git a/Examples/10-1-Alist-v2-spec/SimpleChecks.java b/Examples/10-1-Alist-v2-spec/SimpleChecks.java new file mode 100644 index 0000000..3a645b0 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/SimpleChecks.java @@ -0,0 +1,38 @@ +class SimpleChecks { + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-1-Alist-v2-spec/Tests.java b/Examples/10-1-Alist-v2-spec/Tests.java new file mode 100644 index 0000000..4347fd3 --- /dev/null +++ b/Examples/10-1-Alist-v2-spec/Tests.java @@ -0,0 +1,92 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + checkTrue (a1.lookup ("x") == 1); + + checkTrue (a2.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + + checkTrue (a3.lookup ("x") == 1); + checkTrue (a3.lookup ("y") == 2); + checkTrue (a3.lookup ("z") == 3); + + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + System.out.println(a1.toString()); + System.out.println(a2.toString()); + System.out.println(a3.toString()); + System.out.println(a4.toString()); + + + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-1-UTCv3/UTC.java b/Examples/10-1-UTCv3/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/10-1-UTCv3/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/10-1-UTCv3/UTC1.java b/Examples/10-1-UTCv3/UTC1.java deleted file mode 100644 index df3be8a..0000000 --- a/Examples/10-1-UTCv3/UTC1.java +++ /dev/null @@ -1,80 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return UTCs.isEqual (this, t2); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return UTCs.hashCode (this); - } - - public String toString () { - return UTCs.toString (this); - } - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/10-1-UTCv3/UTC2.java b/Examples/10-1-UTCv3/UTC2.java deleted file mode 100644 index 72b5cbd..0000000 --- a/Examples/10-1-UTCv3/UTC2.java +++ /dev/null @@ -1,66 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 extends UTC1 implements UTC { - - // the h field inherited from UTC1 will not be used - // we will use the following h field instead - - int h; // the hour in EST, limited to [0,23] - - // the Java constructor - - UTC2 (int h, int m) { - super (h, m); // calls the constructor for UTC1 - this.h = (h >= 5) ? (h - 5) : h + 19; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - @Override - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // The minute, isEqual, equals, hashCode, and toString - // methods are inherited from UTC1. - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/10-1-UTCv3/UTCs.java b/Examples/10-1-UTCv3/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/10-1-UTCv3/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/10-1-communicating-objects.rkt b/Examples/10-1-communicating-objects.rkt deleted file mode 100644 index 40a97ea..0000000 --- a/Examples/10-1-communicating-objects.rkt +++ /dev/null @@ -1,190 +0,0 @@ -#lang racket - -(require rackunit) -(require "extras.rkt") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Balls Communicating with an external agent -;;; this is considered poor OO design -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Ball0 is an object of any class that implements Ball0<%> - -(define Ball0<%> - (interface () - ;; -> Integer - ;; return x, y coords of center and radius, all in pixels - get-x - get-y - get-r)) - -;; Constructor Template for Ball1%: -;; (new Ball1% [x Integer][y Integer][r Integer]) - -(define Ball0% - (class* object% (Ball0<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - (define/public (get-x) x) - (define/public (get-y) y) - (define/public (get-r) r))) - -;; Ball0 Ball0 -> Boolean -;; Do these two balls intersect? -;; This is an ordinary function, outside of any class. -(define (intersects? b1 b2) - (circles-intersect? - (send b1 get-x) (send b1 get-y) (send b1 get-r) - (send b2 get-x) (send b2 get-y) (send b2 get-r))) - -;; Would balls with these coordinates intersect? -(define (circles-intersect? x1 y1 r1 x2 y2 r2) - (<= - (+ (sqr (- x1 x2)) (sqr (- y1 y2))) - (sqr (+ r1 r2)))) - -(begin-for-test - - (check-true - (let ((ball1 (new Ball0% [x 0][y 0][r 10])) - (ball2 (new Ball0% [x 0][y 10][r 10]))) - (and - (intersects? ball1 ball2) - (intersects? ball2 ball1)))) - - (check-false - (let ((ball1 (new Ball0% [x 0][y 0][r 10])) - (ball2 (new Ball0% [x 20][y 10][r 10]))) - (or - (intersects? ball1 ball2) - (intersects? ball2 ball1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; BALLS COMMUNICATING BY PULL -;; computation gets done in this ball -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; A Ball1 is an object of any class that implements Ball1<%> - -(define Ball1<%> - (interface () - ;; -> Integer - ;; return x, y coords of center and radius, all in pixels - get-x - get-y - get-r - - ;; Ball1 -> Boolean - ;; Does this ball intersect the other one? - intersects? - )) - -;; Constructor Template for Ball1%: -;; (new Ball1% [x Integer][y Integer][r Integer]) - -(define Ball1% - (class* object% (Ball-Pull<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - - ;; Does the other ball intersect this one? - ;; STRATEGY: Ask the other ball for its data - (define/public (intersects? other-b) - (coordinates-intersect? - (send other-b get-x) - (send other-b get-y) - (send other-b get-r))) - - ;; Integer^3 -> Boolean - ;; GIVEN: the coordinates of some ball - ;; RETURNS: would that ball intersect this one? - ;; This is a private method (an ordinary function, but inside the - ;; class). Note that it refers to the fields of this object. - (define (coordinates-intersect? other-x other-y other-r) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr (+ r other-r)))) - - (define/public (get-x) x) - (define/public (get-y) y) - (define/public (get-r) r) - -)) - -(begin-for-test - - (check-true - (let ((ball1 (new Ball1% [x 0][y 0][r 10])) - (ball2 (new Ball1% [x 0][y 10][r 10]))) - (and - (send ball1 intersects? ball2) - (send ball2 intersects? ball1)))) - - (check-false - (let ((ball1 (new Ball1% [x 0][y 0][r 10])) - (ball2 (new Ball1% [x 20][y 10][r 10]))) - (or - (send ball1 intersects? ball2) - (send ball2 intersects? ball1))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; BALLS COMMUNICATING BY PUSH -;;; computation gets done in other-ball -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(define Ball2<%> - (interface () - - ;; not needed for this example! - ;; ;; -> Integer - ;; ;; return x, y coords of center and radius, all in pixels - ;; get-x - ;; get-y - ;; get-r - - ;; Ball2 -> Boolean - ;; does this ball intersect the other one? - intersects? - - ;; Integer^3 -> Boolean - ;; Would a ball with the given x,y,r intersect this one? - intersect-responder - - )) - -;; Constructor Template for Ball2%: -;; (new Ball2% [x Integer][y Integer][r Integer]) - -(define Ball2% - (class* object% (Ball-Push<%>) - (init-field x y r) ; interpretation omitted... - (super-new) - - ;; Ball2 -> Boolean - (define/public (intersects? other-b) - (send other-b intersect-responder x y r)) - - ;; Integer^3 -> Boolean - (define/public (intersect-responder other-x other-y other-r) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr (+ r other-r)))) - )) - - -(begin-for-test - - (check-true - (let ((ball1 (new Ball2% [x 0][y 0][r 10])) - (ball2 (new Ball2% [x 0][y 10][r 10]))) - (and - (send ball1 intersects? ball2) - (send ball2 intersects? ball1)))) - - (check-false - (let ((ball1 (new Ball2% [x 0][y 0][r 10])) - (ball2 (new Ball2% [x 20][y 10][r 10]))) - (or - (send ball1 intersects? ball2) - (send ball2 intersects? ball1))))) - - - diff --git a/Examples/10-2-Alist-v3-singletons/AList.java b/Examples/10-2-Alist-v3-singletons/AList.java new file mode 100644 index 0000000..a86e01b --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-2-Alist-v3-singletons/ALists.java b/Examples/10-2-Alist-v3-singletons/ALists.java new file mode 100644 index 0000000..91d4601 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/ALists.java @@ -0,0 +1,36 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +import java.util.NoSuchElementException; + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static AList empty () { + return (AList ) theEmptyAList; + } + + // // this generates a new EmptyAList object every time it is called. + // public static AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-2-Alist-v3-singletons/EmptyAlist.java b/Examples/10-2-Alist-v3-singletons/EmptyAlist.java new file mode 100644 index 0000000..1c88989 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java b/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java new file mode 100644 index 0000000..890737b --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/NonEmptyAList.java @@ -0,0 +1,45 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else + return rest.contains (key); + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-2-Alist-v3-singletons/README b/Examples/10-2-Alist-v3-singletons/README new file mode 100644 index 0000000..a23ac79 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/README @@ -0,0 +1,4 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern diff --git a/Examples/10-2-Alist-v3-singletons/Tests.java b/Examples/10-2-Alist-v3-singletons/Tests.java new file mode 100644 index 0000000..0d49c51 --- /dev/null +++ b/Examples/10-2-Alist-v3-singletons/Tests.java @@ -0,0 +1,77 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkFalse (a0.contains ("x")); + checkTrue (a3.contains ("z")); + checkTrue (a4.contains ("x")); + checkFalse (a4.contains ("b")); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + checkTrue (b2.lookup ("x") == 1); + checkTrue (b2.lookup ("y") == 2); + checkTrue (b4.lookup ("x") == 33); + checkTrue (b4.lookup ("y") == 44); + checkTrue (b4.lookup ("b") == 22); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-2-UTCv4/UTC.java b/Examples/10-2-UTCv4/UTC.java deleted file mode 100644 index a614ee9..0000000 --- a/Examples/10-2-UTCv4/UTC.java +++ /dev/null @@ -1,18 +0,0 @@ -// A UTC is an object of any class that implements UTC. -// -// Interpretation: A UTC represents a Universal Coordinated Time. - -interface UTC { - - // Returns the hour, between 0 and 23 inclusive. - - int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - boolean isEqual (UTC t2); -} diff --git a/Examples/10-2-UTCv4/UTC0.java b/Examples/10-2-UTCv4/UTC0.java deleted file mode 100644 index 04bd9be..0000000 --- a/Examples/10-2-UTCv4/UTC0.java +++ /dev/null @@ -1,43 +0,0 @@ -// Abstract base class for classes that implement the UTC interface. - -abstract class UTC0 implements UTC { - - // the Java constructor has no fields to initialize - // (all fields will be defined in concrete subclasses) - - UTC0 () { } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public abstract int hour (); - - // Returns the minute, between 0 and 59 inclusive. - - public abstract int minute (); - - // Returns true iff the given UTC is equal to this UTC. - - public boolean isEqual (UTC t2) { - return (this.hour() == t2.hour()) && (this.minute() == t2.minute()); - } - - // public methods that override methods inherited from Object - - public boolean equals (Object x) { - if (x instanceof UTC) { - UTC t2 = (UTC) x; - return isEqual (t2); - } - else return false; - } - - public int hashCode () { - return 100 * this.hour() + this.minute(); - } - - public String toString () { - return ((Integer) (100 * this.hour() + this.minute())).toString(); - } -} diff --git a/Examples/10-2-UTCv4/UTC1.java b/Examples/10-2-UTCv4/UTC1.java deleted file mode 100644 index 65ec056..0000000 --- a/Examples/10-2-UTCv4/UTC1.java +++ /dev/null @@ -1,59 +0,0 @@ -// Constructor template for UTC1: -// new UTC1 (h, m) -// Interpretation: -// h is the hour (between 0 and 23, inclusive) -// m is the minute (between 0 and 59, inclusive) - -class UTC1 extends UTC0 implements UTC { - - int h; // the hour, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC1 (int h, int m) { - this.h = h; - this.m = m; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { return h; } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // The isEqual, equals, hashCode, and toString - // methods are inherited from UTC0. - - // a main method for unit testing - - public static void main (String[] args) { - UTC1tests.main(args); - } -} - -// Unit tests for UTC1. - -class UTC1tests { - - public static void main (String[] args) { - UTC t1 = new UTC1 (15, 31); - UTC t2 = new UTC1 (14, 31); - UTC t3 = new UTC1 (15, 32); - UTC t4 = new UTC1 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC1 passed."); - } -} diff --git a/Examples/10-2-UTCv4/UTC2.java b/Examples/10-2-UTCv4/UTC2.java deleted file mode 100644 index bc1d49a..0000000 --- a/Examples/10-2-UTCv4/UTC2.java +++ /dev/null @@ -1,67 +0,0 @@ -// Constructor template for UTC2: -// new UTC2 (h, m) -// Interpretation: -// h is the UTC hour (between 0 and 23, inclusive) -// m is the UTC minute (between 0 and 59, inclusive) -// Representation: -// Internally, the hour is represented in Eastern Standard Time, -// which is five hours behind UTC. - -class UTC2 extends UTC0 implements UTC { - - int h; // the hour in EST, limited to [0,23] - int m; // the minute, limited to [0,59] - - // the Java constructor - - UTC2 (int h, int m) { - super (); // calls the constructor for UTC0 - this.h = (h >= 5) ? (h - 5) : h + 19; - } - - // public methods - - // Returns the hour, between 0 and 23 inclusive. - - public int hour () { - if (h < 19) - return h + 5; - else - return h - 19; - } - - // Returns the minute, between 0 and 59 inclusive. - - public int minute () { return m; } - - // The isEqual, equals, hashCode, and toString - // methods are inherited from UTC0. - - // a main method for unit testing - - public static void main (String[] args) { - UTC2tests.main(args); - } -} - -// Unit tests for UTC2. - -class UTC2tests { - - public static void main (String[] args) { - UTC t1 = new UTC2 (15, 31); - UTC t2 = new UTC2 (14, 31); - UTC t3 = new UTC2 (15, 32); - UTC t4 = new UTC2 (15, 31); - - assert t1.hour() == 15 : "wrong hour for t1"; - assert t1.minute() == 31 : "wrong minute for t1"; - - assert t1.isEqual (t1) : "isEqual says this doesn't equal this"; - assert t1.isEqual (t4) : "isEqual says this doesn't equal that"; - assert ! (t1.isEqual (t2)) : "isEqual true but hour different"; - assert ! (t1.isEqual (t3)) : "isEqual true but minute different"; - - System.out.println ("All unit tests of UTC2 passed."); - } -} \ No newline at end of file diff --git a/Examples/10-2-UTCv4/UTCs.java b/Examples/10-2-UTCv4/UTCs.java deleted file mode 100644 index 30660ae..0000000 --- a/Examples/10-2-UTCv4/UTCs.java +++ /dev/null @@ -1,145 +0,0 @@ -// In Java, it is often convenient to define static methods -// that deal with some interface type in a separate class -// that does not itself implement the interface. -// -// By convention, the name of that class is the plural of the -// name of the interface. -// -// For example: Collections is a class that defines static methods -// for the Collection type. - -import java.util.Random; - -// The UTCs class defines static methods for the UTC type. -// In particular, it defines a static factory method for creating -// values of the UTC type. - -public class UTCs { - - // Dynamic isEqual methods should delegate to this static method. - - public static boolean isEqual (UTC t1, UTC t2) { - return (t1.hour() == t2.hour()) && (t1.minute() == t2.minute()); - } - - // Dynamic hashCode methods should delegate to this static method. - - public static int hashCode (UTC t) { - return 100 * t.hour() + t.minute(); - } - - // Dynamic toString methods should delegate to this static method. - - public static String toString (UTC t) { - return ((Integer) (100 * t.hour() + t.minute())).toString(); - } - - // random number generator, to be used as a coin flip - - private static Random coinFlips = new Random(); - - // static factory method for creating a UTC - // GIVEN: the hour in [0,23] and the minute in [0,59] - // RETURNS: a UTC with that hour and minute - - public static UTC make (int h, int m) { - // flips a coin to decide whether to return an object - // of class UTC1 or UTC2 - - if (coinFlips.nextBoolean()) - return new UTC1 (h, m); - else - return new UTC2 (h, m); - } - - // main method for testing - - public static void main (String[] args) { - for (String arg : args) - System.out.println (arg); - UTCsTests.main (args); - } -} - -// Tests for UTC objects created by the static factory method in UTCs. - -class UTCsTests { - - public static void main (String[] args) { - - // We'll do these tests several times, to increase the - // probability that objects of different classes will be created. - - int NTESTS = 5; // how many times we'll run each test - - for (int i = 0; i < NTESTS; i = i + 1) { - UTC t0000 = UTCs.make (0, 0); // always test boundary cases - UTC t0059 = UTCs.make (0, 59); - UTC t2300 = UTCs.make (23, 0); - UTC t2359 = UTCs.make (23, 59); - UTC t1531 = UTCs.make (15, 31); // and test typical cases - - assert t0000.hour() == 0 : "wrong hour for t0000"; - assert t0000.minute() == 0 : "wrong minute for t0000"; - assert t0059.hour() == 0 : "wrong hour for t0059"; - assert t0059.minute() == 59 : "wrong minute for t0059"; - assert t2300.hour() == 23 : "wrong hour for t2300"; - assert t2300.minute() == 0 : "wrong minute for t2300"; - assert t2359.hour() == 23 : "wrong hour for t2359"; - assert t2359.minute() == 59 : "wrong minute for t2359"; - assert t1531.hour() == 15 : "wrong hour for t1531"; - assert t1531.minute() == 31 : "wrong minute for t1531"; - - assert t0000.isEqual(t0000) : "isEqual says t0000 != t0000"; - assert t0059.isEqual(t0059) : "isEqual says t0059 != t0059"; - assert t2300.isEqual(t2300) : "isEqual says t2300 != t2300"; - assert t2359.isEqual(t2359) : "isEqual says t2359 != t2359"; - assert t1531.isEqual(t1531) : "isEqual says t1531 != t1531"; - - assert t0000.isEqual(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.isEqual(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.isEqual(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.isEqual(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.isEqual(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.isEqual(t0059)) : "isEqual says t0000 = t0059"; - assert ! (t0059.isEqual(t2359)) : "isEqual says t0059 = t2359"; - assert ! (t2359.isEqual(t2300)) : "isEqual says t2359 = t2300"; - - // tests of the usual triumvirate - - assert t0000.equals(t0000) : "equals says t0000 != t0000"; - assert t0059.equals(t0059) : "equals says t0059 != t0059"; - assert t2300.equals(t2300) : "equals says t2300 != t2300"; - assert t2359.equals(t2359) : "equals says t2359 != t2359"; - assert t1531.equals(t1531) : "equals says t1531 != t1531"; - - assert t0000.equals(UTCs.make(0, 0)) : "t0000 != t0000"; - assert t0059.equals(UTCs.make(0, 59)) : "t0059 != t0059"; - assert t2300.equals(UTCs.make(23, 0)) : "t2300 != t2300"; - assert t2359.equals(UTCs.make(23, 59)) : "t2359 != t2359"; - assert t1531.equals(UTCs.make(15, 31)) : "t1531 != t1531"; - - assert ! (t0000.equals(t0059)) : "equals says t0000 = t0059"; - assert ! (t0059.equals(t2359)) : "equals says t0059 = t2359"; - assert ! (t2359.equals(t2300)) : "equals says t2359 = t2300"; - - assert ! (t0000.equals(null)) : "equals says t0000 = null"; - assert ! (t0059.equals("foo")) : "equals says t0059 = a string"; - - assert t0000.hashCode() == (UTCs.make(0, 0).hashCode()); - assert t0059.hashCode() == (UTCs.make(0, 59).hashCode()); - assert t2300.hashCode() == (UTCs.make(23, 0).hashCode()); - assert t2359.hashCode() == (UTCs.make(23, 59).hashCode()); - assert t1531.hashCode() == (UTCs.make(15, 31).hashCode()); - - assert t0000.toString().equals(UTCs.make(0, 0).toString()); - assert t0059.toString().equals(UTCs.make(0, 59).toString()); - assert t2300.toString().equals(UTCs.make(23, 0).toString()); - assert t2359.toString().equals(UTCs.make(23, 59).toString()); - assert t1531.toString().equals(UTCs.make(15, 31).toString()); - } - - System.out.println ("UTCs tests passed."); - } -} \ No newline at end of file diff --git a/Examples/10-2-ball-and-wall.rkt b/Examples/10-2-ball-and-wall.rkt deleted file mode 100644 index 85747a1..0000000 --- a/Examples/10-2-ball-and-wall.rkt +++ /dev/null @@ -1,450 +0,0 @@ -#lang racket - -;; 10-2-1-ball-and-wall.rkt - -;; the world will be an object with exactly two widgets: -;; a ball and a wall. - -;; In this version, the wall is draggable, but the ball is not. -;; The ball should bounce off the wall. - -;; The ball is told about the wall when it's created - -(require rackunit) -(require 2htdp/universe) -(require 2htdp/image) -(require "extras.rkt") - - -;; start with (run framerate). Typically: (run 0.25) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; CONSTANTS - -(define CANVAS-WIDTH 400) -(define CANVAS-HEIGHT 300) - -(define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) - - -(define INIT-BALL-X (/ CANVAS-HEIGHT 2)) -(define INIT-BALL-Y (/ CANVAS-WIDTH 3)) -(define INIT-BALL-SPEED 8) - -(define INITIAL-WALL-POSITION 300) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; INTERFACES - -;; A World is an object of any class that implements World<%> - -(define World<%> - (interface () - - ; -> World - ; GIVEN: no arguments - ; RETURNS: the state of the world at the next tick - after-tick - - ; Integer Integer MouseEvent-> World - ; GIVEN: a location - ; RETURNS: the state of the world that should follow the - ; given mouse event at the given location. - after-mouse-event - - ; KeyEvent -> World - ; GIVEN: a key event - ; RETURNS: the state of the world that should follow the - ; given key event - after-key-event - - ; -> Scene - ; GIVEN: a scene - ; RETURNS: a scene that depicts this World - to-scene - )) - - -;; A Widget is an object of any class that implements Widget<%> - -(define Widget<%> - (interface () - - ; -> Widget - ; GIVEN: no arguments - ; RETURNS: the state of this object that should follow at time t+1. - after-tick - - ; Integer Integer -> Widget - ; GIVEN: a location - ; RETURNS: the state of this object that should follow the - ; specified mouse event at the given location. - after-button-down - after-button-up - after-drag - - ; KeyEvent -> Widget - ; GIVEN: a key event and a time - ; RETURNS: the state of this object that should follow the - ; given key event - after-key-event - - ; Scene -> Scene - ; GIVEN: a scene - ; RETURNS: a scene like the given one, but with this object - ; painted on it. - add-to-scene - )) - -;; Additional method for Wall. - -;; A Wall is an object of any class that implements Wall<%>. -;; There will be only one such class - -(define Wall<%> - (interface (Widget<%>) - - ; -> Int - ; RETURNS: the x-position of the wall - get-pos - - )) - - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; initial-world : -> World -;; RETURNS: a world with -(define (initial-world) - (local - ((define the-wall (new Wall%)) - (define the-ball (new Ball% [w the-wall]))) - (make-world - (list the-wall the-ball)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -; run : PosReal -> World -; GIVEN: a frame rate, in secs/tick -; EFFECT: runs an initial world at the given frame rate -; RETURNS: the final state of the world -(define (run rate) - (big-bang (initial-world) - (on-tick - (lambda (w) (send w after-tick)) - rate) - (on-draw - (lambda (w) (send w to-scene))) - (on-key - (lambda (w kev) - (send w after-key-event kev))) - (on-mouse - (lambda (w mx my mev) - (send w after-mouse-event mx my mev))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The World% class - -;; In this example, the world will have exactly two widgets in it. -;; To get perfect marks on design, we would rewrite the World% class -;; to reflect this invariant to replace the ListOfWidget by two -;; init-fields. But this is a special situation for this example only, -;; so we don't take the effort to do this. - -; ListOfWidget -> World -(define (make-world objs) - (new World% [objs objs])) - -(define World% - (class* object% (World<%>) - - (init-field objs) ; ListOfWidget - - (super-new) - - ;; after-tick : -> World - ;; Use HOFC map on the Widgets in this World - (define/public (after-tick) - (make-world - (map - (lambda (obj) (send obj after-tick)) - objs))) - - ;; to-scene : -> Scene - ;; Use HOFC foldr on the Widgets in this World - (define/public (to-scene) - (foldr - (lambda (obj scene) - (send obj add-to-scene scene)) - EMPTY-CANVAS - objs)) - - ;; after-key-event : KeyEvent -> World - ;; STRATEGY: Pass the KeyEvents on to the objects in the world. - - (define/public (after-key-event kev) - (make-world - (map - (lambda (obj) (send obj after-key-event kev)) - objs))) - - ;; world-after-mouse-event : Nat Nat MouseEvent -> World - ;; STRATGY: Cases on mev - (define/public (after-mouse-event mx my mev) - (cond - [(mouse=? mev "button-down") - (world-after-button-down mx my)] - [(mouse=? mev "drag") - (world-after-drag mx my)] - [(mouse=? mev "button-up") - (world-after-button-up mx my)] - [else this])) - - ;; the next few functions are local functions, not in the interface. - - (define (world-after-button-down mx my) - (make-world - (map - (lambda (obj) (send obj after-button-down mx my)) - objs))) - - - (define (world-after-button-up mx my) - (make-world - (map - (lambda (obj) (send obj after-button-up mx my)) - objs))) - - (define (world-after-drag mx my) - (make-world - (map - (lambda (obj) (send obj after-drag mx my)) - objs))) - - )) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; The Ball% class - -;; A Ball is a (new Ball% [x Int][y Int][speed Int][w Wall]) -;; w is required; all others have default values - -(define Ball% - (class* object% (Widget<%>) - - (init-field w) ;; the Wall that the ball should bounce off of - - ;; initial values of x, y (center of ball) - (init-field [x INIT-BALL-X]) - (init-field [y INIT-BALL-Y]) - (init-field [speed INIT-BALL-SPEED]) - - ; is this selected? Default is false. - (init-field [selected? false]) - - ;; if this is selected, the position of - ;; the last button-down event inside this, relative to the - ;; ball's center. Else any value. - (init-field [saved-mx 0] [saved-my 0]) - - (field [radius 20]) - - (super-new) - - ;; after-tick : -> Ball - ;; state of this ball after a tick. A selected ball doesn't move. - (define/public (after-tick) - (if selected? this - (new Ball% - [x (next-x-pos)] - [y y] - [speed (next-speed)] - [selected? selected?] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]))) - - ;; -> Integer - ;; position of the ball at the next tick - ;; STRATEGY: ask the wall for its position and use that to - ;; calculate the upper bound for the ball's x position - (define (next-x-pos) - (limit-value - radius - (+ x speed) - (- (send w get-pos) radius))) - - ;; Number^3 -> Number - ;; WHERE: lo <= hi - ;; RETURNS: val, but limited to the range [lo,hi] - ;; EXAMPLES: - ;; (limit-value 10 20 30) = 20 - ;; (limit-value 10 5 30) = 10 - ;; (limit-value 10 100 30) = 30 - (define (limit-value lo val hi) - (max lo (min val hi))) - - ;; -> Integer - ;; RETURNS: the velocity of the ball at the next tick - ;; STRATEGY: if at the next tick, the ball will be at its limit, negate the - ;; velocity, otherwise return the velocity unchanged - (define (next-speed) - (if (or - (= (next-x-pos) radius) - (= (next-x-pos) (- (send w get-pos) radius))) - (- speed) - speed)) - - (define/public (add-to-scene s) - (place-image - (circle radius - "outline" - "red") - x y s)) - - ; after-button-down : Integer Integer -> Ball - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is in this - (define/public (after-button-down mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? true] - [saved-mx (- mx x)] - [saved-my (- my y)] - [w w]) - this)) - - ;; in-this? : Integer Integer -> Boolean - ;; GIVEN: a location on the canvas - ;; RETURNS: true iff the location is inside this ball. - (define (in-this? other-x other-y) - (<= (+ (sqr (- x other-x)) (sqr (- y other-y))) - (sqr radius))) - - ; after-button-up : Integer Integer -> Ball - ; GIVEN: the location of a button-up event - ; STRATEGY: Cases on whether the event is in this - ; If this is selected, then unselect it. - (define/public (after-button-up mx my) - (if (in-this? mx my) - (new Ball% - [x x][y y][speed speed] - [selected? false] - [saved-mx 127] - [saved-my 98] ; the invariant says that if selected? is - ; false, you can put anything here. - [w w]) - this)) - - ; after-drag : Integer Integer -> Ball - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the ball is selected. - ; If it is selected, move it so that the vector from the center to - ; the drag event is equal to (mx, my) - (define/public (after-drag mx my) - (if selected? - (new Ball% - [x (- mx saved-mx)] - [y (- my saved-my)] - [speed speed] - [selected? true] - [saved-mx saved-mx] - [saved-my saved-my] - [w w]) - this)) - - ;; the ball ignores key events - (define/public (after-key-event kev) this) - - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The Wall% class - -;; A Wall is (new Wall% [pos Integer] -;; [saved-mx Integer] -;; [selected? Boolean]) -;; all these fields have default values. - -(define Wall% - (class* object% (Wall<%>) - - (init-field [pos INITIAL-WALL-POSITION]) ; the x position of the wall - - ; is the wall selected? Default is false. - (init-field [selected? false]) - - ;; if the wall is selected, the x position of - ;; the last button-down event near the wall - ;; relative to the wall position - (init-field [saved-mx 0]) - - (super-new) - - ;; the extra behavior for Wall<%> - (define/public (get-pos) pos) - - ; after-button-down : Integer Integer -> Wall - ; GIVEN: the location of a button-down event - ; STRATEGY: Cases on whether the event is near the wall - ; RETURNS: A wall like this one, but marked as selected and with - ; the mouse position recorded. - (define/public (after-button-down mx my) - (if (near-wall? mx) - (new Wall% - [pos pos] - [selected? true] - [saved-mx (- mx pos)]) - this)) - - ; after-button-up : Integer Integer -> Wall - ; GIVEN: the location of a button-up event - ; RETURNS: a Wall like this one, but unselected - (define/public (after-button-up mx my) - (new Wall% - [pos pos] - [selected? false] - [saved-mx saved-mx])) - - ; after-drag : Integer Integer -> Wall - ; GIVEN: the location of a drag event - ; STRATEGY: Cases on whether the wall is selected. - ; DETAILS: If this wall is selected, returns a wall like this one, - ; except that the vector from its position to - ; the drag event is equal to saved-mx - (define/public (after-drag mx my) - (if selected? - (new Wall% - [pos (- mx saved-mx)] - [selected? true] - [saved-mx saved-mx]) - this)) - - - ;; add-to-scene : Scene -> Scene - ;; RETURNS: a scene like the given one, but with this wall painted - ;; on it. - (define/public (add-to-scene scene) - (scene+line scene pos 0 pos CANVAS-HEIGHT "black")) - - ;; is mx near the wall? We arbitrarily say it's near if its - ;; within 5 pixels. - (define (near-wall? mx) - (< (abs (- mx pos)) 5)) - - ;; the wall has no other behaviors - (define/public (after-tick) this) - (define/public (after-key-event kev) this) - - )) - diff --git a/Examples/10-3-Alist-v4-sorted/AList.java b/Examples/10-3-Alist-v4-sorted/AList.java new file mode 100644 index 0000000..a5283a4 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList ,V> { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-3-Alist-v4-sorted/ALists.java b/Examples/10-3-Alist-v4-sorted/ALists.java new file mode 100644 index 0000000..7551e51 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/ALists.java @@ -0,0 +1,35 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static ,V> AList empty () { + return (AList ) theEmptyAList; + } + + + // // this generates a new EmptyAList object every time it is called. + // public static AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-3-Alist-v4-sorted/EmptyAlist.java b/Examples/10-3-Alist-v4-sorted/EmptyAlist.java new file mode 100644 index 0000000..d50616e --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/EmptyAlist.java @@ -0,0 +1,36 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList ,V> implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + public String toString() {return "%";} + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + +} diff --git a/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java b/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java new file mode 100644 index 0000000..783c990 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/NonEmptyAList.java @@ -0,0 +1,64 @@ +// The object constructed by NonEmptyAlst(k,v,rest) represents an +// association list just like 'rest', except that the key k is mapped +// to the value v. Any other key is mapped to the value it had in 'rest'. + +class NonEmptyAList ,V> implements AList { + + private K key; // key for the first entry in this AList + private V val; // val for the first entry in this AList + private AList rest; // the other entries in this AList + + NonEmptyAList (K key, V val, AList rest) { + this.key = key; + this.val = val; + this.rest = rest; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + + // maintains the list in sorted order + // use <= so to maintain stable sort for duplicate keys :) + + public AList extend (K newKey, V newVal) { + + if (newKey.compareTo(this.key) <= 0) + return new NonEmptyAList (newKey, newVal, this); + else + return new NonEmptyAList + (this.key, + this.val, + this.rest.extend(newKey,newVal)); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K otherKey) { + if (otherKey.compareTo(this.key) < 0) {return false;} + else if (otherKey.equals (this.key)) + return true; + else + return rest.contains (otherKey); + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else + return rest.lookup (key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () { + return ("[" + + this.key.toString() +":" + this.val.toString() + + "]" + this.rest.toString() + ); + } + +} diff --git a/Examples/10-3-Alist-v4-sorted/README b/Examples/10-3-Alist-v4-sorted/README new file mode 100644 index 0000000..44c7230 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/README @@ -0,0 +1,5 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern +10-3 ADDS: keep keys in order diff --git a/Examples/10-3-Alist-v4-sorted/Tests.java b/Examples/10-3-Alist-v4-sorted/Tests.java new file mode 100644 index 0000000..f5f36b3 --- /dev/null +++ b/Examples/10-3-Alist-v4-sorted/Tests.java @@ -0,0 +1,95 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + checkTrue (a1.lookup ("x") == 1); + + checkTrue (a2.lookup ("x") == 1); + checkTrue (a2.lookup ("y") == 2); + + checkTrue (a3.lookup ("x") == 1); + checkTrue (a3.lookup ("y") == 2); + checkTrue (a3.lookup ("z") == 3); + + checkTrue (a4.lookup ("x") == 1); + checkTrue (a4.lookup ("y") == 4); + checkTrue (a4.lookup ("z") == 3); + + System.out.println(a1.toString()); + System.out.println(a2.toString()); + System.out.println(a3.toString()); + System.out.println(a4.toString()); + + checkFalse (a0.contains ("x"), "a0 should not contain x"); + checkTrue (a3.contains ("z"), "a3 should contain z"); + checkTrue (a4.contains ("x"), "a4 should contain x"); + checkFalse (a4.contains ("b"), "a4 should contain x"); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1, "a1(x) should equal 1"); + checkTrue (a2.lookup ("y") == 2, "a2(x) should equal 2"); + checkTrue (a4.lookup ("x") == 1, "a4(x) should equal 1"); + checkTrue (a4.lookup ("y") == 4, "a4(y) should equal 4"); + checkTrue (a4.lookup ("z") == 3, "a4(z) should equal 3"); + + checkTrue (b2.lookup ("x") == 1, "b2(x) should equal 1"); + checkTrue (b2.lookup ("y") == 2, "b2(y) should equal 2"); + checkTrue (b4.lookup ("x") == 33, "b4(x) should equal 33"); + checkTrue (b4.lookup ("y") == 44, "b4(y) should equal 44"); + checkTrue (b4.lookup ("b") == 22, "b4(b) should equal 22"); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + // System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-3-IMapV1/IMap.java b/Examples/10-3-IMapV1/IMap.java deleted file mode 100644 index 7088d4f..0000000 --- a/Examples/10-3-IMapV1/IMap.java +++ /dev/null @@ -1,18 +0,0 @@ -// An IMap is an object of any class that implements IMap . -// -// Interpretation: An IMap represents an immutable finite function -// from keys to values. -// -// IMap extends java.util.Map , so an IMap can be used -// as an unmodifiable Map . - -import java.util.Map; - -interface IMap extends Map { - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - IMap extend (K key, V value); -} diff --git a/Examples/10-3-IMapV1/IMapList.java b/Examples/10-3-IMapV1/IMapList.java deleted file mode 100644 index 19a813b..0000000 --- a/Examples/10-3-IMapV1/IMapList.java +++ /dev/null @@ -1,114 +0,0 @@ -// Constructor templates for IMapList : -// new IMapList (rktList) -// new IMapList () -// Interpretation: -// rktList is a RacketList -// containing the key/value pairs of the IMap -// where no key is the key for two different key/value pairs -// if rktList is omitted, creates an empty map - -import java.util.Map; -import java.util.Map.Entry; -import java.util.AbstractMap; -import java.util.AbstractMap.SimpleEntry; -import java.util.AbstractMap.SimpleImmutableEntry; - -import java.util.Set; -import java.util.AbstractSet; - -import java.util.Iterator; - -// Strategy, quoted from the documentation for AbstractMap: -// -// To implement an unmodifiable map, the programmer needs only to -// extend [the AbstractMap] class and provide an implementation -// for the entrySet method, which returns a set-view of the map's -// mappings. Typically, the returned set will, in turn, be -// implemented atop AbstractSet. This set should not support the -// add or remove methods, and its iterator should not support the -// remove method. - -class IMapList extends AbstractMap implements IMap { - - RacketList > entries; // set of key/value pairs - - // Java constructors - - IMapList () { - this.entries = RacketLists.empty(); - } - - IMapList (RacketList > entries) { - this.entries = entries; - } - - // public methods listed by IMap interface - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - - public IMap extend (K key, V value) { - Entry entry = new SimpleImmutableEntry (key, value); - return new IMapList (extended (entries, entry)); - } - - // public methods listed by Map interface - - // Returns a set of the key/value pairs in this Map. - - public Set > entrySet () { - return new IMapListSet (entries); - } - - // all other public methods are defined by AbstractMap - - // private help methods - - // Given a RacketList of entries and an entry with key k, - // returns a RacketList in which the given entry replaces - // any entry with key k or, if the given RacketList of entries - // contains no entry with key k, returns a RacketList with - // the given entry added to it. - // - // This method has no side effects. - - private RacketList > extended (RacketList > entries, - Entry entry) { - if (entries.isEmpty()) { - return entries.cons (entry); - } - if (entries.first().getKey().equals (entry.getKey())) { - return entries.rest().cons (entry); - } - else - return extended (entries.rest(), entry).cons (entries.first()); - } -} - -class IMapListSet extends AbstractSet > { - - RacketList > entries; - - // Java constructors - - IMapListSet () { - this.entries = RacketLists.empty(); - } - - IMapListSet (RacketList > entries) { - this.entries = entries; - } - - // public methods - - // Returns an Iterator for the entries in this set. - - public Iterator > iterator () { - return RacketLists.makeIterator (entries); - } - - // Returns the size of this set. - - public int size () { return RacketLists.length (entries); } -} diff --git a/Examples/10-3-IMapV1/IMaps.java b/Examples/10-3-IMapV1/IMaps.java deleted file mode 100644 index 67ad58b..0000000 --- a/Examples/10-3-IMapV1/IMaps.java +++ /dev/null @@ -1,68 +0,0 @@ -// The IMaps class defines static methods for the IMap type. -// In particular, it defines a static factory method for creating the -// empty map of the IMap type. - -import java.util.Iterator; - -class IMaps { - - private static IMap theEmptyIMap = new IMapList(); - - // static factory method for creating an empty IMap - - @SuppressWarnings("unchecked") - public static IMap empty () { - return (IMap ) theEmptyIMap; - } - - // main method for testing - - public static void main (String[] args) { - IMapTests.main (args); - } -} - -// Tests for IMap objects. - -class IMapTests { - - public static void main (String[] args) { - IMap m0 = IMaps.empty(); - IMap m1 = m0.extend (1, "one"); - IMap m2 = m0.extend (2, "two"); - IMap m3 = m0.extend (3, "three"); - IMap m4 = m0.extend (4, "four"); - IMap m5 = m0.extend (5, "five"); - IMap m6 = m0.extend (6, "six"); - IMap m7 = m0.extend (7, "seven"); - IMap m8 = m0.extend (8, "eight"); - IMap m9 = m0.extend (9, "nine"); - - IMap m00 = IMaps.empty(); - IMap m03 = m9.extend (3, "drei"); - IMap m10 = m03.extend (10, "zehn"); - - assert ! m0.containsKey(1); - assert m9.containsKey(4); - assert ! m9.containsKey(10); - - assert m9.get(9).equals("nine"); - assert m9.get(3).equals("three"); - assert m9.get(1).equals("one"); - - assert m10.get(9).equals("nine"); - assert m10.get(3).equals("drei"); - assert m10.get(1).equals("one"); - - assert m0.isEmpty(); - assert ! m1.isEmpty(); - - assert m0.size() == 0; - assert m1.size() == 1; - assert m9.size() == 9; - assert m03.size() == 9; - assert m10.size() == 10; - - System.out.println ("IMap tests passed."); - } -} diff --git a/Examples/10-4-Alist-v5-BSTs/AList.java b/Examples/10-4-Alist-v5-BSTs/AList.java new file mode 100644 index 0000000..a5283a4 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/AList.java @@ -0,0 +1,43 @@ +// An AList is an object of any class that implements +// the AList interface. + +// interpretation: An Alist represents a finite partial map from K to V. + +// Specification: + +// Let a be an alist, k1 and k2 be unequal keys. Then +// a.extend(k1,v1).lookup(k1) = v1 +// a.extend(k1,v1).lookup(k2) = a.lookup(k2) + +// a.extend(k1,v1).contains(k1) = true +// a.extend(k1,v1).contains(k2) = a.contains(k2) + +// If empty_alist is a representation of the empty alist, then +// empty_alist.contains(k1) = false + +// Note that this is what the English description says. Furthermore +// the "=" means the Java equality predicate on the appropriate type. +// So, for example, the first equation above means + +// a.extend(k1,v1).lookup(k1).equals(v1) is true + +// Note also that the interface does NOT include a constructor for the +// empty AList. This is because different implementations of AList may +// require different arguments to this constructor. + +interface AList ,V> { + + // Returns an association list like this one + // except the given key is associated with the given value. + + AList extend (K key, V val); + + // Returns true iff the key is found within this AList. + + boolean contains (K key); + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + V lookup (K key); +} diff --git a/Examples/10-4-Alist-v5-BSTs/ALists.java b/Examples/10-4-Alist-v5-BSTs/ALists.java new file mode 100644 index 0000000..3157b98 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/ALists.java @@ -0,0 +1,36 @@ +// To compile: +// +// javac *.java +// +// To run: +// +// java AListTests + +// This class defines a main method for testing the EmptyAList class, +// which implements the AList interface. + +class ALists { + + private static AList theEmptyAList = new EmptyAList(); + + // static factory method for creating an empty AList + + @SuppressWarnings("unchecked") + public static ,V> AList empty () { + return (AList ) theEmptyAList; + } + + + // // this generates a new EmptyAList object every time it is called. + // // public static AList empty () { + // public static ,V> AList empty () { + // return new EmptyAList (); + // } + + public static void main (String[] args) { + Tests.main (args); + } + +} + + diff --git a/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java b/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java new file mode 100644 index 0000000..a5a041f --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/EmptyAlist.java @@ -0,0 +1,40 @@ +// Objects of the EmptyAList class represent an empty +// association list with no keys. + +import java.util.NoSuchElementException; + +// An object of class EmptyAlist represents an empty partial map +// from K to V, that is, a map with an empty domain. + +class EmptyAList ,V> implements AList { + + // Returns an association list like this one + // except the given key is associated with the given value. + + // returns a new interior node, with both left and right subtrees empty. + + public AList extend (K key, V val) { + return new NonEmptyAList (key, val, this, this); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + return false; + } + + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + throw new NoSuchElementException ("key not found: " + key); + } + + + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + public String toString () {return "*";} + +} diff --git a/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java b/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java new file mode 100644 index 0000000..6e85a96 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/NonEmptyAList.java @@ -0,0 +1,84 @@ +// The object constructed by NonEmptyAlist(k,v,left,right) represents an +// interior node of a binary search tree, mapping k to v with left and +// right as the subtrees. + +class NonEmptyAList ,V> implements AList { + + private K key; // key for this entry in the AList + private V val; // val for this entry in the AList + private AList left; // the entries with keys < this key + private AList right; // the entries with keys > this key + + NonEmptyAList (K key, V val, AList left, AList right) { + this.key = key; + this.val = val; + this.left = left; + this.right = right; + } + + // Returns an association list like this one + // except the given key is associated with the given value. + // Be smart about duplicate keys. + // New keys are eventually inserted at the leaves + + public AList extend (K newKey, V val) { + if (newKey.equals(this.key)) + return new NonEmptyAList + (this.key, val, left, right); + if (newKey.compareTo(this.key) < 0) + return new NonEmptyAList + (this.key, this.val, + left.extend(newKey,val), + right); + else + return new NonEmptyAList + (this.key, this.val, + left, + right.extend(newKey,val)); + } + + // Returns true iff the key is found within this AList. + + public boolean contains (K key) { + if (key.equals (this.key)) + return true; + else if (key.compareTo(this.key) < 0) + return left.contains(key); + else + return right.contains(key); + + } + // Returns the value associated with the given key. + // Throws a NoSuchElementException if the key is not found. + + public V lookup (K key) { + if (key.equals (this.key)) + return this.val; + else if (key.compareTo(this.key) < 0) + return left.lookup(key); + else return right.lookup(key); + } + + // We will not have reason to compare ALists to each other, so we + // won't stop to override equals, toString, or hashcode. + + // public String toString() { + // return ("[" + + // left.toString() + // + (this.key.toString()) + // + ":" + (this.val.toString()) + // + right.toString() + // + "]"); + // } + + public String toString() { + return ("(" + (this.key.toString()) + ":" + (this.val.toString()) + ")" + + "[" + + left.toString() + + "," + + right.toString() + + "]" + ); + } + +} diff --git a/Examples/10-4-Alist-v5-BSTs/README b/Examples/10-4-Alist-v5-BSTs/README new file mode 100644 index 0000000..44c7230 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/README @@ -0,0 +1,5 @@ +This folder contains another version of Alist. + +ADDS: An algebraic specification of Alist +10-2: Adds singleton pattern +10-3 ADDS: keep keys in order diff --git a/Examples/10-4-Alist-v5-BSTs/Tests.java b/Examples/10-4-Alist-v5-BSTs/Tests.java new file mode 100644 index 0000000..820eaf0 --- /dev/null +++ b/Examples/10-4-Alist-v5-BSTs/Tests.java @@ -0,0 +1,114 @@ +class Tests { + + public static void main (String[] args) { + AList a0 = ALists.empty(); + + AList a1 = a0.extend ("x", 1); + AList a2 = a1.extend ("y", 2); + AList a3 = a2.extend ("z", 3); + AList a4 = a3.extend ("y", 4); + AList a5 = a4.extend ("u", 5); + + System.out.println("a0: " + a0.toString()); + System.out.println("a1: " + a1.toString()); + System.out.println("a2: " + a2.toString()); + System.out.println("a3: " + a3.toString()); + System.out.println("a4: " + a4.toString()); + System.out.println("a5: " + a5.toString()); + + checkTrue(a1.contains("x"), "a1 should contain x"); + + checkTrue(a2.contains("x"), "a2 should contain x"); + checkTrue(a2.contains("y"), "a2 should contain y"); + + checkTrue(a3.contains("x"), "a3 should contain x"); + checkTrue(a3.contains("y"), "a3 should contain y"); + checkTrue(a3.contains("z"), "a3 should contain z"); + + checkTrue(a4.lookup("x")==1, "a4(z) should equal 1"); + + checkTrue(a4.contains("x"), "a4 should contain x (first test)"); + checkTrue(a4.contains("y"), "a4 ahould contain y"); + checkTrue(a4.contains("z"), "a4 should contain z"); + checkFalse(a4.contains("u"), "a4 should contain u"); + + checkTrue(a4.lookup("y")== 4, "a4(y) should equal 4"); + checkTrue(a4.lookup("z") == 3, "a4(z) should equal 3"); + + System.err.println("end of a4 tests"); + + AList b2 = a2.extend ("b", 22); + AList b3 = b2.extend ("x", 33); + AList b4 = b3.extend ("y", 44); + + AList c0 = ALists.empty(); + checkFalse (c0.contains ("x"), "c0 should not contain x"); + AList c1 = c0.extend("x",11); + checkTrue (c1.lookup("x") == 11, "c1(x) should equal 11"); + AList c2 = c1.extend("x",22); + checkTrue (c1.lookup("x") == 11, "c1(x) should still equal 11"); + checkTrue (c2.lookup("x") == 22, "c2(x) should equal 22"); + + checkFalse (a0.contains ("x"), "a0 should not contain x"); + checkTrue (a3.contains ("z"), "a3 should contain z"); + checkTrue (a4.contains ("x"), "a4 should contain x"); + checkFalse (a4.contains ("b"), "a4 should contain x"); + + checkTrue (b2.contains ("b")); + checkTrue (b2.contains ("x")); + checkTrue (b2.contains ("y")); + checkFalse (b2.contains ("z")); + + checkTrue (a1.lookup ("x") == 1, "a1(x) should equal 1"); + checkTrue (a2.lookup ("y") == 2, "a2(x) should equal 2"); + checkTrue (a4.lookup ("x") == 1, "a4(x) should equal 1"); + checkTrue (a4.lookup ("y") == 4, "a4(y) should equal 4"); + checkTrue (a4.lookup ("z") == 3, "a4(z) should equal 3"); + + checkTrue (b2.lookup ("x") == 1, "b2(x) should equal 1"); + checkTrue (b2.lookup ("y") == 2, "b2(y) should equal 2"); + checkTrue (b4.lookup ("x") == 33, "b4(x) should equal 33"); + checkTrue (b4.lookup ("y") == 44, "b4(y) should equal 44"); + checkTrue (b4.lookup ("b") == 22, "b4(b) should equal 22"); + + summarize(); + } + + //////////////////////////////////////////////////////////////// + + private static int testsPassed = 0; + private static int testsFailed = 0; + + private static final String FAILED + = " TEST FAILED: "; + + static void checkTrue (boolean result) { + checkTrue (result, "anonymous"); + } + + static void checkTrue (boolean result, String name) { + if (result) { + testsPassed = testsPassed + 1; + // System.err.print("."); + } + else { + testsFailed = testsFailed + 1; + System.err.println (FAILED + name); + } + } + + static void checkFalse (boolean result) { + checkFalse (result, "anonymous"); + } + + static void checkFalse (boolean result, String name) { + checkTrue (! result, name); + } + + static void summarize () { + System.err.println ("Passed " + testsPassed + " tests"); + if (true) { + System.err.println ("Failed " + testsFailed + " tests"); + } + } +} diff --git a/Examples/10-4-IMapV2/IMap.java b/Examples/10-4-IMapV2/IMap.java deleted file mode 100644 index 509f0be..0000000 --- a/Examples/10-4-IMapV2/IMap.java +++ /dev/null @@ -1,20 +0,0 @@ -// An IMap is an object of any class that implements IMap . -// -// Interpretation: An IMap represents an immutable finite function -// from keys to values. -// -// IMap extends java.util.Map , so an IMap can be used -// as an unmodifiable Map . - -import java.util.Map; - -interface IMap extends Map { - - // Returns an IMap like this one except the given key is associated - // with the given value. The extend operation does not modify this - // IMap. - // - // Invariant: the key cannot be null. - - IMap extend (K key, V value); -} diff --git a/Examples/10-4-IMapV2/IMapBST.java b/Examples/10-4-IMapV2/IMapBST.java deleted file mode 100644 index 4fc4830..0000000 --- a/Examples/10-4-IMapV2/IMapBST.java +++ /dev/null @@ -1,192 +0,0 @@ -// Constructor templates for IMapBST : -// -// IMapBST.empty(c) -// Interpretation: -// c is the comparator to be used by the map -// -// this.make (k, v, left, right) -// Interpretation: -// k and v are the key and value to be used at the root -// left is the left subtree -// right is the right subtree -// Where: -// k is distinct from all keys in the left and right subtrees -// k is greater than all keys in the left subtree -// k is less than all keys in the right subtree -// the left and right subtrees obey those invariants, recursively - -import java.util.List; -import java.util.ArrayList; - -import java.util.Iterator; - -import java.util.Comparator; - -// Strategy: extends SortedIMapBase - -abstract class IMapBST extends SortedIMapBase { - - private Comparator super K> cmp; // the comparator for this map - - IMapBST (Comparator super K> cmp) { - this.cmp = cmp; - } - - // Returns an empty map with the given comparator. - - static IMapBST empty (Comparator super K> cmp) { - return new IMapEmptyBST (cmp); - } - - // Returns an non-empty map with the given components. - // Invariants: - // key does not occur in the left or right subtrees - // key is greater than all keys in left subtree - // key is less than all keys in right subtree - // the left and right subtrees obey those invariants, recursively - - IMapBST make (K key, V val, - IMapBST left, - IMapBST right) { - return new IMapNonEmptyBST (key, val, left, right); - } - - // abstract methods listed by SortedMap - - public Comparator super K> comparator () { return cmp; } - - // Returns an iterator for the keys of this IMap. - - protected Iterator keyIterator() { - List lst = new ArrayList (); - this.addKeys (lst); - return lst.iterator(); - } - - // Abstract help methods. - - // Adds the keys of this tree, in order, to the given list. - - abstract void addKeys (List lst); -} - -class IMapEmptyBST extends IMapBST { - - // Java constructor - - IMapEmptyBST (Comparator super K> cmp) { - super(cmp); - } - - // abstract methods listed by Map - - public int size () { return 0; } - - // abstract methods listed by IMap - - public IMap extend (K key, V val) { - return this.make (key, val, this, this); - } - - // abstract methods declared by IMapBase - - // Returns true iff this map has a mapping for the given key. - - protected boolean hasKey (K key) { return false; } - - // Returns the value associated with the given key. - - protected V getVal (K key) { - throw new RuntimeException ("getVal called with empty map: " + key); - } - - // Abstract help methods. - - // Adds the keys of this tree, in order, to the given list. - - void addKeys (List lst) { } -} - -class IMapNonEmptyBST extends IMapBST { - - private K key; // the key at the root of this tree - private V val; // the value associated with that key - private IMapBST left; // the left subtree of this tree - private IMapBST right; // the right subtree of this tree - - private int theSize; // the size of this tree - - // Java constructor - // Invariant: the left and right subtrees have the same comparator. - - IMapNonEmptyBST (K key, V val, IMapBST left, IMapBST right) { - super(left.comparator()); - this.key = key; - this.val = val; - this.left = left; - this.right = right; - this.theSize = 1 + left.size() + right.size(); - } - - // abstract methods listed by Map - - public int size () { return theSize; } - - // abstract methods listed by IMap