rubylabs 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,9 +1,30 @@
1
- = rubylabs
1
+ == Description
2
2
 
3
- The modules in this Gem have methods and data for lab projects in the textbook
4
- <em>The Science of Computing: A Problem Solving Approach</em>. There is one module
5
- for each chapter, plus a set of common methods shared by more than one module.
3
+ RubyLabs is a collection of modules used for tutorial exercises in the textbook
4
+ <em>{Explorations in Computing: An Introduction to Computer Science}[http://www.cs.uoregon.edu]</em>.
5
+ There is one module for each chapter in the text:
6
6
 
7
- == Copyright
7
+ <b>IntroLab[link:classes/RubyLabs/IntroLab.html]</b>:: A quick introduction to Ruby, with an exercise leading to the definition of a method to convert temperatures from Fahrenheit to Celsius.
8
+ <b>SieveLab[link:classes/RubyLabs/SieveLab.html]</b>:: A project on the Sieve of Eratosthenes, an algorithm for generating lists of prime numbers.
9
+ <b>IterationLab[link:classes/RubyLabs/IterationLab.html]</b>:: Simple iterative algorithms for searching and sorting.
10
+ <b>RecursionLab[link:classes/RubyLabs/RecursionLab.html]</b>:: More sophisticated algorithms, using a divide and conquer strategy.
11
+ <b>HashLab[link:classes/RubyLabs/HashLab.html]</b>:: Using a hash table to represent a word list, e.g. for a crossword puzzle dictionary.
12
+ <b>BitLab[link:classes/RubyLabs/BitLab.html]</b>:: Projects with binary encodings, including methods for simple error correction with parity bits and text compression with Huffman codes.
13
+ <b>MARSLab[link:classes/RubyLabs/MARSLab.html]</b>:: Using the game of Core War to explore the von Neumann architecture.
14
+ <b>RandomLab[link:classes/RubyLabs/RandomLab.html]</b>:: Creating lists of random numbers with a pseudo-random number generator.
15
+ <b>ElizaLab[link:classes/RubyLabs/ElizaLab.html]</b>:: An introduction to issues in natural language processing, using a version of ELIZA written in Ruby.
16
+ <b>SphereLab[link:classes/RubyLabs/SphereLab.html]</b>:: Introduction to modeling and simulation, culminating in an N-body simulation of the movement of planets in the Solar System.
17
+ <b>TSPLab[link:classes/RubyLabs/TSPLab.html]</b>:: Solving the Traveling Salesman Problem with a genetic algorithm.
18
+
19
+ The main *RubyLabs* module has some common methods (e.g. min and max) used throughout the book.
20
+
21
+ == Installing
22
+
23
+ == Examples
24
+
25
+ == Documentation
26
+
27
+ A lab manual is available from http://ix.cs.uoregon.edu/~conery/eic.
28
+
29
+ == Questions
8
30
 
9
- Copyright (c) 2009 John S. Conery. See LICENSE for details.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ begin
6
6
  Jeweler::Tasks.new do |gem|
7
7
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
8
8
  gem.name = "rubylabs"
9
- gem.summary = %Q{Software and data for lab projects in the Science of Computing text.}
9
+ gem.summary = %Q{Software and data for lab projects for Explorations in Computing.}
10
10
  gem.description = %Q{A set of modules for interactive experiments in an introductory computer science class.}
11
11
  gem.email = "conery@cs.uoregon.edu"
12
12
  gem.homepage = "http://github.com/conery/rubylabs"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.0
1
+ 0.8.1
@@ -57,7 +57,7 @@ remember 5
57
57
 
58
58
  if 3
59
59
  /if (.*)/
60
- "Do you think its likely that $1?"
60
+ "Do you think it's likely that $1?"
61
61
  "Do you wish that $1?"
62
62
  "What do you think about $1?"
63
63
  "Really, if $1?"
data/data/tsp/ireland.txt CHANGED
@@ -8,16 +8,16 @@
8
8
 
9
9
  :matrix driving distances (in kilometers) between cities
10
10
 
11
- belfast cork 422
12
- belfast dublin 157
13
- belfast galway 331
14
- belfast limerick 364
11
+ belfast cork 425
12
+ belfast dublin 167
13
+ belfast galway 306
14
+ belfast limerick 323
15
15
 
16
- cork dublin 254
17
- cork galway 200
18
- cork limerick 100
16
+ cork dublin 257
17
+ cork galway 209
18
+ cork limerick 105
19
19
 
20
- dublin galway 214
21
- dublin limerick 100
20
+ dublin galway 219
21
+ dublin limerick 198
22
22
 
23
- galway limerick 101
23
+ galway limerick 105
data/lib/bitlab.rb CHANGED
@@ -10,7 +10,9 @@ module RubyLabs
10
10
 
11
11
  module BitLab
12
12
 
13
- QueueView = Struct.new(:queue)
13
+ QueueView = Struct.new(:queue, :options)
14
+ NodeView = Struct.new(:circle, :text, :ftext, :lseg, :rseg)
15
+ NodeCoords = Struct.new(:x, :y, :leftedge, :leftdepth, :rightedge, :rightdepth)
14
16
 
15
17
  =begin rdoc
16
18
  Make a unique binary code for each item in array +a+, returning a Hash that
@@ -163,7 +165,7 @@ module BitLab
163
165
  while pq.length > 1
164
166
  n1 = pq.shift
165
167
  n2 = pq.shift
166
- pq << Node.combine( n1, n2)
168
+ pq << Node.combine(n1, n2)
167
169
  end
168
170
 
169
171
  return pq[0]
@@ -286,7 +288,8 @@ module BitLab
286
288
  are Nodes for the roots of subtrees.
287
289
 
288
290
  Use +new+ to create a new leaf node. Call the class method +combine+ (an alternative
289
- constructor) to make a new interior node from two existing nodes.
291
+ constructor) to make a new interior node from two existing nodes. If the tree is
292
+ being displayed on the RubyLabs canvas, make a graphic for the new interior node, too.
290
293
 
