is103 1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/graphlab.rb +650 -0
- data/lib/is103.rb +3 -0
- data/lib/lineardslab.rb +395 -0
- data/lib/treelab.rb +418 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d27d23670db8b113b4f20683f4671368e4d52024
|
4
|
+
data.tar.gz: 631da5c6cfbe1decc3afe494629e9bc525c86114
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 57d06dbc0e45653b2f4639ad37217550bb0c55e029f9d92272e47d22cc71c9e48a13737d99580fbf474b9d9cb481aceda42a3c7a06c81128539d09464b18a295
|
7
|
+
data.tar.gz: 7b9e90c9858206ecf1f663452526c34584d818e723fb299c99e46351b2b860bf46d2045cbe0610c6b2ee436b3bf7876134ee54a0e9cbec89639d6c1143346778
|
data/lib/graphlab.rb
ADDED
@@ -0,0 +1,650 @@
|
|
1
|
+
module GraphLab
|
2
|
+
|
3
|
+
=begin doc
|
4
|
+
|
5
|
+
== Graph
|
6
|
+
|
7
|
+
A Graph is made up of vertices and edges between vertices.
|
8
|
+
In this lab, to represent edges, we use adjacency list to represent an directed graph.
|
9
|
+
Vertex position will be created randomly.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
# Version 2.7
|
14
|
+
# Change log:
|
15
|
+
#1. added method g.deleteEdges(v1,v2)
|
16
|
+
#2. added another constructor where user can define x coord and y coord for the vertex created
|
17
|
+
|
18
|
+
|
19
|
+
@@graph = nil
|
20
|
+
@@visitedV = Array.new
|
21
|
+
@@position = Array.new #to keep track of position of vertex in canvas
|
22
|
+
@@createdValues = Array.new #to keep track of created value
|
23
|
+
|
24
|
+
#method to view graph
|
25
|
+
def view_graph(graph)
|
26
|
+
@@graph = graph
|
27
|
+
raise "Value must be a Graph!" if graph.class != GraphLab::Graph
|
28
|
+
# Initializes the canvas and font type
|
29
|
+
Canvas.init(650, 650, "GraphLab")
|
30
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 14)
|
31
|
+
Canvas::Font.new('visitedfont', :family => 'Helvetica', :size => 12)
|
32
|
+
if (graph.vertices == nil)
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
if(graph.vertices != nil)
|
36
|
+
draw_graph(graph)
|
37
|
+
end
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
|
41
|
+
def graph
|
42
|
+
@@graph
|
43
|
+
end
|
44
|
+
|
45
|
+
#called by view graph, to draw GRAPH, calls draw vertices and draw edge
|
46
|
+
def draw_graph(g)
|
47
|
+
v = g.vertices
|
48
|
+
#to draw edges
|
49
|
+
v.each { |vertex| draw_ed(vertex.xcoord,vertex.ycoord, vertex.adjList, vertex.value)}
|
50
|
+
|
51
|
+
#to draw the vertices
|
52
|
+
v.each { |x| draw_v(x.xcoord,x.ycoord, x.value,"gray") }
|
53
|
+
end
|
54
|
+
|
55
|
+
#to draw vertices
|
56
|
+
def draw_v(x,y,value,color)
|
57
|
+
Canvas::Circle.new(x, y, 18, :fill => color)
|
58
|
+
Canvas::Text.new(value, (x-8), (y-8), :font => 'bucketfont')
|
59
|
+
end
|
60
|
+
|
61
|
+
#to call drawedge for each adj
|
62
|
+
def draw_ed(x1,y1,adjList,val1)
|
63
|
+
adjList.each { |a| draw_edge(x1,y1, a.xcoord, a.ycoord, val1, a.value)}
|
64
|
+
end
|
65
|
+
|
66
|
+
#to draw edges
|
67
|
+
def draw_edge(x1,y1,x2,y2, val1, val2)
|
68
|
+
Canvas::Line.new(x1,y1,x2,y2)
|
69
|
+
arrowLengthx = (x2-x1)
|
70
|
+
arrowLengthx = arrowLengthx.abs
|
71
|
+
arrowLengthx = (arrowLengthx - 9.0)*0.03
|
72
|
+
arrowLengthy = (y2-y1)
|
73
|
+
arrowLengthy = arrowLengthy.abs
|
74
|
+
arrowLengthy = (arrowLengthy - 9.0)*0.03
|
75
|
+
#to mark the directed graph from the source to the adj node e.g. node 5 had adj node 4, mark will be *4
|
76
|
+
x5= 0.0
|
77
|
+
y5= 0.0
|
78
|
+
distnce = 9.0
|
79
|
+
dist = 7.0
|
80
|
+
if(arrowLengthx < arrowLengthy && (arrowLengthx/0.03) >= 60)
|
81
|
+
distnce = 8.8
|
82
|
+
dist = 7.0
|
83
|
+
elsif(arrowLengthx < arrowLengthy)
|
84
|
+
distnce = 2.8
|
85
|
+
dist = 2.5
|
86
|
+
elsif(arrowLengthx > arrowLengthy && (arrowLengthy/0.03) >= 60)
|
87
|
+
distnce =8.8
|
88
|
+
dist = 7.0
|
89
|
+
elsif(arrowLengthx > arrowLengthy)
|
90
|
+
distnce = 2.8
|
91
|
+
dist = 2.2
|
92
|
+
end
|
93
|
+
|
94
|
+
if(x2<x1 && y1>y2)
|
95
|
+
x5 = ((x1-x2)/distnce)+x2
|
96
|
+
y5 = ((y1-y2)/distnce)+y2
|
97
|
+
elsif(x2<x1 && y1<y2)
|
98
|
+
x5 = ((x1-x2)/distnce)+x2
|
99
|
+
y5 = y2-((y2-y1)/distnce)
|
100
|
+
elsif(x2>x1 && y1<y2)
|
101
|
+
x5 = x2-((x2-x1)/distnce)
|
102
|
+
y5 = y2-((y2-y1)/distnce)
|
103
|
+
elsif(x2>x1 && y1>y2)
|
104
|
+
x5 = x2-((x2-x1)/distnce)
|
105
|
+
y5 = ((y1-y2)/distnce)+y2
|
106
|
+
end
|
107
|
+
x0= 0.0
|
108
|
+
y0= 0.0
|
109
|
+
gradient =(((y2*-1.0)-(y1*-1.0))/(x2-x1))
|
110
|
+
c= (y2*-1.0)-(gradient*x2)
|
111
|
+
if(x2<x1 && y1>y2)
|
112
|
+
x0 = ((x1-x2)/dist)+x2
|
113
|
+
y0 = ((y1-y2)/dist)+y2
|
114
|
+
elsif(x2<x1 && y1<y2)
|
115
|
+
x0 = ((x1-x2)/dist)+x2
|
116
|
+
y0 = y2-((y2-y1)/dist)
|
117
|
+
elsif(x2>x1 && y1<y2)
|
118
|
+
x0 = x2-((x2-x1)/dist)
|
119
|
+
y0 = y2-((y2-y1)/dist)
|
120
|
+
elsif(x2>x1 && y1>y2)
|
121
|
+
x0 = x2-((x2-x1)/dist)
|
122
|
+
y0 = ((y1-y2)/dist)+y2
|
123
|
+
end
|
124
|
+
gradientPerpendicular = (1.0/gradient)*-1.0
|
125
|
+
cPerpendicular = (y0*-1.0) - (gradientPerpendicular*x0)
|
126
|
+
if(arrowLengthx < arrowLengthy && arrowLengthx >= 60)
|
127
|
+
arrl = arrowLengthx
|
128
|
+
x3 = x0 - arrl
|
129
|
+
y3 = (x3*gradientPerpendicular + cPerpendicular)*-1.0
|
130
|
+
x4 = x0 + arrl
|
131
|
+
y4 = (x4*gradientPerpendicular + cPerpendicular)*-1.0
|
132
|
+
elsif(arrowLengthx < arrowLengthy)
|
133
|
+
arrl = 9.0
|
134
|
+
x3 = x0 - arrl
|
135
|
+
y3 = (x3*gradientPerpendicular + cPerpendicular)*-1.0
|
136
|
+
x4 = x0 + arrl
|
137
|
+
y4 = (x4*gradientPerpendicular + cPerpendicular)*-1.0
|
138
|
+
elsif(arrowLengthx > arrowLengthy && arrowLengthy >=60)
|
139
|
+
arrl = arrowLengthy
|
140
|
+
y3 = (-y0 - arrl)*-1.0
|
141
|
+
x3 = (-y3-cPerpendicular)/gradientPerpendicular
|
142
|
+
y4 = (-y0 + arrl)*-1.0
|
143
|
+
x4 = (-y4-cPerpendicular)/gradientPerpendicular
|
144
|
+
elsif(arrowLengthx > arrowLengthy)
|
145
|
+
arrl = 9.0
|
146
|
+
y3 = (-y0 - arrl)*-1.0
|
147
|
+
x3 = (-y3-cPerpendicular)/gradientPerpendicular
|
148
|
+
y4 = (-y0 + arrl)*-1.0
|
149
|
+
x4 = (-y4-cPerpendicular)/gradientPerpendicular
|
150
|
+
|
151
|
+
end
|
152
|
+
Canvas::Line.new(x3,y3,x5,y5)
|
153
|
+
Canvas::Line.new(x4,y4,x5,y5)
|
154
|
+
end
|
155
|
+
|
156
|
+
def dfs(s)
|
157
|
+
@@visitedV << "DFS order of visit: "
|
158
|
+
view_graph(self)
|
159
|
+
_dfs(s)
|
160
|
+
self.clearAll
|
161
|
+
@@visitedV.clear
|
162
|
+
return nil
|
163
|
+
end
|
164
|
+
|
165
|
+
#to perform dfs with x as the starting node, recursive
|
166
|
+
def _dfs(v)
|
167
|
+
setVisitedDfs(v)
|
168
|
+
#recursive dfs
|
169
|
+
v.adjList.each{ |u| setVisitedDfs(u) }
|
170
|
+
end
|
171
|
+
|
172
|
+
def setVisitedDfs(u)
|
173
|
+
if(!u.isVisited?)
|
174
|
+
u.visited = true
|
175
|
+
p u
|
176
|
+
@@visitedV << u
|
177
|
+
anim(u)
|
178
|
+
_dfs(u)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
#to perform bfs with x as the starting node, using queue implementation
|
183
|
+
def bfs(s)
|
184
|
+
@@visitedV << "BFS order of visit: "
|
185
|
+
view_graph(self)
|
186
|
+
@q = Queue.new
|
187
|
+
setVisitedBfs(s)
|
188
|
+
while (!@q.isEmpty?)
|
189
|
+
v = @q.dequeue
|
190
|
+
adjList = v.adjList
|
191
|
+
adjList.each { |u| setVisitedBfs(u)}
|
192
|
+
end
|
193
|
+
self.clearAll
|
194
|
+
@@visitedV.clear
|
195
|
+
return nil
|
196
|
+
end
|
197
|
+
|
198
|
+
def setVisitedBfs(u)
|
199
|
+
if(!u.isVisited?)
|
200
|
+
u.visited = true
|
201
|
+
p u
|
202
|
+
@@visitedV << u
|
203
|
+
anim(u)
|
204
|
+
@q.enqueue(u)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def clearAll
|
209
|
+
self.vertices.each { |u| u.visited = false}
|
210
|
+
end
|
211
|
+
|
212
|
+
def anim(s)
|
213
|
+
draw_v(s.xcoord,s.ycoord, s.value,"red")
|
214
|
+
Canvas::Text.new(@@visitedV.to_s, 30, 600, :font => 'visitedfont')
|
215
|
+
sleep(1.5)
|
216
|
+
draw_v(s.xcoord,s.ycoord, s.value, "green")
|
217
|
+
end
|
218
|
+
|
219
|
+
class Graph
|
220
|
+
|
221
|
+
#to keep array of vertices
|
222
|
+
attr_reader :vertices
|
223
|
+
|
224
|
+
# class constructor
|
225
|
+
def initialize
|
226
|
+
@vertices = Array.new
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
# checks whether the graph is empty
|
231
|
+
def isEmpty?
|
232
|
+
return vertices == nil
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
#to add new vertex in the graph
|
237
|
+
def addVertex(vertex)
|
238
|
+
raise "Value must be a Vertex!" if vertex.class != GraphLab::Vertex
|
239
|
+
raise "Vertex already added in the graph!" if vertices.include?(vertex)
|
240
|
+
if(vertex.class == GraphLab::Vertex && !vertices.include?(vertex))
|
241
|
+
vertices << vertex
|
242
|
+
end
|
243
|
+
view_graph(self)
|
244
|
+
return @vertices
|
245
|
+
end
|
246
|
+
|
247
|
+
#to draw edges between 2 vertices in graph randomly from v1 to v2
|
248
|
+
def addEdge(v1,v2)
|
249
|
+
raise "Value must be a Vertex!" if v1.class != GraphLab::Vertex
|
250
|
+
raise "Value must be a Vertex!" if v2.class != GraphLab::Vertex
|
251
|
+
raise "Vertex already added in the graph!" if v1.adjList.include?(v2)
|
252
|
+
if(v1.class == GraphLab::Vertex && v2.class == GraphLab::Vertex && !v1.adjList.include?(v2))
|
253
|
+
v1.addEdge(v2)
|
254
|
+
end
|
255
|
+
view_graph(self)
|
256
|
+
end
|
257
|
+
|
258
|
+
def deleteEdge(v1, v2)
|
259
|
+
raise "Value must be a Vertex!" if v1.class != GraphLab::Vertex
|
260
|
+
raise "Value must be a Vertex!" if v2.class != GraphLab::Vertex
|
261
|
+
raise "Vertex "+v1.value.to_s+" does not have "+v2.value.to_s+" edge" if !v1.adjList.include?(v2)
|
262
|
+
if(v1.class == GraphLab::Vertex && v2.class == GraphLab::Vertex && v1.adjList.include?(v2))
|
263
|
+
v1.deleteEdge(v2)
|
264
|
+
end
|
265
|
+
view_graph(self)
|
266
|
+
end
|
267
|
+
|
268
|
+
#to draw edges between 2 vertices in graph randomly
|
269
|
+
def addEdges(x)
|
270
|
+
raise "Value must be smaller than 1!" if x > 1
|
271
|
+
raise "Value must be larger than 0!" if x <= 0
|
272
|
+
x = x*100
|
273
|
+
vertices.each { |u| drawOrNot(u,vertices,x) }
|
274
|
+
view_graph(self)
|
275
|
+
end
|
276
|
+
|
277
|
+
def drawOrNot(u,adjList,x)
|
278
|
+
adjList.each{ |o| drawNot(u,o,x) }
|
279
|
+
end
|
280
|
+
|
281
|
+
def drawNot(u,o,x)
|
282
|
+
a = rand(101) #from 100, what is the generated random no
|
283
|
+
if(a<=x && u!=o)
|
284
|
+
addEdgeForGraph(u,o)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
#to add edge from v1 to v2 - directed graph
|
289
|
+
def addEdgeForGraph(v1,v2)
|
290
|
+
raise "Value must be a Vertex!" if v1.class != GraphLab::Vertex
|
291
|
+
raise "Value must be a Vertex!" if v2.class != GraphLab::Vertex
|
292
|
+
raise "Vertex must be in the graph" if !include?(v1)
|
293
|
+
raise "Vertex must be in the graph" if !include?(v2)
|
294
|
+
raise "Vertex "+v2+" already adjacent vertex of "+v1+" in the graph!" if v1.adjList.include?(v2)
|
295
|
+
raise "cannot add edge to itself" if v1 == v2
|
296
|
+
if(v1.class == GraphLab::Vertex && v2.class == GraphLab::Vertex && include?(v1) && include?(v2))
|
297
|
+
v1.addEdge(v2)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
#to count number of vertices in the graph
|
302
|
+
def count_v()
|
303
|
+
return vertices.length
|
304
|
+
end
|
305
|
+
|
306
|
+
#to delete the vertex from the graph
|
307
|
+
def deleteVertex(vertex)
|
308
|
+
if(vertex.class == GraphLab::Vertex)
|
309
|
+
for i in 0..graph.vertices.length-1
|
310
|
+
vi = graph.vertices[i]
|
311
|
+
if(vi.adjList.include?(vertex))
|
312
|
+
vi.adjList.delete(vertex)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
vertex.adjList.each { |adj| adj.adjList.delete(vertex)}
|
316
|
+
vertex.adjList.clear
|
317
|
+
vertices.delete(vertex)
|
318
|
+
end
|
319
|
+
view_graph(self)
|
320
|
+
return @vertices
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
def include?(v1)
|
325
|
+
return vertices.include?(v1)
|
326
|
+
end
|
327
|
+
|
328
|
+
# return a string representation of the array
|
329
|
+
def inspect
|
330
|
+
return to_s
|
331
|
+
end
|
332
|
+
|
333
|
+
# returns a string representation of the array
|
334
|
+
def to_s
|
335
|
+
return @vertices.inspect
|
336
|
+
end
|
337
|
+
|
338
|
+
end
|
339
|
+
|
340
|
+
class Vertex
|
341
|
+
# value and coordinate of vertex
|
342
|
+
attr_accessor:value
|
343
|
+
attr_accessor:xcoord
|
344
|
+
attr_accessor:ycoord
|
345
|
+
# attribute that represents the node in a graph canvas
|
346
|
+
attr_accessor:adjList
|
347
|
+
attr_accessor:visited
|
348
|
+
|
349
|
+
|
350
|
+
def initialize *args
|
351
|
+
case args.size
|
352
|
+
when 3
|
353
|
+
init_valxy *args
|
354
|
+
when 1
|
355
|
+
init_val *args
|
356
|
+
else
|
357
|
+
error
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def init_valxy(value, x , y)
|
362
|
+
raise "Enter other value. Vertex with this value has been created!" if @@createdValues.include?(value)
|
363
|
+
if(!@@createdValues.include?(value))
|
364
|
+
@@createdValues << value
|
365
|
+
@value = value
|
366
|
+
@xcoord = x
|
367
|
+
@ycoord = y
|
368
|
+
@adjList = Array.new
|
369
|
+
@visited = false
|
370
|
+
end
|
371
|
+
return @value
|
372
|
+
end
|
373
|
+
|
374
|
+
def init_val(value)
|
375
|
+
raise "Enter other value. Vertex with this value has been created!" if @@createdValues.include?(value)
|
376
|
+
if(!@@createdValues.include?(value))
|
377
|
+
@@createdValues << value
|
378
|
+
@value = value
|
379
|
+
@xcoord = rand(450)+30
|
380
|
+
@ycoord = rand(450)+30
|
381
|
+
coord = (xcoord.to_s + ycoord.to_s)
|
382
|
+
#to avoid overlapping vertex coordinates in canvas
|
383
|
+
while (@@position.include?(coord))
|
384
|
+
puts "regenerate to avoid collision"
|
385
|
+
@xcoord = rand(450)+30
|
386
|
+
@ycoord = rand(450)+30
|
387
|
+
coord = (xcoord.to_s + ycoord.to_s)
|
388
|
+
end
|
389
|
+
#@@position << coord
|
390
|
+
#need to add more y coord and x coord
|
391
|
+
a = 50
|
392
|
+
|
393
|
+
x = @xcoord - a
|
394
|
+
y = @ycoord - a
|
395
|
+
for i in 0..100
|
396
|
+
x = x + i
|
397
|
+
for j in 0..100
|
398
|
+
y = y + j
|
399
|
+
coord = (x.to_s + y.to_s)
|
400
|
+
@@position << coord
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
@adjList = Array.new
|
406
|
+
@visited = false
|
407
|
+
end
|
408
|
+
return @value
|
409
|
+
end
|
410
|
+
|
411
|
+
def getAdjList()
|
412
|
+
return self.adjList
|
413
|
+
end
|
414
|
+
|
415
|
+
#to add edge to this vertex
|
416
|
+
def addEdge(vertex)
|
417
|
+
raise "Value must be a Vertex!" if vertex.class != GraphLab::Vertex
|
418
|
+
raise "cannot add edge to itself" if vertex == self
|
419
|
+
adjList << vertex
|
420
|
+
end
|
421
|
+
|
422
|
+
def deleteEdge(vertex)
|
423
|
+
raise "Value must be a Vertex!" if vertex.class != GraphLab::Vertex
|
424
|
+
adjList.delete(vertex)
|
425
|
+
end
|
426
|
+
|
427
|
+
# return a string representation of the vertex
|
428
|
+
def inspect
|
429
|
+
return to_s
|
430
|
+
end
|
431
|
+
|
432
|
+
|
433
|
+
# returns a string representation of the vertex
|
434
|
+
def to_s
|
435
|
+
s = value.to_s+" ";
|
436
|
+
#s+= "("+xcoord.to_s+",";
|
437
|
+
#s+= ycoord.to_s+")";
|
438
|
+
return s;
|
439
|
+
end
|
440
|
+
|
441
|
+
def isVisited?
|
442
|
+
return @visited
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
446
|
+
|
447
|
+
class Queue
|
448
|
+
|
449
|
+
# array used to store the values in the queue
|
450
|
+
attr_reader :items
|
451
|
+
# Struct object to store the attributes of the drawn visualization
|
452
|
+
attr_accessor :drawing
|
453
|
+
|
454
|
+
# class constructor
|
455
|
+
def initialize
|
456
|
+
@items = Array.new
|
457
|
+
end
|
458
|
+
|
459
|
+
# dequeue method. if a drawing exists, redraw the canvas
|
460
|
+
def dequeue
|
461
|
+
value = items.shift
|
462
|
+
if @drawing
|
463
|
+
view_queue(self, false)
|
464
|
+
end
|
465
|
+
return value
|
466
|
+
end
|
467
|
+
|
468
|
+
# peek method. if a drawing exists, redraw the canvas
|
469
|
+
def peek
|
470
|
+
if @drawing
|
471
|
+
view_queue(self, true)
|
472
|
+
end
|
473
|
+
return items.first
|
474
|
+
end
|
475
|
+
|
476
|
+
# enqueue method. if a drawing exists, redraw the canvas
|
477
|
+
def enqueue(value)
|
478
|
+
output = items << value
|
479
|
+
if @drawing
|
480
|
+
view_queue(self, false)
|
481
|
+
end
|
482
|
+
return output
|
483
|
+
end
|
484
|
+
|
485
|
+
# return a string representation of the array
|
486
|
+
def inspect
|
487
|
+
return to_s
|
488
|
+
end
|
489
|
+
|
490
|
+
# returns a string representation of the array
|
491
|
+
def to_s
|
492
|
+
return @items.inspect
|
493
|
+
end
|
494
|
+
|
495
|
+
def isEmpty?
|
496
|
+
output = false
|
497
|
+
if(@items.size == 0)
|
498
|
+
output = true
|
499
|
+
end
|
500
|
+
return output
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class. This StackView object is being used to store the location of all the rectangles, and its corresponding values.
|
505
|
+
StackView = Struct.new(:cells, :values)
|
506
|
+
|
507
|
+
# Generates the view for a stack visualization
|
508
|
+
def view_stack(s, *peek)
|
509
|
+
# Initializes the canvas and font type
|
510
|
+
Canvas.init(400, 400, "Stack")
|
511
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 11)
|
512
|
+
|
513
|
+
stack = s.items
|
514
|
+
|
515
|
+
cells = []
|
516
|
+
values = []
|
517
|
+
|
518
|
+
# Define starting height of first rectangle
|
519
|
+
y0 = 50
|
520
|
+
Canvas::Text.new("Stack Lab", 10, 1, {:font => :bucketfont})
|
521
|
+
Canvas::Line.new(0, 20, 400, 20, :fill => :gray, :width => 1)
|
522
|
+
|
523
|
+
# If generating a peek view, color first rectangle red, and place it on the right
|
524
|
+
if peek[0] && stack[0]
|
525
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
526
|
+
cells[0].fill = 'red'
|
527
|
+
y1 = y0+3
|
528
|
+
values << Canvas::Text.new(stack[0], 65, y0+3, {:font => :bucketfont})
|
529
|
+
Canvas::Text.new("<- Top of the Stack", 200, y1, {:font => :bucketfont})
|
530
|
+
|
531
|
+
# Else place a normal rectangle
|
532
|
+
elsif stack[0]
|
533
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
534
|
+
cells[0].fill = 'grey'
|
535
|
+
y1 = y0+3
|
536
|
+
values << Canvas::Text.new(stack[0], 65, y0+3, {:font => :bucketfont})
|
537
|
+
Canvas::Text.new("<- Top of the Stack", 200, y1, {:font => :bucketfont})
|
538
|
+
end
|
539
|
+
|
540
|
+
iterations = stack.length-1
|
541
|
+
|
542
|
+
# Iterate as many times as the number of elements in the array minus one. The first element is already handled above.
|
543
|
+
iterations.times do |i|
|
544
|
+
y0 += 25
|
545
|
+
# Draw a rectangle and store a reference to this rectangle in the cells array
|
546
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
547
|
+
cells[i+1].fill = 'grey'
|
548
|
+
# Draw the text value and store a reference to this value in the values array
|
549
|
+
values << Canvas::Text.new(stack[i+1], 65, y0+3, {:font => :bucketfont})
|
550
|
+
end
|
551
|
+
|
552
|
+
if stack.length-1 > 0
|
553
|
+
Canvas::Text.new("<- Bottom of the Stack", 200, y0+3, {:font => :bucketfont})
|
554
|
+
end
|
555
|
+
|
556
|
+
# Store the properties of this drawing as a Struct object
|
557
|
+
s.drawing = StackView.new(cells, values)
|
558
|
+
return true
|
559
|
+
end
|
560
|
+
|
561
|
+
# Ruby Array-based implementation of a Stack
|
562
|
+
class Stack
|
563
|
+
|
564
|
+
# array used to store the values in the stack
|
565
|
+
attr_reader :items
|
566
|
+
# Struct object to store the attributes of the drawn visualization
|
567
|
+
attr_accessor :drawing
|
568
|
+
|
569
|
+
# class constructor
|
570
|
+
def initialize
|
571
|
+
@items = Array.new
|
572
|
+
end
|
573
|
+
|
574
|
+
# pop method. if a drawing exists, redraw the canvas
|
575
|
+
def pop
|
576
|
+
value = items.shift
|
577
|
+
if @drawing
|
578
|
+
view_stack(self, false)
|
579
|
+
end
|
580
|
+
return value
|
581
|
+
end
|
582
|
+
|
583
|
+
# peek method. if a drawing exists, redraw the canvas
|
584
|
+
def peek
|
585
|
+
if @drawing
|
586
|
+
view_stack(self, true)
|
587
|
+
end
|
588
|
+
return items.first
|
589
|
+
end
|
590
|
+
|
591
|
+
# push method. if a drawing exists, redraw the canvas
|
592
|
+
def push(value)
|
593
|
+
output = items.unshift(value)
|
594
|
+
if @drawing
|
595
|
+
view_stack(self, false)
|
596
|
+
end
|
597
|
+
return output
|
598
|
+
end
|
599
|
+
|
600
|
+
# return a string representation of the array
|
601
|
+
def inspect
|
602
|
+
return to_s
|
603
|
+
end
|
604
|
+
|
605
|
+
# returns a string representation of the array
|
606
|
+
def to_s
|
607
|
+
return @items.inspect
|
608
|
+
end
|
609
|
+
|
610
|
+
# returns the number of items currently in the stack
|
611
|
+
def count
|
612
|
+
return items.count
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
# :begin :visit
|
617
|
+
def visit(vertex)
|
618
|
+
vertex.visited = true
|
619
|
+
p vertex
|
620
|
+
end
|
621
|
+
# :end :visit
|
622
|
+
|
623
|
+
# :begin :topsort
|
624
|
+
def topsort(graph)
|
625
|
+
graph.clearAll
|
626
|
+
s = Stack.new
|
627
|
+
for i in 0..graph.vertices.length-1
|
628
|
+
vi = graph.vertices[i]
|
629
|
+
if !vi.isVisited?
|
630
|
+
topsort_dfs(vi, s)
|
631
|
+
end
|
632
|
+
end
|
633
|
+
return s
|
634
|
+
end
|
635
|
+
# :end :topsort
|
636
|
+
|
637
|
+
# :begin :topsort_dfs
|
638
|
+
def topsort_dfs(vertex, stack)
|
639
|
+
visit(vertex)
|
640
|
+
for i in 0..(vertex.adjList.length-1)
|
641
|
+
neighbor = vertex.adjList[i]
|
642
|
+
if(!neighbor.isVisited?)
|
643
|
+
topsort_dfs(neighbor, stack)
|
644
|
+
end
|
645
|
+
end
|
646
|
+
stack.push(vertex)
|
647
|
+
end
|
648
|
+
# :end :topsort_dfs
|
649
|
+
|
650
|
+
end
|