class Sortviz::Visualizer
Visualizer
is the entry point of Sortviz
, given an algorithm name it'll initialize Curses library, a Sortviz::Canvas
with proper screen dimensions and a Sortviz::Cursor
.
It also generates a shuffled list of numbers counting from 1 to n, n is decided by Sortviz::Visualizer#generate_list
which calculates the number of bar charts that can be drawn given the current screen size.
Notice: Curses coordinates are treated in reverse, (y, x) and x represents the number of columns, y represents the number of lines so (y, x) is (cols, lines). As a result of that we too, use (y, x).
Constants
- ORIGIN
Origin starts at (1, 0) not (0, 0)
Public Class Methods
Initializes a new Visualizer
for a sorting algorithm
Params:
args
-
Struct
Command line args that configure how visualization will happen
# File lib/sortviz/visualizer.rb, line 21 def initialize(args) setup_curses @screen_dim = { cols: Curses.cols - ORIGIN[:x], lines: Curses.lines } @screen = Curses.stdscr @cursor = Cursor.new(@screen, ORIGIN) @algorithm = args.algorithm @canvas = Canvas.new(@algorithm[:display_name], @cursor, @screen_dim) @sorting_speed = args.speed @unsorted_list = generate_list end
Public Instance Methods
Starts the actual visualization
-
First prints the program's banner
-
Sets up the canvas (
Sortviz::Canvas
) -
Caches the cursor location so we can return to our original location later
-
Refreshes the current standard screen first
-
Refreshes the canvas
-
Finally we switch input to the canvas through
Sortviz::Cursor#switch_window
The order is important because curses works in such a way that the last thing on display is the last thing refreshed, if we had refreshed canvas first, it would have been drawn normally, then we refresh the standard screen (in which the canvas is inside) it'll do just that refreshs and overrides the canvas.
The loop¶ ↑
In order to draw every returned partially sorted list from the algorithm method we have to loop, clearing the canvas everytime and redrawing it then telling Curses to apply these drawn updates. This helps with flicker but I still seem to be getting some of it ever since I introduced the Curses::A_REVERSE
attribute.
Durring the loop, we're trapped inside the sorting method, as a block of code that gets yielded to on every iteration of the sorting algorithm. To exit that at anytime during the sorting run, we capture the keyboard and return if any key is pressed, the canvas has Curses::Window#getch
on non-block mode so it doesn't block waiting for a character.
Finally, we make sure both the canvas and the standard screen are closed. It's important to note that we also poll on keyboard after we exit the sorting method. In order to allow the user a moment to see the final sorted graph.
# File lib/sortviz/visualizer.rb, line 63 def visualize begin banner @canvas.setup @cursor.cache @screen.refresh @canvas.refresh @cursor.switch_window @canvas.window while true do result = @algorithm[:sort].call(@unsorted_list) result.versions.each do |version| @canvas.draw(version[0], version[1]) sleep @sorting_speed return if @canvas.getch end @cursor.switch_window @screen # Switch back to our stdscr @cursor.restore # Restoring here, would place us right under the canvas box @cursor.newline @cursor.tprint("Press any key to exit") break if Curses.getch end ensure @canvas.close Curses.close_screen end end
Private Instance Methods
We want to know how much can we draw depending on the window size To do that, we know that a single bar takes up 4 columns '|00|'' (bar_len) We also know that we add 5 columns between bars (Canvas::MARGIN) So we take cols/bar_len + CANVAS::MARGIN = n_bars
# File lib/sortviz/visualizer.rb, line 109 def generate_list n = @screen_dim[:cols] / (4 + Canvas::MARGIN) (1..n).to_a.shuffle end
# File lib/sortviz/visualizer.rb, line 94 def setup_curses Curses.init_screen Curses.noecho Curses.curs_set(0) # Hide cursor Curses.start_color # Kick off colored output Curses.use_default_colors # We only need Red Curses.init_pair(Curses::COLOR_RED, -1, Curses::COLOR_RED) end