sortviz 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -35
- data/exe/sortviz +40 -19
- data/lib/algorithms/bubblesort.rb +12 -11
- data/lib/algorithms/insertionsort.rb +11 -11
- data/lib/algorithms/selectionsort.rb +12 -13
- data/lib/sortviz.rb +10 -3
- data/lib/sortviz/algorithms.rb +30 -0
- data/lib/sortviz/canvas.rb +30 -15
- data/lib/sortviz/core_ext.rb +17 -0
- data/lib/sortviz/version.rb +1 -1
- data/lib/sortviz/visualizer.rb +13 -11
- metadata +4 -3
- data/lib/sortviz/plugins.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 970249e15c43b4ade3c5ea494b42c41105854a23
|
4
|
+
data.tar.gz: a85bbd678f174d5efc01da4fe8d432fbbc450922
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
8
|
-
[lib/
|
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
|
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
|
-
|
61
|
-
|
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
|
-
|
13
|
+
Options = Struct.new(:algorithm, :speed, :path)
|
14
|
+
args = Options.new(:'bubble-sort', 0.05)
|
14
15
|
|
15
|
-
|
16
|
-
opts.banner =
|
17
|
-
USAGE: sortviz [options]
|
16
|
+
@parser = OptionParser.new do |opts|
|
17
|
+
opts.banner = 'Usage: sortviz [options] sorting_algorithm_name'
|
18
18
|
|
19
|
-
|
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::
|
36
|
-
|
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.
|
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
|
-
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
13
|
-
|
14
|
-
define_algorithm "Bubble Sort", :bubblesort
|
14
|
+
return unsorted_list
|
15
|
+
}
|
15
16
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
8
|
-
|
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
|
-
|
14
|
-
|
15
|
-
define_algorithm "Insertion Sort", :insertionsort
|
14
|
+
return unsorted_list
|
15
|
+
}
|
16
16
|
end
|
@@ -1,19 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
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...
|
9
|
-
iMin = i if
|
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
|
-
|
14
|
-
yield list, j
|
14
|
+
unsorted_list.swap!(j, iMin)
|
15
15
|
end
|
16
|
-
|
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/
|
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
|
-
|
15
|
-
|
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
|
data/lib/sortviz/canvas.rb
CHANGED
@@ -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
|
36
|
-
|
37
|
-
|
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
|
-
|
44
|
+
draw_number(number)
|
45
|
+
draw_bar(number, i == selection)
|
46
|
+
next_bar
|
47
|
+
end
|
48
|
+
|
49
|
+
Curses.doupdate
|
50
|
+
end
|
47
51
|
|
48
|
-
|
52
|
+
private
|
49
53
|
|
50
|
-
|
54
|
+
def clear
|
55
|
+
@window.clear
|
56
|
+
@window.box('|', '-')
|
57
|
+
end
|
51
58
|
|
52
|
-
|
53
|
-
|
54
|
-
|
59
|
+
def draw_title
|
60
|
+
@cursor.move(0, 0)
|
61
|
+
@cursor.tprint("Algorithm: #{@title}")
|
55
62
|
end
|
56
63
|
|
57
|
-
|
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
|
-
@
|
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
|
data/lib/sortviz/version.rb
CHANGED
data/lib/sortviz/visualizer.rb
CHANGED
@@ -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
|
-
# +
|
22
|
-
def initialize(
|
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
|
-
@
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
sleep
|
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
|
-
|
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.
|
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-
|
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
|
data/lib/sortviz/plugins.rb
DELETED
@@ -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
|