sortviz 0.6.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ab0c658aff4dc772ecffcacb46cf611eabb3461
4
- data.tar.gz: 22438a128feac8deb9c70aee7c33d580d5faed1b
3
+ metadata.gz: 970249e15c43b4ade3c5ea494b42c41105854a23
4
+ data.tar.gz: a85bbd678f174d5efc01da4fe8d432fbbc450922
5
5
  SHA512:
6
- metadata.gz: 142a64eec59079b2e6e8af322a593226ebdbd04163b69f6f964b2bbe856db9a043626ea61e3d7761533afa833b1c300509983275f78416ad37a2ae98054fe880
7
- data.tar.gz: 76f9fed39164fbad24c24cef1891095e581eb551b8c967dfff3ed7b5973c8b561912525f3836da19a65b0fe0fd5499967992a27403a71ae37205be3ffef419c7
6
+ metadata.gz: 7d1545bfa711f394446dba788a9784bb045e01689f74906944e08c9d506b97afd9c69a37cf8e4629edc9c7afa9dc221a2f9a67c6c8803dce6d869f220d828167
7
+ data.tar.gz: 3c2b5d78bad824b5926debf84533a1b5fa9dcd6cbb23fddbd6738b13fec39bd11bcb46d96040e4baf51b08feba355313b1d47a466ec136546498acf97fb190ff
data/README.md CHANGED
@@ -4,30 +4,13 @@ Sortviz is a small terminal program written in Ruby and uses the Curses library
4
4
  It lets you visualize sorting algorithms, you can add more sorting algorithms
5
5
  at will but for the time being it can only load the ones bundled with itself.
6
6
 
7
- For pointers on the over simplified (Quite bad too) plugin system, check
8
- [lib/sortviz/plugins.rb](lib/sortviz/plugins.rb) and check the plugins at
9
- [lib/algorithms](lib/algorithms).
7
+ However, for pointers about writing plugins, check
8
+ [lib/algorithms](lib/algorithms) and check the plugin system at
9
+ [lib/sortviz/algorithms.rb](lib/sortviz/algorithms.rb).
10
10
 
11
11
  ## Looks like this
12
12
  ![Screenshot][screenshot]
13
13
 
14
- ## Working with Sortviz
15
-
16
- Some sorting algorithms operate on single lists, swapping and sifting through
17
- them. Others operate on multiple lists, like merge sort. With any luck, you
18
- might be able to get these kind of sorting algorithms working but until I officially test against them, you're on your own.
19
-
20
- __Generally speaking, the sorting algorithm (your code) has to yield a partially sorted list, with a current index on *every iteration*__.
21
-
22
- For examples, check the [lib/algorithms](lib/algorithms) directory.
23
-
24
- Some implementations like the bubble sort one at [lib/algorithms/bubblesort.rb](lib/algorithms/bubblesort.rb) generate some visual artifacts.
25
- If you look at it, you'd notice that the index we're yielding is +1.
26
-
27
- The reason for that is because otherwise, Sortviz will be selecting a column
28
- that might in fact be the real current index, but the actual swapping is happening a column + 1. Which becomes confusing, so we +1 to select the
29
- actual column that's moving around.
30
-
31
14
  ## Installation
32
15
 
33
16
  This gem is not intended for your application's Gemfile, it's a
@@ -40,10 +23,9 @@ install it as:
40
23
  ## Usage
41
24
 
42
25
  ```shell
43
- $ sortviz -h # Will display help
44
- $ sortviz -l # Will give you a list of available sorting algorithms
45
- $ sortviz -s ALGO # Will start visualizing the sorting of 20 digits using that algorithm
26
+ $ sortviz -h
46
27
  ```
28
+
47
29
  ## Development
48
30
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
31
 
@@ -57,18 +39,8 @@ And don't make me do your job for you. It's OSS, be reasonable.
57
39
 
58
40
  ## Why
59
41
 