291
294
  The +<+ method allows Nodes to be compared so they can be ordered in a priority
292
295
  queue.
@@ -294,18 +297,32 @@ module BitLab
294
297
 
295
298
  class Node
296
299
 
297
- attr_accessor :freq, :char, :left, :right
298
-
300
+ attr_accessor :freq, :char, :left, :right, :drawing, :coords, :lfchain, :rfchain, :depth
301
+
299
302
  def initialize(char,freq)
300
303
  @char = char
301
304
  @freq = freq
302
305
  @left = @right = nil
303
- end
304
-
305
- def Node.combine(n1,n2)
306
- node = Node.new(nil, n1.freq + n2.freq)
307
- node.left = n1
308
- node.right = n2
306
+ @drawing = @coords = nil
307
+ @lfchain = @rfchain = self
308
+ @depth = 0
309
+ end
310
+
311
+ # todo -- need to follow chains to end when updating shallower tree
312
+
313
+ def Node.combine(leftdesc, rightdesc)
314
+ node = Node.new(nil, leftdesc.freq + rightdesc.freq)
315
+ node.left = leftdesc
316
+ node.right = rightdesc
317
+ node.depth = 1 + max(leftdesc.depth, rightdesc.depth)
318
+ node.lfchain = leftdesc
319
+ node.rfchain = rightdesc
320
+ if leftdesc.depth > rightdesc.depth
321
+ rightdesc.rfchain = leftdesc.rfchain
322
+ elsif leftdesc.depth < rightdesc.depth
323
+ leftdesc.lfchain = rightdesc.lfchain
324
+ end
325
+ draw_root(node, leftdesc, rightdesc) if (leftdesc.drawing && rightdesc.drawing)
309
326
  return node
310
327
  end
311
328
 
@@ -559,28 +576,74 @@ module BitLab
559
576
 
560
577
  end # Message
561
578
 
