Skip to content

Commit a28e4a7

Browse files
committed
Adds initial selection of sample programs
Joe the bos, lists, binary trees.
1 parent 88dc379 commit a28e4a7

9 files changed

+555
-0
lines changed

binaryTrees/binaryTree.grace

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
def ConcurrentModification = ProgrammingError.refine "ConcurrentModification "
2+
3+
method empty {
4+
withAll []
5+
}
6+
7+
class withAll(pairs:Collection) {
8+
// answers a new mutable binary tree containing pairs, a which must be
9+
// a collection of key-value bindings.
10+
11+
class nodeContaining(key', data')withChildren(left', right') is confidential {
12+
var key is readable := key'
13+
var data is public := data'
14+
var left is public := left'
15+
var right is public := right'
16+
method isEmpty { false }
17+
method asString { "Node({key}, {data}, {left}, {right})" }
18+
method copy {
19+
nodeContaining(key, data) withChildren(left.copy, right.copy)
20+
}
21+
method height { 1 + max(left.height, right.height) }
22+
method do(block1) {
23+
left.do(block1)
24+
block1.apply(key::data)
25+
right.do(block1)
26+
}
27+
}
28+
29+
def emptyTree = object {
30+
method isEmpty { true }
31+
method asString { "emptyTree" }
32+
method copy { emptyTree }
33+
method height { 0 }
34+
method do(block1) { }
35+
}
36+
37+
method nodeContaining(key, data) is confidential {
38+
nodeContaining(key, data) withChildren(emptyTree, emptyTree)
39+
}
40+
41+
var root := emptyTree
42+
var size is readable := 0
43+
var eventCount := 0
44+
45+
addAll(pairs)
46+
47+
method height { root.height } // TODO: should this be confidential?
48+
49+
method at(key) put(data) {
50+
addNode(nodeContaining(key, data))
51+
}
52+
53+
method addNode(newNode) is confidential {
54+
eventCount := eventCount + 1
55+
def addNode' = { newNode', currentNode ->
56+
if (newNode'.isEmpty) then {
57+
currentNode
58+
} elseif (currentNode.isEmpty) then {
59+
size := size + 1
60+
newNode'
61+
} elseif (newNode'.key < currentNode.key) then {
62+
currentNode.left := addNode'.apply(newNode', currentNode.left)
63+
currentNode
64+
} elseif (newNode'.key > currentNode.key) then {
65+
currentNode.right := addNode'.apply(newNode', currentNode.right)
66+
currentNode
67+
} else {
68+
currentNode.data := newNode'.data
69+
currentNode
70+
}
71+
}
72+
73+
root := addNode'.apply(newNode, root)
74+
}
75+
76+
method addAll(newPairs) {
77+
newPairs.do { each -> at(each.key) put(each.value) }
78+
}
79+
80+
method remove(key) {
81+
eventCount := eventCount + 1
82+
var removedNode := emptyTree
83+
var rightBranch := emptyTree
84+
85+
def remove' = { key', parentNode, currentNode ->
86+
if (currentNode.isEmpty) then {
87+
NoSuchObject.raise "Can't remove key {key} because it is not present"
88+
} elseif (key' < currentNode.key) then {
89+
currentNode.left := remove'.apply(key', currentNode, currentNode.left)
90+
currentNode
91+
} elseif (key' > currentNode.key) then {
92+
currentNode.right := remove'.apply(key', currentNode, currentNode.right)
93+
currentNode
94+
} else {
95+
size := size - 1
96+
removedNode := currentNode
97+
rightBranch := currentNode.right
98+
currentNode.left
99+
}
100+
}
101+
102+
root := remove'.apply(key, emptyTree, root)
103+
addNode(rightBranch)
104+
if (!rightBranch.isEmpty) then { size := size - 1 }
105+
removedNode.key::removedNode.data
106+
}
107+
method at(key) {
108+
def at' = { key', currentNode ->
109+
if (currentNode.isEmpty) then {
110+
NoSuchObject.raise
111+
} elseif (key' < currentNode.key) then {
112+
at'.apply(key', currentNode.left)
113+
} elseif (key' > currentNode.key) then {
114+
at'.apply(key', currentNode.right)
115+
} else {
116+
return currentNode.data
117+
}
118+
}
119+
at'.apply(key, root)
120+
}
121+
method isEmpty { root.isEmpty }
122+
method asString { root.asString }
123+
method copy {
124+
def newTree = outer.with
125+
newTree.addNode(root.copy)
126+
newTree
127+
}
128+
method do(block1) {
129+
root.do(block1)
130+
}
131+
class iterator<T> {
132+
def zipper is readable = list []
133+
def savedEventCount = eventCount
134+
addLeftmostPath(root)
135+
method addLeftmostPath(start) is confidential {
136+
var n := start
137+
while { n.isEmpty.not } do {
138+
zipper.addLast(n)
139+
n := n.left
140+
}
141+
}
142+
method hasNext { zipper.isEmpty.not }
143+
method next {
144+
if (savedEventCount != eventCount) then {
145+
ConcurrentModification.raise "the tree has changed!"
146+
}
147+
if (!hasNext) then {
148+
IteratorExhausted.raise "on Tree"
149+
}
150+
def current = zipper.removeLast
151+
addLeftmostPath(current.right)
152+
current.key::current.data
153+
}
154+
}
155+
}
156+
157+