60
- Because I'm a terminal guy that's why. I like to think I'm not too
61
- bad googling either and for the life of me I couldn't find anything similar
62
- when a buddy of mine that teaches CS at a university was like, I need a terminal based sorting visualizer. I'm like PSH! Like there has to be some out there, lo-and-behold, they're all web and javascript based.
63
-
64
- I'm also using this as a demo for an interview, hope it works out. They asked
65
- for code I'm most proud of, pretty hard question to find an answer to, as it turns out.
66
- It's not like I write code I'm not generally proud of but yeah, was a real
67
- bummer looking over everything I worked in, so this is my solution.
68
-
69
- Am I proud of it? Well yes, could be way better but I'm pressed on time.
70
-
71
- *I also realized the notion of being proud of something is more of a process, after you've invested time and effort into something and grew it, you can't help but feel proud of it.*
42
+ I blogged about this here:
43
+ [Software, a labor of love](http://hadyahmed.com/2016/06/software-a-labor-of-love/)
72
44
 
73
45
  ## Future
74
46
 
data/exe/sortviz CHANGED
@@ -10,37 +10,58 @@
10
10
  require 'optparse'
11
11
  require "sortviz"
12
12
 
13
- options = {}
13
+ Options = Struct.new(:algorithm, :speed, :path)
14
+ args = Options.new(:'bubble-sort', 0.05)
14
15
 
15
- oparser = OptionParser.new do |opts|
16
- opts.banner = <<-HELP
17
- USAGE: sortviz [options]
16
+ @parser = OptionParser.new do |opts|
17
+ opts.banner = 'Usage: sortviz [options] sorting_algorithm_name'
18
18
 
19
- Exit: Use 'q' to exit during visualization
20
-
21
- HELP
22
-
23
- opts.on('-s', '--sort ALGORITHM', 'Visualize sorting ALGORITHM (Default: bubblesort)') do |algo|
24
- if Sortviz::ALGORITHMS.has_key? algo.to_sym
25
- Sortviz.init(algo.to_sym)
26
- else
27
- puts "We couldn't find this algorithm, please check available algorithms through -l option"
28
- exit
29
- end
19
+ opts.on('-sSPEED', '--sorting-speed=SPEED', OptionParser::DecimalNumeric, 'Set the sorting speed in seconds') do |speed|
20
+ args.speed = speed
30
21
  end
31
22
 
32
23
  opts.on('-l', '--list', 'List of available sorting algorithms') do
33
24
  puts "Sortviz: List of available algorithms"
34
25
  puts "-------------------------------------"
35
- Sortviz::ALGORITHMS.each do |func_name, name|
36
- puts " #{name} (-s #{func_name})"
26
+ Sortviz::Algorithms.plugins.each do |plugin|
27
+ print "#{plugin[:display_name]} \n"
28
+ print "\t Use as: sortviz #{plugin[:name]} \n"
29
+ print "\t Author: #{plugin[:author]} \n"
37
30
  end
31
+ exit
38
32
  end
39
33
 
40
- opts.on('-h', '--help', 'View this help') do
34
+ opts.on_tail('-h', '--help', 'Show this message') do
41
35
  puts opts
42
36
  exit
43
37
  end
38
+
39
+ opts.on_tail('--version', 'Show version') do
40
+ puts "Sortviz v#{Sortviz::VERSION}"
41
+ exit
42
+ end
44
43
  end
45
44
 
46
- oparser.parse!(ARGV)
45
+ def show_help(message = nil)
46
+ print "#{message} \n\n" unless message.nil?
47
+ puts @parser
48
+ exit -1
49
+ end
50
+
51
+ if ARGV.empty?
52
+ show_help
53
+ else
54
+ begin
55
+ @parser.parse!(ARGV)
56
+ rescue OptionParser::MissingArgument => missing
57
+ print "Error: #{missing.to_s} \n\n"
58
+ show_help
59
+ end
60
+
61
+ algorithm = Sortviz.find_algorithm(ARGV.pop)
62
+ show_help("Error: Please specify the algorithm name") if algorithm.nil?
63
+
64
+ args.algorithm = algorithm
65
+
66
+ Sortviz.init(args)
67
+ end
@@ -1,15 +1,16 @@
1
- module Sortviz
2
-
3
- def bubblesort(list)
4
- list.each_index do |i|
5
- (list.length - i - 1).times do |j|
6
- if list[j] > list[j + 1]
7
- list[j], list[j + 1] = list[j + 1], list[j]
1
+ Sortviz::Algorithms.define 'Bubble Sort' do
2
+ author 'ieatkimchi'
3
+ url 'https://github.com/ieatkimchi/Bubble_Sort_Ruby'
4
+ name :'bubble-sort'
5
+
6
+ sort -> (unsorted_list){
7
+ unsorted_list.each_index do |i|
8
+ (unsorted_list.length - i - 1).times do |j|
9
+ if unsorted_list[j] > unsorted_list[j + 1]
10
+ unsorted_list.swap!(j, j+1)
8
11
  end
9
- yield list, j + 1
10
12
  end
11
13
  end
12
- end
13
-
14
- define_algorithm "Bubble Sort", :bubblesort
14
+ return unsorted_list
15
+ }
15
16
  end
@@ -1,16 +1,16 @@
1
- module Sortviz
2
- # insertion_sort is brought in from
3
- # https://coderwall.com/p/z8vowg/simple-sorting-algorithms-with-ruby
4
- def insertionsort(list)
5
- (1...list.size).each do |i|
1
+ Sortviz::Algorithms.define 'Insertion Sort' do
2
+ author 'Emad Elsaid'
3
+ url 'https://coderwall.com/p/z8vowg/simple-sorting-algorithms-with-ruby'
4
+ name :'insertion-sort'
5
+
6
+ sort -> (unsorted_list) {
7
+ (1...unsorted_list.size).each do |i|
6
8
  j = i
7
- while j > 0 and list[j-1] > list[j]
8
- list[j], list[j-1] = list[j-1], list[j]
9
+ while j > 0 and unsorted_list[j-1] > unsorted_list[j]
10
+ unsorted_list.swap!(j, j-1)
9
11
  j = j - 1
10
- yield list, j
11
12
  end
12
13
  end
13
- end
14
-
15
- define_algorithm "Insertion Sort", :insertionsort
14
+ return unsorted_list
15
+ }
16
16
  end
@@ -1,19 +1,18 @@
1
- module Sortviz
2
- # selection_sort is brought in from
3
- # https://coderwall.com/p/z8vowg/simple-sorting-algorithms-with-ruby
4
- def selectionsort(list)
5
- (0...list.size).each do |j|
1
+ Sortviz::Algorithms.define 'Selection Sort' do
2
+ author 'Emad Elsaid'
3
+ url 'https://coderwall.com/p/z8vowg/simple-sorting-algorithms-with-ruby'
4
+ name :'selection-sort'
5
+
6
+ sort -> (unsorted_list) {
7
+ (0...unsorted_list.size).each do |j|
6
8
  # find index of minimum element in the unsorted part
7
9
  iMin = j
8
- (j+1...list.size).each do |i|
9
- iMin = i if list[i] < list[iMin]
10
+ (j+1...unsorted_list.size).each do |i|
11
+ iMin = i if unsorted_list[i] < unsorted_list[iMin]
10
12
  end
11
-
12
13
  # then swap it
13
- list[j], list[iMin] = list[iMin], list[j]
14
- yield list, j
14
+ unsorted_list.swap!(j, iMin)
15
15
  end
16
- end
17
-
18
- define_algorithm "Selection Sort", :selectionsort
16
+ return unsorted_list
17
+ }
19
18
  end
data/lib/sortviz.rb CHANGED
@@ -1,18 +1,25 @@
1
1
  require 'curses'
2
2
  require 'forwardable'
3
3
  require 'sortviz/version'
4
+ require 'sortviz/core_ext'
4
5
  require 'sortviz/cursor'
5
6
  require 'sortviz/canvas'
6
7
  require 'sortviz/visualizer'
7
- require 'sortviz/plugins'
8
+ require 'sortviz/algorithms'
8
9
 
9
10
  libdir = File.dirname(__FILE__)
10
11
  Dir[libdir + '/algorithms/*.rb'].each {|file| require file }
11
12
 
12
13
  module Sortviz
13
14
  extend self
14
- def init(algo)
15
- visualizer = Visualizer.new algo
15
+
16
+ def find_algorithm(algorithm)
17
+ return nil if algorithm.nil?
18
+ Algorithms.plugins.find { |plugin| plugin[:name] == algorithm.to_sym }.freeze
19
+ end
20
+
21
+ def init(args)
22
+ visualizer = Visualizer.new args
16
23
  visualizer.visualize
17
24
  end
18
25
  end
@@ -0,0 +1,30 @@
1
+ module Sortviz
2
+ class Algorithms
3
+ class << self
4
+ def define(algorithm_name, &block)
5
+ plugins << { display_name: algorithm_name }
6
+ instance_eval &block
7
+ end
8
+
9
+ def plugins
10
+ @plugins ||= []
11
+ end
12
+
13
+ def sort(block)
14
+ Algorithms.plugins.last[:sort] = block
15
+ end
16
+
17
+ def name(name)
18
+ plugins.last[:name] = name
19
+ end
20
+
21
+ def author(author)
22
+ plugins.last[:author] = author
23
+ end
24
+
25
+ def url(link)
26
+ plugins.last[:url] = link
27
+ end
28
+ end
29
+ end
30
+ end
@@ -25,45 +25,60 @@ module Sortviz
25
25
  @screen_dim[:lines] - MARGIN,
26
26
  @screen_dim[:cols] - MARGIN,
27
27
  @cursor.y, @cursor.x)