579
+ def move_tree(tree, dx, dy)
580
+ tree.coords.x += dx
581
+ tree.coords.y += dy
582
+ Canvas.move(tree.drawing.circle, dx, dy)
583
+ Canvas.move(tree.drawing.text, dx, dy)
584
+ Canvas.move(tree.drawing.ftext, dx, dy) if tree.drawing.ftext
585
+ if tree.left
586
+ Canvas.move(tree.drawing.lseg, dx, dy)
587
+ move_tree(tree.left, dx, dy)
588
+ end
589
+ if tree.right
590
+ Canvas.move(tree.drawing.rseg, dx, dy)
591
+ move_tree(tree.right, dx, dy)
592
+ end
593
+ Canvas.sync
594
+ end
595
+
596
+ def draw_root(node, left, right)
597
+ opts = @@drawing.options
598
+ x = (left.coords.x + right.coords.x) / 2
599
+ y = left.coords.y - 2 * @@unit
600
+ draw_node(node, x, y)
601
+ node.drawing.lseg = Canvas.line(x, y, left.coords.x, left.coords.y).lower
602
+ node.drawing.rseg = Canvas.line(x, y, right.coords.x, right.coords.y).lower
603
+ # [left, right].each do |desc|
604
+ # desc.drawing.ftext.delete
605
+ # desc.drawing.ftext = nil
606
+ # end
607
+ end
608
+
609
+ def draw_node(node, x, y)
610
+ return nil unless @@drawing
611
+ opts = @@drawing.options
612
+ d = @@unit
613
+ circ = Canvas.circle( x, y, d / 2, :fill => opts[:nodefill] )
614
+ text = Canvas.text( node.char, x, y, :anchor => :center )
615
+ ftext = Canvas.text( node.freq.to_s, x, y-d, {:font => opts[:freqfont], :anchor => :center} )
616
+ node.drawing = NodeView.new(circ, text, ftext, nil, nil)
617
+ node.coords = NodeCoords.new(x, y, x, 0, x, 0)
618
+ end
619
+
562
620
  =begin rdoc
563
621
  Initialize the canvas with a drawing of a priority queue.
564
622
  =end
565
623
 
566
- =begin
567
- TODO fill in this stub...
568
- =end
569
-
570
624
  def view_queue(pq, userOptions = {} )
571
- options = @@queueOptions.merge(userOptions)
572
- Canvas.init(300, 500, "BitLab")
573
- @@drawing = QueueView.new(pq)
625
+ options = @@queueViewOptions.merge(userOptions)
626
+ Canvas.init(options[:width], options[:height], "BitLab")
627
+ @@drawing = QueueView.new(pq, options)
628
+ options[:nodefill] = "lightgray"
629
+ options[:freqfont] = Canvas.font(:family => 'Helvetica', :size => 10)
574
630
  pq.on_canvas = true
631
+ x = options[:qx]
632
+ pq.each_with_index do |node, i|
633
+ draw_node(node, x, options[:qy])
634
+ x += 3 * @@unit
635
+ end
575
636
  Canvas.sync
576
637
  return true
577
638
  end
578
639
 