binaryTrees/binaryTreeTest.grace

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import "gUnit" as gU
2+
import "binaryTree" as tree
3+
import "unicode" as u
4+
5+
def binaryTreeTest = object {
6+
class forMethod(m) {
7+
inherits gU.testCaseNamed(m)
8+
9+
method tournamentTree(grow, lo, hi) {
10+
if (lo <= hi) then {
11+
def k = ((lo + hi) / 2).truncated
12+
def d = u.create("a".ord - 1 + k)
13+
grow.at(k) put (d)
14+
tournamentTree(grow, lo, k-1)
15+
tournamentTree(grow, k+1, hi)
16+
}
17+
}
18+
19+
method testTournamentTreeDo {
20+
def tt = tree.empty
21+
tournamentTree(tt, 1, 26)
22+
def l = list []
23+
tt.do { each -> l.add(each.value) }
24+
assert (l) shouldBe ((1..26).map {n -> u.create("a".ord - 1 + n)})
25+
}
26+
27+
method testIsEmptyOfEmptyTree {
28+
assert (tree.empty.isEmpty) shouldBe (true)
29+
}
30+
method testIssizeEmptyTree {
31+
assert (tree.empty.size) shouldBe (0)
32+
}
33+
method testIsEmptyOfNonEmptyTree {
34+
assert (tree.withAll ["a"::1].isEmpty) shouldBe (false)
35+
}
36+
method testSizeOfNonEmptyTree {
37+
assert (tree.withAll ["a"::1].size) shouldBe (1)
38+
}
39+
method testSizeAfterRemoval {
40+
def t = tree.withAll [1::"a"]
41+
assert (t.remove(1)) shouldBe (1::"a")
42+
assert (t.size) shouldBe (0)
43+
}
44+
method testAddToEmptyTree {
45+
def t = tree.empty
46+
t.at(1)put(1)
47+
assert (t.isEmpty) shouldBe (false)
48+
}
49+
method testAtWithOneNode {
50+
def t = tree.withAll ["a"::1]
51+
assert (t.at("a")) shouldBe (1)
52+
}
53+
method testAtWithALeftNode {
54+
def t = tree.withAll ["b"::1, "a"::2]
55+
assert (t.at("a")) shouldBe (2)
56+
assert (t.at("b")) shouldBe (1)
57+
}
58+
method testAtWithARightNode {
59+
def t = tree.withAll ["a"::1, "c"::2]
60+
assert (t.at("a")) shouldBe (1)
61+
assert (t.at("c")) shouldBe (2)
62+
}
63+
method testRemoveFromEmtpyTree {
64+
def t = tree.empty
65+
assert { t.remove(1) } shouldRaise (NoSuchObject)
66+
}
67+
method testRemoveNodeWithNoChildrenFromTree {
68+
def t = tree.withAll [1::2]
69+
t.remove(1)
70+
assert (t.isEmpty) shouldBe (true)
71+
}
72+
method testRemoveNodeWithRightChildFromTree {
73+
def t = tree.withAll [1::"a", 2::"b"]
74+
t.remove(1)
75+
assert (t.isEmpty) shouldBe (false)
76+
assert (t.at(2)) shouldBe ("b")
77+
}
78+
method testRemoveNodeWithLeftChildFromTree {
79+
def t = tree.withAll [2::"b", 1::"a"]
80+
t.remove(2)
81+
assert (t.isEmpty) shouldBe (false)
82+
assert (t.at(1)) shouldBe ("a")
83+
}
84+
method testRemoveNodeWithBothChildrenFromTree {
85+
def t = tree.withAll [2::"b", 1::"a", 3::"c"]
86+
t.remove(2)
87+
assert (t.isEmpty) shouldBe (false)
88+
assert (t.at(1)) shouldBe ("a")
89+
assert (t.at(3)) shouldBe ("c")
90+
}
91+
method testRemoveInnerNodeFromTree {
92+
def t = tree.withAll [4::"d", 2::"b", 1::"a", 3::"c"]
93+
t.remove(2)
94+
assert (t.isEmpty) shouldBe (false)
95+
assert (t.at(1)) shouldBe ("a")
96+
assert (t.at(3)) shouldBe ("c")
97+
assert (t.at(4)) shouldBe ("d")
98+
}
99+
method testIteratorTT {
100+
def tt = tree.empty
101+
tournamentTree(tt, 1, 26)
102+
def ks = list []
103+
def vs = list []
104+
def iter = tt.iterator
105+
while { iter.hasNext } do {
106+
def each = iter.next
107+
ks.add(each.key)
108+
vs.add(each.value)
109+
}
110+
assert (ks) shouldBe ((1..26))
111+
assert (vs) shouldBe ((1..26).map {n -> u.create("a".ord - 1 + n)})
112+
}
113+
method testIterator {
114+
def t = tree.withAll [4::"d", 2::"b", 1::"a", 3::"c"]
115+
def r = list []
116+
def iter = t.iterator
117+
while {iter.hasNext} do {
118+
r.addLast(iter.next)
119+
}
120+
def desired = list [1::"a", 2::"b", 3::"c", 4::"d"]
121+
assert (r) shouldBe (desired)
122+
}
123+
method testConcurrentModification {
124+
def t = tree.withAll [4::"d", 2::"b", 1::"a", 3::"c"]
125+
def r = list []
126+
def iter = t.iterator
127+
assert {
128+
while {iter.hasNext} do {
129+
def n = iter.next
130+
r.addLast(n)
131+
t.at(n.key + 10) put(n.value)
132+
}
133+
} shouldRaise (tree.ConcurrentModification)
134+
}
135+
}
136+
}
137+
138+
gU.testSuite.fromTestMethodsIn(binaryTreeTest).runAndPrintResults