28
- @window.box('|', '-')
29
28
  @window.nodelay = 1 # Non-blocking mode for #getch
30
29
  end
31
30
 
32
31
  # Draws the partially sorted list and highlights the current index
33
32
  # It also attempts to center the graph in the display area, does well but
34
33
  # not always, sometimes it'll be shifted to the right a bit.
35
- def redraw(partially_sorted, selected_indx)
36
- @window.clear
37
- @window.box('|', '-')
38
-
39
- @cursor.move(0, 0)
40
- @cursor.tprint("Algorithm: #{@title}")
34
+ def draw(partially_sorted, selection)
35
+ clear
36
+ draw_title
41
37
 
42
38
  len = partially_sorted.join.center(4).length
39
+ # We draw bottom up, this sets our y-position at the very bottom of
40
+ # the canvas and our x-position half way through the canvas
43
41
  @cursor.move(@window.maxy - 1, (@window.maxx - len) / MARGIN)
44
42
 
45
43
  partially_sorted.each_with_index do |number, i|
46
- @cursor.tprint(("|%02d|" % number))
44
+ draw_number(number)
45
+ draw_bar(number, i == selection)
46
+ next_bar
47
+ end
48
+
49
+ Curses.doupdate
50
+ end
47
51
 
48
- @cursor.decr_y
52
+ private
49
53
 