579
- def redraw_queue(pq)
580
- puts "redraw: #{pq.inspect}"
581
- end
582
-
583
- @@queueOptions = {
640
+ @@unit = 24 # pixels per "tree unit"
641
+
642
+ @@queueViewOptions = {
643
+ :width => 42 * @@unit,
644
+ :height => 15 * @@unit,
645
+ :qy => 50,
646
+ :qx => 50,
584
647
  }
585
648
 
586
649
  @@bitsDirectory = File.join(File.dirname(__FILE__), '..', 'data', 'huffman')
@@ -590,27 +653,83 @@ end # BitLab
590
653
  end # RubyLabs
591
654
 
592
655
  =begin rdoc
593
- Add hooks to the PriorityQueue's shift and << methods so they check to see if the
594
- queue is on the canvas, and if so, update the drawing when an item is removed or added.
656
+ Add an update method to the PriorityQueue so nodes are moved around on the screen when
657
+ they are removed from or added to the queue (if the queue is on the canvas).
658
+ Note: the << and shift methods call this method when @on_canvas is true....
595
659
  =end
596
660
 
661
+ =begin
662
+ TODO make time to sleep a parameter
663
+ todo add comments, rdoc
664
+ todo distance in units (down, up, spacing) should also be params
665
+ todo clean up def of Node -- coords not being used, combine with graphics
666
+ =end
597
667
  class PriorityQueue
598
668
 
599
669
  attr_accessor :on_canvas
600
670
 
601
- alias_method :pqappend, :<<
602
-
603
- def <<(obj)
604
- res = pqappend(obj)
605
- redraw_queue(self) if on_canvas
606
- return res
671
+ def update(op, node)
672
+ if op == :shift
673
+ move_tree(node, 0, 4 * @@unit) # move subtree rooted at node down 4 units
674
+ else
675
+ i = 0
676
+ dx = @@drawing.options[:qx] - left_edge(@q[0])
677
+ while @q[i] != node
678
+ move_tree(@q[i], dx, 0)
679
+ dx = 3 * @@unit - tree_sep(@q[i], node)
680
+ move_tree(node, dx, 0)
681
+ dx = 3 * @@unit - tree_sep(@q[i], @q[i+1])
682
+ i += 1
683
+ sleep(0.2)
684
+ end
685
+ move_tree(node, 0, -2 * @@unit)
686
+ if i < @q.length - 1
687
+ dx = 3 * @@unit - tree_sep(@q[i], @q[i+1])
688
+ i += 1
689
+ while i < @q.length
690
+ sleep(0.2)
691
+ move_tree(@q[i], dx, 0)
692
+ i += 1
693
+ end
694
+ end
695
+ end
607
696
  end
608
-
609
- alias_method :pqshift, :shift
610
-
611
- def shift
612
- res = pqshift
613
- redraw_queue(self) if on_canvas
697
+
698
+ def left_edge(tree)
699
+ x = tree.coords.x
700
+ while tree.lfchain != tree
701
+ tree = tree.lfchain
702
+ x = min(x, tree.coords.x)
703
+ end
704
+ return x
705
+ end
706
+
707
+ def right_edge(tree)
708
+ x = tree.coords.x
709
+ while tree.rfchain != tree
710
+ tree = tree.rfchain
711
+ x = max(x, tree.coords.x)
712
+ end
713
+ return x
714
+ end
715
+
716
+ def tree_sep(left, right)
717
+ res = right.coords.x - left.coords.x
718
+ while (left.rfchain != left && right.lfchain != right)
719
+ left = left.rfchain
720
+ right = right.lfchain
721
+ dist = right.coords.x - left.coords.x
722
+ res = dist if dist < res
723
+ end
724
+ # loop do
725
+ # puts "res = #{res}"
726
+ # break if left == left.rfchain || right == right.lfchain
727
+ # left = left.rfchain
728
+ # right = right.lfchain
729
+ # puts "down #{left.inspect} --- #{right.inspect}"
730
+ # dist = right.coords.x - left.coords.x
731
+ # res = dist if dist < res
732
+ # end
614
733
  return res
615
734
  end
616
735
 
@@ -649,3 +768,17 @@ class Fixnum
649
768
 
650
769
  end
651
770
 
771
+ =begin
772
+ TODO delete this
773
+ =end
774
+
775
+ def test_view
776
+ vf = read_frequencies(:hafreq)
777
+ pq = init_queue(vf)
778
+ view_queue(pq)
779
+ Canvas.sync
780
+ return pq
781
+ end
782
+
783
+
784
+
data/lib/demos.rb CHANGED
@@ -21,19 +21,19 @@ module Demos
21
21
  end
22
22
 
23
23
  =begin rdoc
24
- This version of the Sieve of Eratosthenes iterates until the worklist is
24
+ This version of the Sieve of Eratosthenes iterates until the worksheet is
25
25
  empty. Use it as a baseline for counting the number of iterations, to
26
26
  compare it to the actual version that iterates until finding the first
27
27
  prime greater than sqrt(n)
28
28
  =end
29
29
 
30
30
  def sieve(n)
31
- worklist = Array(2..n)
31
+ worksheet = Array(2..n)
32
32
  primes = []
33
33
 
34
- while worklist.length > 0
35
- primes << worklist.first
36
- worklist.delete_if { |x| x % primes.last == 0 }
34
+ while worksheet.length > 0
35
+ primes << worksheet.first
36
+ worksheet.delete_if { |x| x % primes.last == 0 }
37
37
  end
38
38
 
39
39
  return primes
data/lib/rubylabs.rb CHANGED
@@ -576,6 +576,7 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
576
576
  if RUBY_VERSION =~ %r{^1\.8} && RUBY_PLATFORM =~ %r{darwin} && caller[1].index("(irb)") == 0
577
577
  sleep(0.1)
578
578
  end
579
+ # @@tkroot.update :idletasks
579
580
  end
580
581
 
581
582
  =begin rdoc
@@ -585,13 +586,17 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
585
586
 
586
587
  def Canvas.text(s, x, y, opts = {})
587
588
  return nil unless @@canvas
588
- opts[:anchor] = :nw
589
+ opts[:anchor] = :nw unless opts.has_key?(:anchor)
589
590
  opts[:text] = s
590
591
  text = TkcText.new( @@canvas, x, y, opts)
591
592
  @@objects << text
592
593
  return text
593
594
  end
594
595
 
596
+ def Canvas.font(options)
597
+ return TkFont.new(options)
598
+ end
599
+
595
600
  =begin rdoc
596
601
  Draw a line from (x0,y0) to (x1,y1)
597
602
  =end
@@ -735,6 +740,10 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
735
740
  assignment via an index or any other array operation.
736
741
  The +<<+ method checks to make sure an object is comparable (responds to <) before
737
742
  adding it to the queue.
743
+
744
+ If a program that uses a priority queue adds an instance variable named @on_canvas
745
+ the shift and << methods will call a method named update so drawings that show
746
+ a queue can be updated.
738
747
  =end
739
748
 
740
749
  class PriorityQueue
@@ -751,9 +760,17 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
751
760
  i += 1
752
761
  end
753
762
  @q.insert(i, obj)
763
+ update(:insert, obj) if @on_canvas
764
+ return @q
765
+ end
766
+
767
+ def shift
768
+ res = @q.shift
769
+ update(:shift, res) if @on_canvas
770
+ return res
754
771
  end
755
772
 
756
- %w{shift length first last to_s inspect clear empty?}.each do |name|
773
+ %w{length first last to_s inspect clear empty?}.each do |name|
757
774
  eval "def #{name}() @q.#{name} end"
758
775
  end
759
776
 
@@ -764,6 +781,14 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
764
781
  def collect(&f)
765
782
  @q.map { |x| f.call(x) }
766
783
  end
784
+
785
+ def each(&b)
786
+ @q.each &b
787
+ end
788
+
789
+ def each_with_index(&b)
790
+ @q.each_with_index &b
791
+ end
767
792
 
768
793
  end # PriorityQueue
769
794
 
data/lib/sievelab.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  Use the Sieve of Eratosthenes algorithm to generate a list of prime
7
7
  numbers. The method is an introduction to iteration, using iterators
8
8
  to make and filter lists of numbers, and a while loop to repeat the
9
- filtering step until no more composite numbers are left in the worklist.
9
+ filtering step until no more composite numbers are left in the worksheet.
10
10
 
11
11
  =end
12
12
 
@@ -21,15 +21,15 @@ module SieveLab
21
21
  # :begin :sieve
22
22
  def sieve(n)
23
23
  return [] if n < 2
24
- worklist = Array(2..n)
24
+ worksheet = Array(2..n)
25
25
  primes = []
26
26
 
27
- while worklist.first < sqrt(n)
28
- primes << worklist.first
29
- worklist.delete_if { |x| x % primes.last == 0 }
27
+ while worksheet.first < sqrt(n)
28
+ primes << worksheet.first
29
+ worksheet.delete_if { |x| x % primes.last == 0 }
30
30
  end
31
31
 
32
- return primes + worklist
32
+ return primes + worksheet
33
33
  end
34
34
  # :end :sieve
35
35
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubylabs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - conery
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-05-17 00:00:00 -07:00
12
+ date: 2010-08-08 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -114,7 +114,7 @@ rubyforge_project: rubylabs
114
114
  rubygems_version: 1.3.5
115
115
  signing_key:
116
116
  specification_version: 3
117
- summary: Software and data for lab projects in the Science of Computing text.
117
+ summary: Software and data for lab projects for Explorations in Computing.
118
118
  test_files:
119
119
  - test/bit_test.rb
120
120
  - test/eliza_test.rb