Created
September 6, 2013 03:15
Revisions
-
alexdantas created this gist
Sep 6, 2013 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,284 @@ #!/usr/bin/env ruby # # pipes.rb: Displays a nice animation on the terminal, # based on an old screensaver. # # If you want to see some action, scroll to the bottom. # The main code is between "begin" and "end". # # This code uses Ruby and it's Curses module to display # characters on the terminal. # # I've tried to keep the code clean but it's a mess by # now. Hey, I was excited when coding, don't blame me. # # This code is DEFINITELY not Rubyish. Looks like a messed # up C/C++ cousing. Maybe that creepy uncle who shows up # at birthday parties. require 'curses' # Awesome terminal-handling library # Since Ruby doesn't natively supports "enums", I've # used a lot of labels (those things with ':') # If you find a better one, please tell me (eu@alexdantas.net) :direction_left :direction_right :direction_up :direction_down # Represents a single pipe, that will scroll around the # screen, leaving a colourful trail behind. class Pipe # It's public components. attr_reader :x, :y, :behaviour # All possible colors that a pipe can have. Colors = { :black => 1, :white => 2, :red => 3, :yellow => 4, :magenta => 5, :blue => 6, :green => 7, :cyan => 8 }.freeze # The possible ways a pipe can behave. # Nice little feature, right? Behaviour = [:dumb, # Randomly decide where to go :line, # Keep making long lines :curvy] # Make a lot of curves # Constructor, creates a pipe. def initialize(x, y, behaviour = :dumb, color = Colors[:cyan]) @x = x @y = y @appearance = '-' @previous_dir = :direction_right @current_dir = :direction_right @color = Curses::color_pair color @behaviour = behaviour end # Shows the pipe on the screen. # This is VERY UGLY, DAMn. def print # If we're changing direction it's best to use '+' instead # of '-' or '|' if @current_dir == :direction_right or @current_dir == :direction_left if (@previous_dir == :direction_up or @previous_dir == :direction_down) @appearance = '+' else @appearance = '-' end elsif @current_dir == :direction_up or @current_dir == :direction_down if (@previous_dir == :direction_left or @previous_dir == :direction_right) @appearance = '+' else @appearance = '|' end end Curses::setpos(@y, @x) Curses::attrset @color Curses::addstr @appearance Curses::refresh end # Refreshes the pipe's direction. # If `change_direction` is true, forces the pipe to # do it. # If not, it will keep on it's current way. def refresh_direction(change_direction) dir = @current_dir if change_direction begin # Getting a random direction result = Random.new.rand(1..4) if result == 1; dir = :direction_left elsif result == 2; dir = :direction_up elsif result == 3; dir = :direction_right else dir = :direction_down end end while not is_valid_movement? dir end @previous_dir = @current_dir @current_dir = dir end # Tells if we can move the cursor to the next direction. # Invalid movements will be returning 180o. def is_valid_movement? dir if (@current_dir == :direction_right and dir == :direction_left) or (@current_dir == :direction_left and dir == :direction_right) or (@current_dir == :direction_up and dir == :direction_down) or (@current_dir == :direction_down and dir == :direction_up) return false else return true end end # Actually steps the terminal a position on the screen, # based on it's internal directions. def move if @current_dir == :direction_right; @x += 1 elsif @current_dir == :direction_left; @x -= 1 elsif @current_dir == :direction_up; @y -= 1 elsif @current_dir == :direction_down; @y += 1 end out_of_screen = false if @x < 0 @x = Curses::cols - 1 out_of_screen = true elsif @x > Curses::cols - 1 @x = 0 out_of_screen = true end if @y < 0 @y = Curses::lines - 1 out_of_screen = true elsif @y > Curses::lines - 1 @y = 0 out_of_screen = true end self.change_color if out_of_screen end # Randomly changes the pipe's color. def change_color result = Random.new.rand(Colors[:red]..Colors[:cyan]) # first..last @color = Curses::color_pair result # Randomly choosing between normal and bold @color = @color | Curses::A_BOLD if random_bool end # Updates all the pipe's internal stuff. def update if @behaviour == :dumb if random_bool self.refresh_direction true else self.refresh_direction false end elsif @behaviour == :line if random_bool_with_chance 0.2 self.refresh_direction true else self.refresh_direction false end elsif @behaviour == :curvy if random_bool_with_chance 0.8 self.refresh_direction true else self.refresh_direction false end end self.print self.move end end # Initializes the curses engine. # ugly function is ugly D: def curses_init timeout Curses::init_screen Curses::start_color Curses::init_pair(Pipe::Colors[:black], Curses::COLOR_BLACK, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:white], Curses::COLOR_WHITE, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:red], Curses::COLOR_RED, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:yellow], Curses::COLOR_YELLOW, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:magenta], Curses::COLOR_MAGENTA, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:blue], Curses::COLOR_BLUE, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:green], Curses::COLOR_GREEN, Curses::COLOR_BLACK) Curses::init_pair(Pipe::Colors[:cyan], Curses::COLOR_CYAN, Curses::COLOR_BLACK) Curses::curs_set 0 Curses::noecho Curses::nonl Curses::timeout = timeout Curses::refresh end # Returns randomly 'true' or 'false'. def random_bool result = Random.new.rand(1..10) if (result % 2) == 0 # is even return true else return false end end # Returns 'true' or 'false' with a probability of 'chance' def random_bool_with_chance chance result = Random.new.rand(1..100) return true if (result <= (chance*100)) return false end # Here's the main function! # _ _ __ # (_) / \ \ # _ __ ___ __ _ _ _ __ | | | | # | '_ ` _ \ / _` | | '_ \| | | | # | | | | | | (_| | | | | | | | | # |_| |_| |_|\__,_|_|_| |_| | | | # \_ /_/ begin timeout = 50 # default delay in miliseconds curses_init timeout pipes = [Pipe.new(Curses::cols/2, Curses::lines/2, :dumb, Pipe::Colors[:cyan]), Pipe.new(Curses::cols/4, Curses::lines/8, :line, Pipe::Colors[:red]), Pipe.new(Curses::cols/8, Curses::lines/4, :curvy, Pipe::Colors[:magenta])] while true # Updating all pipes for i in 0..(pipes.size-1) pipes[i].update end # This is where the timeout delay happens. case Curses::getch when 'q', 'Q' # quit break when 'a', 'A' # faster! timeout -= 10 timeout = 10 if timeout < 10 Curses::timeout = timeout when 's', 'S' # slower! timeout += 10 timeout = 50 if timeout > 50 Curses::timeout = timeout when 'c', 'C' # clear Curses::clear Curses::refresh end end exit 0 end