50
- draw_bar(number, selected_indx == i)
54
+ def clear
55
+ @window.clear
56
+ @window.box('|', '-')
57
+ end
51
58
 
52
- @cursor.move_y(@window.maxy - 1)
53
- @cursor.incr_x MARGIN
54
- end
59
+ def draw_title
60
+ @cursor.move(0, 0)
61
+ @cursor.tprint("Algorithm: #{@title}")
55
62
  end
56
63
 
57
- private
64
+ def draw_number(number)
65
+ @cursor.tprint(("|%02d|" % number))
66
+ @cursor.decr_y
67
+ end
58
68
 
59
69
  def draw_bar(height, highlighted)
60
70
  attr = highlighted ? @red_highlight : Curses::A_REVERSE
61
71
  attron(attr)
62
72
  height.times do
63
- @window.addstr(" ".center(4)) # 4 spaces
73
+ @cursor.tprint(" ".center(4)) # 4 spaces
64
74
  @cursor.decr_y
65
75
  end
66
76
  attroff(attr)
67
77
  end
78
+
79
+ def next_bar
80
+ @cursor.move_y(@window.maxy - 1)
81
+ @cursor.incr_x MARGIN
82
+ end
68
83
  end
69
84
  end
@@ -0,0 +1,17 @@
1
+ # TODO: Use refinements
2
+ class Array
3
+ def versions
4
+ @versions ||= Array.new
5
+ end
6
+
7
+ def swap!(a, b)
8
+ self[a], self[b] = self[b], self[a]
9
+ mark_version(b)
10
+ end
11
+
12
+ private
13
+ # idx: Current selection index
14
+ def mark_version(idx)
15
+ versions << [self.dup, idx]
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Sortviz
2
- VERSION = "0.6.1"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -13,20 +13,22 @@ module Sortviz
13
13
  class Visualizer