binaryTrees/exploreTree.grace

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import "unicode" as u
2+
import "binaryTree" as bt
3+
4+
def t = bt.empty
5+
6+
(1..26).do { each ->
7+
def data = u.create("a".ord - 1 + each)
8+
t.at(each) put(data)
9+
}
10+
11+
for(t) do { each -> print(each) }
12+
13+
print "height of t is {t.height}."
14+
15+
def tt = bt.empty
16+
17+
method tournamentTree(grow, lo, hi) {
18+
if (lo <= hi) then {
19+
def k = ((lo + hi) / 2).truncated
20+
def d = u.create("a".ord - 1 + k)
21+
grow.at(k) put (d)
22+
tournamentTree(grow, lo, k-1)
23+
tournamentTree(grow, k+1, hi)
24+
}
25+
}
26+
27+
tournamentTree(tt, 1, 26)
28+
for(tt) do { each -> print(each) }
29+
print "height of tt is {tt.height}."
30+

joeTheBox/box.grace

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// Steve Willoughby
3+
// Spring 2016
4+
//
5+
import "objectdraw" as od
6+
import "math" as math
7+
method named(name) {
8+
object {
9+
var origin is readable := 0@0
10+
var heading is public := 0
11+
var extent is public := defaultExtent
12+
def noRect = object {
13+
inherits Singleton.new
14+
def asString is readable = "noRect"
15+
method moveTo { }
16+
method visible:=(_) { }
17+
}
18+
var myRect := noRect
19+
20+
method defaultExtent {
21+
20@20
22+
}
23+
24+
method turnBy(degrees) {
25+
heading := (heading + degrees) % 360
26+
}
27+
28+
method face(degrees) {
29+
heading := degrees
30+
}
31+
method faceEast {
32+
// Set heading to 0 degrees explicitly
33+
face(0)
34+
}
35+
36+
method showOn(canvas) {
37+
if (myRect == noRect) then {
38+
myRect := od.framedRectAt(origin) size(extent) on (canvas)
39+
}
40+
myRect.visible := true
41+
}
42+
43+
method hide {
44+
myRect.visible := false
45+
}
46+
47+
method moveTo(location:Point) {
48+
origin := location
49+
if (myRect ≠ noRect) then {myRect.moveTo(origin)}
50+
}
51+
52+
method moveBy(increment:Point) {
53+
moveTo(origin + increment)
54+
}
55+
56+
method moveDistance(distance:Number) {
57+
// Move in the current heading some distance
58+
moveBy(((heading*π/180).cos*distance)@((heading*π/180.0).sin*distance))
59+
}
60+
61+
method growBy(increment:Point) {
62+
extent := extent + increment
63+
myRect.setSize(extent)
64+
}
65+
66+
method asString {
67+
"a box named {name}"
68+
}
69+
}
70+
}
71+

0 commit comments

Comments
 (0)