some refactoring
[ruby_quiz.git] / lcd.rb
1 #! /usr/bin/env ruby
2
3 class LCD
4
5   # the display data for each digit at scale == 1
6   # each digit is a 3 x 5 array of characters.
7   @@display_data = {
8     0 => [ " - ", "| |", "   ", "| |", " - " ],
9     1 => [ "   ", "  |", "   ", "  |", "   " ],
10     2 => [ " - ", "  |", " - ", "|  ", " - " ],
11     3 => [ " - ", "  |", " - ", "  |", " - " ],
12     4 => [ "   ", "| |", " - ", "  |", "   " ],
13     5 => [ " - ", "|  ", " - ", "  |", " - " ],
14     6 => [ " - ", "|  ", " - ", "| |", " - " ],
15     7 => [ " - ", "  |", "   ", "  |", "   " ],
16     8 => [ " - ", "| |", " - ", "| |", " - " ],
17     9 => [ " - ", "| |", " - ", "  |", " - " ]
18   }
19
20   def initialize(scale)
21     @scale = Integer(scale)
22   end
23
24   def find_digits(number)
25     number = Integer(number)
26     digits = []
27     while number > 0
28       number, digit = number.divmod(10)
29       digits.unshift(digit)
30     end
31     digits
32   end
33
34   def generate_display_row(digits, line)
35     row = ""
36     digits.each do |digit|
37       row << @@display_data[digit][line] << " "
38     end
39     row << "\n"
40   end
41
42   # Given a newline terminated row, scale it both horizontally and
43   # vertically
44   def scale_row(row)
45     result = ""
46     (0..row.length).each do |index|
47       # repeat the middle character of each digit @scale times.  At
48       # scale 1, each char is 3 wide, plus a single space separator
49       next unless row[index]
50       result << (index % 4 == 1 ? row[index] * @scale : row[index])
51     end
52
53     if row =~ /\|/
54       result *= @scale
55     end
56     result
57   end
58
59   # Given a number to display, print it out at scale
60   def draw(number)
61     # decompose our number into an array of digits
62     digits = find_digits(number)
63
64     # construct a series of rows that compose the display
65     rows = []
66     (0..4).each do |line|
67       rows << scale_row(generate_display_row(digits, line))
68     end
69
70     print rows.join("")
71   end
72 end
73
74 if __FILE__ == $0
75   # parse options
76   require 'optparse'
77
78   options = {}
79   optparse = OptionParser.new do |opts|
80     opts.banner = "usage: lcd.rb [-s scale] number"
81     options[:scale] = 2
82     opts.on( '-s', '--scale SIZE', "display using scale") do |size|
83       options[:scale] = size
84     end
85   end
86
87   optparse.parse!
88
89   display = LCD.new(options[:scale])
90   number  = ARGV.shift || 0
91
92   display.draw(number)
93 end