14
14
  # Origin starts at (1, 0) not (0, 0)
15
15
  ORIGIN = { y: 1, x: 5 }
16
- SLEEP_INTERVAL = 0.05
17
16
 
18
17
  # Initializes a new Visualizer for a sorting algorithm
19
18
  #
20
19
  # Params:
21
- # +algo+:: <tt>Symbol</tt> A symbol representing a sorting algorithm method
22
- def initialize(algo)
20
+ # +args+:: <tt>Struct</tt> Command line args that configure how visualization will happen
21
+ def initialize(args)
23
22
  setup_curses
24
23
  @screen_dim = { cols: Curses.cols - ORIGIN[:x], lines: Curses.lines }
25
24
  @screen = Curses.stdscr
26
25
  @cursor = Cursor.new(@screen, ORIGIN)
27
- @canvas = Canvas.new(ALGORITHMS[algo], @cursor, @screen_dim)
28
26
 
29
- @algo = algo
27
+ @algorithm = args.algorithm
28
+
29
+ @canvas = Canvas.new(@algorithm[:display_name], @cursor, @screen_dim)
30
+
31
+ @sorting_speed = args.speed
30
32
  @unsorted_list = generate_list
31
33
  end
32
34
 
@@ -69,13 +71,13 @@ module Sortviz
69
71
 
70
72
  @cursor.switch_window @canvas.window
71
73
 
72
- loop do
73
- Sortviz.send(@algo, @unsorted_list) do |partially_sorted, selected_indx|
74
- @canvas.redraw(partially_sorted, selected_indx)
75
- Curses.doupdate
76
- sleep SLEEP_INTERVAL
74
+ while true do
75
+ result = @algorithm[:sort].call(@unsorted_list)
76
+ result.versions.each do |version|
77
+ @canvas.draw(version[0], version[1])
78
+ sleep @sorting_speed
77
79
  return if @canvas.getch
78
- end
80
+ end
79
81
  @cursor.switch_window @screen # Switch back to our stdscr
80
82
  @cursor.restore # Restoring here, would place us right under the canvas box
81
83
  @cursor.newline
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sortviz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hady Ahmed
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-20 00:00:00.000000000 Z
11
+ date: 2016-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -91,9 +91,10 @@ files:
91
91
  - lib/algorithms/insertionsort.rb
92
92
  - lib/algorithms/selectionsort.rb
93
93
  - lib/sortviz.rb
94
+ - lib/sortviz/algorithms.rb
94
95
  - lib/sortviz/canvas.rb
96
+ - lib/sortviz/core_ext.rb
95
97
  - lib/sortviz/cursor.rb
96
- - lib/sortviz/plugins.rb
97
98
  - lib/sortviz/version.rb
98
99
  - lib/sortviz/visualizer.rb
99
100
  - screenshot.png
@@ -1,21 +0,0 @@
1
- module Sortviz
2
- extend self
3
- ALGORITHMS = {}
4
-
5
- # Defines a new algorithm for sorting by adding some meta data to
6
- # <tt>Sortviz::ALGORITHMS</tt> and turning the sorting algorithm method into a
7
- # Module function of <tt>Sortviz</tt>.
8
- #
9
- # It's a bad design, should be fixed soon with a proper plugin system as this
10
- # way pollutes the Sortviz namespace.
11
- #
12
- # Params:
13
- # +name+:: <tt>String</tt> Name of the sorting algorithm for display purposes
14
- # +func_name+:: <tt>Symbol</tt> A symbol representation of the actual method that does
15
- # the actual sorting. It's important that both match or else <tt>Sortviz::Visualizer</tt>
16
- # will not be able to find it and call it.
17
- def define_algorithm(name, func_name)
18
- ALGORITHMS[func_name] = name
19
- module_function func_name
20
- end
21
- end