[QUIZ] LCD Numbers (#14)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.grayproductions.net/ruby_quiz/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

This week's quiz is to write a program that displays LCD style numbers at
adjustable sizes.

The digits to be displayed will be passed as an argument to the program. Size
should be controlled with the command-line option -s follow up by a positive
integer. The default value for -s is 2.

For example, if your program is called with:

  > lcd.rb 012345

The correct display is:

   -- -- -- --
  > > > > > > > >
  > > > > > > > >
             -- -- -- --
  > > > > > > >
  > > > > > > >
   -- -- -- --

And for:

  > lcd.rb -s 1 6789

Your program should print:

   - - - -
  > > > > > >
   - - -
  > > > > > >
   - - -

Note the single column of space between digits in both examples. For other
values of -s, simply lengthen the - and | bars.

Question, I assume the idea is for a 7 seqment LCD?

Also just wanted to say that the formatting on the quiz page

http://www.grayproductions.net/ruby_quiz/quiz14.html

is broken for the examples.

This quiz got my attention. I can't wait until I get home from work and can do this one...this one just looks so fun

=)

Zach

Here's my solution:

**************************** [begin code ] ****************************

#!/usr/local/bin/ruby -w

require 'getoptlong'

# ---------------------------------------------------------------------

class Digit
    
    @@chars = [ " ", "-", "|" ]
    @@segments =
    [
        [ [0,1,0], [2,0,2], [0,0,0], [2,0,2], [0,1,0] ], # 0
        [ [0,0,0], [0,0,2], [0,0,0], [0,0,2], [0,0,0] ], # 1
        [ [0,1,0], [0,0,2], [0,1,0], [2,0,0], [0,1,0] ], # 2
        [ [0,1,0], [0,0,2], [0,1,0], [0,0,2], [0,1,0] ], # 3
        [ [0,0,0], [2,0,2], [0,1,0], [0,0,2], [0,0,0] ], # 4
        [ [0,1,0], [2,0,0], [0,1,0], [0,0,2], [0,1,0] ], # 5
        [ [0,1,0], [2,0,0], [0,1,0], [2,0,2], [0,1,0] ], # 6
        [ [0,1,0], [0,0,2], [0,0,0], [0,0,2], [0,0,0] ], # 7
        [ [0,1,0], [2,0,2], [0,1,0], [2,0,2], [0,1,0] ], # 8
        [ [0,1,0], [2,0,2], [0,1,0], [0,0,2], [0,1,0] ] # 9
    ]
    
    attr_reader :height
    
    def initialize( num, size )
        @matrix = @@segments[ num ]
        @height = @matrix.size
        self.scale_to_size( size ) if size > 1
    end
    
    def scale_to_size( size )
        t = size - 1
        @matrix.each { |l| t.times { l.insert(-2, 0) } }
        @matrix.each { |l| l.fill(1, l.index(1),size) if l.include?(1) }
        t.times { @matrix.insert( 1, @matrix[1]) }
        t.times { @matrix.insert(-2, @matrix[-2]) }
        @height = @matrix.size
    end
    
    def display_line( line )
        @matrix[ line ].each { |c| print @@chars[c] }
        print " "
    end
    
end

# ---------------------------------------------------------------------

class LCD
    
    def initialize( num, size=1 )
        @digits = Array.new
        num.each_byte { |b| @digits << Digit.new( b.to_i - 48, size ) }
    end
    
    def display
        for line in 0...@digits.first.height
            @digits.each { |d| d.display_line( line ) }
            puts
        end
    end
    
end

# ---------------------------------------------------------------------

def print_usage( message=nil )
    puts "Usage: lcd [-s size] digits"
end

# ---------------------------------------------------------------------

print_usage & exit if ARGV.empty?

size = 2
opts = GetoptLong.new( ["--size", "-s", GetoptLong::REQUIRED_ARGUMENT] )
opts.each { |opt, val| size = val.to_i if opt == "--size" }

print_usage & exit if ARGV.empty?

digits = ARGV[0].gsub( /[^0-9]/, "" )
lcd = LCD.new( digits, size )
lcd.display

# ---------------------------------------------------------------------

**************************** [end code ] ******************************

···

Ruby Quiz <james@grayproductions.net> wrote:

This week's quiz is to write a program that displays LCD style numbers at
adjustable sizes.

--
Luc Heinrich - lucsky@mac.com

Hi!

Thanks for the quiz, it was really fun to code :slight_smile:
Here is my variant:

···

#####################################################
#!/usr/bin/env ruby

def usage
   print "\n\nUsage: lcd.rb [-s <size>] <digits>\n\n",
         " -s digit size (positive integer), default is 2\n",
         " digits digits to display as lcd\n\n\n"
   exit 1
end

def draw_part_of_digit(d, s, state)
   case state
     when "top"
       print " #{(d == 1 or d == 4) ? ' ' * s : '-' * s} "

     when "up_half"
       print "#{(d.between?(1, 3) or d == 7) ? ' ' : '|'}",
             ' ' * s,
             "#{d.between?(5, 6) ? ' ' : '|'}"

     when "middle"
       print " #{(d.between?(0, 1) or d == 7) ? ' ' * s : '-' * s} "

     when "down_half"
       print "#{(d == 0 or d == 2 or d == 6 or d == 8) ? '|' : ' '}",
             ' ' * s,
             "#{d == 2 ? ' ' : '|'}"

     when "bottom"
       print " #{(d == 1 or d == 4 or d == 7) ? ' ' * s : '-' * s} "

   end # case
end

digits = []
size = 2

if ARGV.join(" ") =~ /^(-s ([1-9]\d*) ){0,1}(\d+)$/
   size = $2.to_i if $2
   $3.each_byte {|i| digits << i - 48}
else
   usage
end

state = "top"

(3 + size * 2).times { |i|
   case i
     when 1 : state = "up_half"
     when 1 + size : state = "middle"
     when 2 + size : state = "down_half"
     when 2 + size * 2 : state = "bottom"
   end

   digits.length.times { |j|
     draw_part_of_digit(digits[j], size, state);
     print ' '
   }
   print "\n"
}

#####################################################

--
   s&g

Ruby Quiz wrote:

This week's quiz is to write a program that displays LCD style numbers at
adjustable sizes.

Here we go. I decided to add support for "-" and ".". My implementation does not actually enforce the argument to be a valid number thus also allowing it to render IP numbers:

C:\dev\ruby\quizes\14>ruby lcd.rb -s 5 127.0.0.1 ----- ----- ----- ----- > > > > > > > >
      > > > > > > > >
         ----- ----- ----- ----- > > > > > > > > > > > > > >
      > > > > > > > > > > > > > >
         ----- ----- ----- ----- ----- -----

I decided to store the representation of digits as binary bit masks. I created a few helpers methods (line, horizontal, vertical, digit) so that I did not need to duplicate code.

I used .transpose in combination with .join for rendering the digits (which are represented as an Array of lines) next to each other instead of below each other.

lcd.rb (2.14 KB)

Here's a Ruby newbie attempt:

************************* lcd_quiz.rb *************************

zero = [[" ", "-", " "],
        ["|", " ", "|"],
        [" ", " ", " "],
        ["|", " ", "|"],
        [" ", "-", " "]]

one = [[" ", " ", " "],
       [" ", " ", "|"],
       [" ", " ", " "],
       [" ", " ", "|"],
       [" ", " ", " "]]

two = [[" ", "-", " "],
       [" ", " ", "|"],
       [" ", "-", " "],
       ["|", " ", " "],
       [" ", "-", " "]]

three = [[" ", "-", " "],
         [" ", " ", "|"],
         [" ", "-", " "],
         [" ", " ", "|"],
         [" ", "-", " "]]

four = [[" ", " ", " "],
        ["|", " ", "|"],
        [" ", "-", " "],
        [" ", " ", "|"],
        [" ", " ", " "]]

five = [[" ", "-", " "],
        ["|", " ", " "],
        [" ", "-", " "],
        [" ", " ", "|"],
        [" ", "-", " "]]

six = [[" ", "-", " "],
       ["|", " ", " "],
       [" ", "-", " "],
       ["|", " ", "|"],
       [" ", "-", " "]]

seven = [[" ", "-", " "],
         [" ", " ", "|"],
         [" ", " ", " "],
         [" ", " ", "|"],
         [" ", " ", " "]]

eight = [[" ", "-", " "],
         ["|", " ", "|"],
         [" ", "-", " "],
         ["|", " ", "|"],
         [" ", "-", " "]]

nine = [[" ", "-", " "],
        ["|", " ", "|"],
        [" ", "-", " "],
        [" ", " ", "|"],
        [" ", "-", " "]]

$numbers = [zero, one, two, three, four, five, six, seven, eight, nine]

def normalized_xy(x, y, size)
  norm_x = case x % (size + 3)
                when 0 then 0
                when size + 1 then 2
                else 1
               end
  norm_y = case y
                when 0 then 0
                when size * 2 + 2 then 4
                when size + 1 then 2
                when 1..(size+1) then 1
                else 3
               end
  [norm_x, norm_y]
end

def stretch(numstring, size = 2)
  nums = numstring.scan(/\d/).collect { |n| n.to_i }
  single_len = (size + 3) # add a space between numbers
  total_len = single_len * nums.length - 1
  height = size*2 + 3
  arr = Array.new(height) { |y|
    Array.new(total_len) { |x|
      norm_x, norm_y = normalized_xy(x, y, size)
      index = (x/(single_len)).floor
      num = nums[index]
      ((x+1) %(single_len) == 0) ? " " : $numbers[num][norm_y][norm_x]
    }
  }
  arr.collect! { |line| line.join }
  arr.join("\n")
end

if __FILE__ == $0
    require 'optparse'
    size = 2
    ARGV.options do |opts|
  opts.banner = "Usage: ruby #$0 [options] number_string"
  opts.on("-s", "--size SIZE", Integer, "the size to print the LCD numbers.", " defaults to 2") do |s|
      size = s.to_i
  end
  opts.on_tail("-h", "--help", "show this message") do
      puts opts
      exit
  end
  opts.parse!
  if ARGV[0] !~ /^\d+$/
      puts opts
      exit
  end
    end

    puts stretch(ARGV[0], size)
end

*********************** end lcd_quiz.rb ***********************

-Lee

···

-----Original Message-----
From: Ruby Quiz [mailto:james@grayproductions.net]
Sent: Friday, January 07, 2005 6:49 AM
To: ruby-talk ML
Subject: [QUIZ] LCD Numbers (#14)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.grayproductions.net/ruby_quiz/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

This week's quiz is to write a program that displays LCD style numbers at adjustable sizes.

The digits to be displayed will be passed as an argument to the program. Size should be controlled with the command-line option -s
follow up by a positive integer. The default value for -s is 2.

For example, if your program is called with:

  > lcd.rb 012345

The correct display is:

   -- -- -- --
  > > > > > > > >
  > > > > > > > >
             -- -- -- --
  > > > > > > >
  > > > > > > >
   -- -- -- --

And for:

  > lcd.rb -s 1 6789

Your program should print:

   - - - -
  > > > > > >
   - - -
  > > > > > >
   - - -

Note the single column of space between digits in both examples. For other values of -s, simply lengthen the - and | bars.

Here is my solution ( 398 bytes )
And my solution with hex digits ( 405 bytes)

Usage:
14-1.rb number* [-s size] number*
Right:
14-1.rb -s 9 456456
14-1.rb 456456 -s 9
14-1.rb 4 5 64 56 -s 9 45 6456
Wrong:
14-1.rb -s9 456456

### Dec
s=$*.index("-s");s=(s ?$*.slice!(s,2)[1].to_i: 2)
i=$*.join.split("").map{|x|x.to_i}
d,="7krtt1r30v/s".unpack("m")[0].unpack("B*")
f=" "
a,b=f*s,f+"-"*s+f
c,e,o="|",a+f+f,49
y=([0]*5).map{""}
i.each{|z|u=d[z*7,7]
y[0]<<(u[0]<o ?e: b)
y[1]<<(u[1]<o ?f: c)+a+(u[2]<o ?f: c)
y[2]<<(u[3]<o ?e: b)
y[3]<<(u[4]<o ?f: c)+a+(u[5]<o ?f: c)
y[4]<<(u[6]<o ?e: b)
y.map!{|v|v<<32}}
y[1,1]*=s
y[2+s,1]*=s
puts y

···

###

### Hex
s=$*.index("-s");s=(s ?$*.slice!(s,2)[1].to_i: 2)
i=$*.join.split("").map{|x|x.hex}
d,="7krtt1r30v/v8vyn9uw=".unpack("m")[0].unpack("B*")
f=" "
a,b=f*s,f+"-"*s+f
c,e,o="|",a+f+f,49
y=([0]*5).map{""}
i.each{|z|u=d[z*7,7]
y[0]<<(u[0]<o ?e: b)
y[1]<<(u[1]<o ?f: c)+a+(u[2]<o ?f: c)
y[2]<<(u[3]<o ?e: b)
y[3]<<(u[4]<o ?f: c)+a+(u[5]<o ?f: c)
y[4]<<(u[6]<o ?e: b)
y.map!{|v|v<<32}}
y[1,1]*=s
y[2+s,1]*=s
puts y
###

PS: it took me 7 minutes to write this mail because everytime I pasted
the source I found another way to do it in less bytes

Here is my solution. I tried to make it as compact as possible (also
see http://www.moldus.org/~laurent/Ruby/quiz/lcd.rb)

# Ruby Quiz #14 - LCD Display
# Laurent Julliard <laurent at moldus dot org>

···

#
digits = [[' - ','|.|',' . ','|.|',' - '],
           [' . ',' .|',' . ',' .|',' . '],
           [' - ',' .|',' - ','|. ',' - '],
           [' - ',' .|',' - ',' .|',' - '],
           [' . ','|. ',' - ',' .|',' . '],
           [' - ','|. ',' - ',' .|',' - '],
           [' - ','|. ',' - ','|.|',' - '],
           [' - ',' .|',' . ',' .|',' . '],
           [' - ','|.|',' - ','|.|',' - '],
           [' - ','|.|',' - ',' .|',' - ']]
if ARGV[0] == "-s"
   s = ARGV[1].to_i; stg = ARGV[2]
else
   s = 1 ; stg = ARGV[0]
end
aff = []
stg.each_byte do |c|
   aff << digits[c-48].collect { |l| l.sub(/\./,' '*s).sub(/-/,'-'*s) }
end
(aff = aff.transpose).each_index do |i|
   puts((aff[i].join(' ')+"\n")*(i%2 == 1 ? s : 1))
end

Here's my solution.

There's an LCD class that accepts an array of numbers (digits) and a size.
It has an out attribute that can be used to set where it should output to.
LCD converts the digits to LCDDigit objects. Each LCDDigit represents a digit
in an LCD display and knows which segments should be on for it.
To output the digits the LCD goes along all 7 segments asking each
digit if it's on at that segment.

I over engineered it a bit, the digits could be represented as arrays.
Using full blown classes for them on the other hand makes it easier to test,
extend and reuse them. Not that there's much to test but anyway... I wanted
to play a bit with Ruby's Unit::Test.

I had previously sent a mail with a zip file attached but it didn't make it
into the mailing list. I suspect it was filtered but I do apologize if the same
mail shows up more than once.

require 'optparse'
require 'singleton'

class LCD
   SPC = ' '
   VS = '|'
   HS = '-'

   attr_accessor :out

   def initialize(digits, size)
     @digits = digits.collect { |d| LCDDigit.digit(d) }
     @size = size
     @out = $stdout
   end

   def output
     output_horiz_segs(1)
     output_vert_segs(2, 3)
     output_horiz_segs(4)
     output_vert_segs(5, 6)
     output_horiz_segs(7)
   end

  private
   def output_horiz_segs(seg)
     @digits.each do |d|
       @out << SPC << hseg(d, seg) * @size << SPC
       @out << SPC unless (@digits.last).equal? d
     end
     @out << $/
   end

   def output_vert_segs(seg1, seg2)
     @size.times do
       @digits.each do |d|
         out << vseg(d, seg1) << SPC * @size << vseg(d, seg2)
         @out << SPC unless (@digits.last).equal? d
       end
       @out << $/
     end
   end

   def hseg(digit, seg)
     digit[seg] ? HS : SPC
   end

   def vseg(digit, seg)
     digit[seg] ? VS : SPC
   end
end

# An LCD digit has 7 segments, they're numbered like this:
# 1
# 2 3
# 4
# 5 6
# 7
class LCDDigit
   # To create LCDDigit::LCDDigit0 .. LCDDigit:LCDDigit9 classes. Only the
   # segments that are on for each LCDDigit are different.
   def LCDDigit.create_digit_class(digit, segments_on)
     LCDDigit.class_eval <<-EOT
       class LCDDigit#{digit} < LCDDigit
         include Singleton

         def [](seg)
           case seg
           when #{segments_on.join(",")} then true
           else false end
         end
       end
       EOT
   end

   create_digit_class(0, [1,2,3,5,6,7])
   create_digit_class(1, [3,6])
   create_digit_class(2, [1,3,4,5,7])
   create_digit_class(3, [1,3,4,6,7])
   create_digit_class(4, [2,3,4,6])
   create_digit_class(5, [1,2,4,6,7])
   create_digit_class(6, [1,2,4,5,6,7])
   create_digit_class(7, [1,3,6])
   create_digit_class(8, [1,2,3,4,5,6,7])
   create_digit_class(9, [1,2,3,4,6,7])

   @@digits = [
     LCDDigit::LCDDigit0.instance, LCDDigit::LCDDigit1.instance,
     LCDDigit::LCDDigit2.instance, LCDDigit::LCDDigit3.instance,
     LCDDigit::LCDDigit4.instance, LCDDigit::LCDDigit5.instance,
     LCDDigit::LCDDigit6.instance, LCDDigit::LCDDigit7.instance,
     LCDDigit::LCDDigit8.instance, LCDDigit::LCDDigit9.instance
   ]

   def LCDDigit.digit(digit)
     raise 'Invalid digit' if digit < 0 or digit > 9
     @@digits[digit]
   end
end

if __FILE__ == $0
   size = 2
   opts = OptionParser.new
   opts.banner = "Usage: #{__FILE__} [options] <digits>"
   opts.on("-s SIZE", "Size of the display", /^\d$/) do |s|
     size = s.to_i
   end
   opts.on_tail("-h", "--help", "Show this message") do
     puts opts
     exit
   end

   opts.parse!(ARGV)
   digits = ARGV.shift

   if ARGV.size > 0 or digits !~ /^\d+$/
     puts opts
     exit
   end

   digits = digits.split('').map { |m| m.to_i }

   lcd = LCD.new(digits, size)
   lcd.output
end

Apologies for a very late entry. I was on the road last week, but I didn't peek at anybody else's solutions. No golfing here, just straightforward raster output.

lcd.rb.txt (1.15 KB)

···

--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/>

This is a very late posting...and I see that James already posted the summary. I didn't have any time this past week/weekend to work on the quiz when I thought I would. So here it is....

Thanks,

Zach

-------Code ---------

#!/usr/bin/ruby

class LcdChar
   @@fragments = { 0 => ' ',
                   1 => ' - ',
                   2 => '| ',
                   3 => ' |',
                   4 => '| |', }

   def initialize( arr )
     @fragments = arr
   end

   def each_fragment
     return unless block_given?
     @fragments.each{ |e| yield @@fragments[e] }
   end

end

class LcdDigit
   class << self
     @@digits = {1 => LcdChar.new( [ 0, 3, 0, 3, 0 ] ),
                 2 => LcdChar.new( [ 1, 3, 1, 2, 1 ] ),
                 3 => LcdChar.new( [ 1, 3, 1, 3, 1 ] ),
                 4 => LcdChar.new( [ 0, 4, 1, 3, 0 ] ),
                 5 => LcdChar.new( [ 1, 2, 1, 3, 1 ] ),
                 6 => LcdChar.new( [ 0, 2, 1, 4, 1 ] ),
                 7 => LcdChar.new( [ 1, 3, 0, 3, 0 ] ),
                 8 => LcdChar.new( [ 1, 4, 1, 4, 1 ] ),
                 9 => LcdChar.new( [ 1, 4, 1, 3, 0 ] ),
                 0 => LcdChar.new( [ 1, 4, 0, 4, 1 ] ) }

     def get_digit( num )
       num = num.to_i if( num.class == ''.class )
       @@digits[ num ]
     end
   end
end

class LcdPrintWriter
   class << self
     def size_str( str, size )
       nstr = str.dup
       nstr[1,1] = nstr[1,1]*size
       nstr
     end

     def print( digits, size=1 )
       rows = []
       digits.to_s.split( '' ).each do |n|
         row = 0
         horiz = true
         LcdDigit.get_digit( n ).each_fragment do |e|
           rows[row] ||= ''
           rows[row] << LcdPrintWriter.size_str( e, size )
           if not horiz
             (1...size).each do
               row += 1
               rows[row] ||= ''
               rows[row] << LcdPrintWriter.size_str( e, size )
             end
           end
           horiz = !horiz
           row += 1
         end
       end
       puts rows
     end
   end
end

if( (sw=ARGV.shift) =~ /-s/ ) then
   size = ARGV.shift
   num = ARGV.shift
   LcdPrintWriter.print( num , size.to_i )
else
   puts "Unknown option #{sw}\nSyntax: \n\tlcd.rb -s size number_to_print"
end

Also just wanted to say that the formatting on the quiz page

Gray Soft / Not Found

is broken for the examples.

In Internet Explorer 6 but fine in Firefox 1.0

When -s == 1, yes.

James Edward Gray II

···

On Jan 7, 2005, at 8:57 AM, Robert McGovern wrote:

Question, I assume the idea is for a 7 seqment LCD?

Hi!

Maybe this is irrelevant, but
what if your script would be called such way:

lcd.rb -b accc 123

lcd.rb -s accc gfgdf 123

lcd.rb -s accc 123 gfgdf

lcd.rb - 2 123

?

:o)

···

--
   s&g

Luc Heinrich wrote:

Ruby Quiz <james@grayproductions.net> wrote:

This week's quiz is to write a program that displays LCD style numbers at
adjustable sizes.

Here's my solution:

**************************** [begin code ] ****************************

#!/usr/local/bin/ruby -w

require 'getoptlong'

# ---------------------------------------------------------------------

class Digit
        @@chars = [ " ", "-", "|" ]
    @@segments =
    [
        [ [0,1,0], [2,0,2], [0,0,0], [2,0,2], [0,1,0] ], # 0
        [ [0,0,0], [0,0,2], [0,0,0], [0,0,2], [0,0,0] ], # 1
        [ [0,1,0], [0,0,2], [0,1,0], [2,0,0], [0,1,0] ], # 2
        [ [0,1,0], [0,0,2], [0,1,0], [0,0,2], [0,1,0] ], # 3
        [ [0,0,0], [2,0,2], [0,1,0], [0,0,2], [0,0,0] ], # 4
        [ [0,1,0], [2,0,0], [0,1,0], [0,0,2], [0,1,0] ], # 5
        [ [0,1,0], [2,0,0], [0,1,0], [2,0,2], [0,1,0] ], # 6
        [ [0,1,0], [0,0,2], [0,0,0], [0,0,2], [0,0,0] ], # 7
        [ [0,1,0], [2,0,2], [0,1,0], [2,0,2], [0,1,0] ], # 8
        [ [0,1,0], [2,0,2], [0,1,0], [0,0,2], [0,1,0] ] # 9
    ]
        attr_reader :height
        def initialize( num, size )
        @matrix = @@segments[ num ]
        @height = @matrix.size
        self.scale_to_size( size ) if size > 1
    end
        def scale_to_size( size )
        t = size - 1
        @matrix.each { |l| t.times { l.insert(-2, 0) } }
        @matrix.each { |l| l.fill(1, l.index(1),size) if l.include?(1) }
        t.times { @matrix.insert( 1, @matrix[1]) }
        t.times { @matrix.insert(-2, @matrix[-2]) }
        @height = @matrix.size
    end
        def display_line( line )
        @matrix[ line ].each { |c| print @@chars[c] }
        print " "
    end
    end

# ---------------------------------------------------------------------

class LCD
        def initialize( num, size=1 )
        @digits = Array.new
        num.each_byte { |b| @digits << Digit.new( b.to_i - 48, size ) }
    end
        def display
        for line in 0...@digits.first.height
            @digits.each { |d| d.display_line( line ) }
            puts
        end
    end
    end

# ---------------------------------------------------------------------

def print_usage( message=nil )
    puts "Usage: lcd [-s size] digits"
end

# ---------------------------------------------------------------------

print_usage & exit if ARGV.empty?

size = 2
opts = GetoptLong.new( ["--size", "-s", GetoptLong::REQUIRED_ARGUMENT] )
opts.each { |opt, val| size = val.to_i if opt == "--size" }

print_usage & exit if ARGV.empty?

digits = ARGV[0].gsub( /[^0-9]/, "" )
lcd = LCD.new( digits, size )
lcd.display

# ---------------------------------------------------------------------

**************************** [end code ] ******************************

Woops, found a bug: displaying the same digit multiple times wasn't
working, so doing 'lcd.rb 55' for example would render garbage.

Here's my fixed (and slightly updated) solution:

**************************** [begin code ] ****************************

#!/usr/local/bin/ruby -w

require 'getoptlong'

# ----------------------------------------------------------------------

class Array
    
    def deep_clone
        Marshal::load(Marshal.dump(self))
    end
    
end

# ----------------------------------------------------------------------

class Digit
    
    S = " "
    H = "-"
    V = "|"

    @@segments =
    [
        [ [S,H,S], [V,S,V], [S,S,S], [V,S,V], [S,H,S] ], # 0
        [ [S,S,S], [S,S,V], [S,S,S], [S,S,V], [S,S,S] ], # 1
        [ [S,H,S], [S,S,V], [S,H,S], [V,S,S], [S,H,S] ], # 2
        [ [S,H,S], [S,S,V], [S,H,S], [S,S,V], [S,H,S] ], # 3
        [ [S,S,S], [V,S,V], [S,H,S], [S,S,V], [S,S,S] ], # 4
        [ [S,H,S], [V,S,S], [S,H,S], [S,S,V], [S,H,S] ], # 5
        [ [S,H,S], [V,S,S], [S,H,S], [V,S,V], [S,H,S] ], # 6
        [ [S,H,S], [S,S,V], [S,S,S], [S,S,V], [S,S,S] ], # 7
        [ [S,H,S], [V,S,V], [S,H,S], [V,S,V], [S,H,S] ], # 8
        [ [S,H,S], [V,S,V], [S,H,S], [S,S,V], [S,H,S] ] # 9
    ]
        
    attr_reader :height
    
    def initialize( num, size )
        @matrix = @@segments[ num ].deep_clone
        @height = @matrix.size
        self.scale_to_size( size ) if size > 1
    end
    
    def scale_to_size( size )
        t = size - 1
        @matrix.each { |l| t.times { l.insert(-2, S) } }
        @matrix.each { |l| l.fill(H, l.index(H), size) if l.include?(H)
}
        t.times { @matrix.insert( 1, @matrix[1]) }
        t.times { @matrix.insert(-2, @matrix[-2]) }
        @height = @matrix.size
    end
    
    def display_line( line )
        print @matrix[ line ], " "
    end
    
end

# ----------------------------------------------------------------------

class LCD
    
    def initialize( num, size=1 )
        @digits = Array.new
        num.each_byte { |b| @digits << Digit.new( b.to_i - 48, size ) }
    end
    
    def display
        for line in 0...@digits.first.height
            @digits.each { |d| d.display_line( line ) }
            puts
        end
    end
    
end

# ----------------------------------------------------------------------

def print_usage( message=nil )
    puts "Usage: lcd [-s size] digits"
end

# ----------------------------------------------------------------------

print_usage & exit if ARGV.empty?

size = 2
opts = GetoptLong.new( ["--size", "-s", GetoptLong::REQUIRED_ARGUMENT] )
opts.each { |opt, val| size = val.to_i if opt == "--size" }

print_usage & exit if ARGV.empty?

digits = ARGV[0].gsub( /[^0-9]/, "" )
lcd = LCD.new( digits, size )
lcd.display

# ----------------------------------------------------------------------

**************************** [end code ] ****************************

···

Luc Heinrich <lucsky@mac.com> wrote:

Here's my solution:

--
Luc Heinrich - lucsky@mac.com

Cool! :o)

It's only slightly hard to read, but
informational saturation/elegance
of each string impresses...

:wink:

···

--
   s&g

Jannis Harder wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here is my solution ( 398 bytes )
And my solution with hex digits ( 405 bytes)

Usage:
14-1.rb number* [-s size] number*
Right:
14-1.rb -s 9 456456
14-1.rb 456456 -s 9
14-1.rb 4 5 64 56 -s 9 45 6456
Wrong:
14-1.rb -s9 456456

### Dec
s=$*.index("-s");s=(s ?$*.slice!(s,2)[1].to_i: 2)
i=$*.join.split("").map{|x|x.to_i}
d,="7krtt1r30v/s".unpack("m")[0].unpack("B*")
f=" "
a,b=f*s,f+"-"*s+f
c,e,o="|",a+f+f,49
y=([0]*5).map{""}
i.each{|z|u=d[z*7,7]
y[0]<<(u[0]<o ?e: b)
y[1]<<(u[1]<o ?f: c)+a+(u[2]<o ?f: c)
y[2]<<(u[3]<o ?e: b)
y[3]<<(u[4]<o ?f: c)+a+(u[5]<o ?f: c)
y[4]<<(u[6]<o ?e: b)
y.map!{|v|v<<32}}
y[1,1]*=s
y[2+s,1]*=s
puts y
###

### Hex
s=$*.index("-s");s=(s ?$*.slice!(s,2)[1].to_i: 2)
i=$*.join.split("").map{|x|x.hex}
d,="7krtt1r30v/v8vyn9uw=".unpack("m")[0].unpack("B*")
f=" "
a,b=f*s,f+"-"*s+f
c,e,o="|",a+f+f,49
y=([0]*5).map{""}
i.each{|z|u=d[z*7,7]
y[0]<<(u[0]<o ?e: b)
y[1]<<(u[1]<o ?f: c)+a+(u[2]<o ?f: c)
y[2]<<(u[3]<o ?e: b)
y[3]<<(u[4]<o ?f: c)+a+(u[5]<o ?f: c)
y[4]<<(u[6]<o ?e: b)
y.map!{|v|v<<32}}
y[1,1]*=s
y[2+s,1]*=s
puts y
###

PS: it took me 7 minutes to write this mail because everytime I pasted
the source I found another way to do it in less bytes

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (Darwin)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFB4WPd5YRWfc27RzQRAmyXAJ9lEcHjbKdIGDLKZAorKDbp/W6u3QCgo2uC
zsgHcCAhm7jkLJpJultYnBI=
=Gk50
-----END PGP SIGNATURE-----

Here is my solution... Not sure that it is really Ruby-ish, as this is
my very first Ruby program and I'm not all that familiar with the
libraries and some of the language features. So I'm certain some of it
could be refactored, cleaned and tightened up. (Apologies for lack of
indentation... can't figure out how to convince google groups to
comply.)

#!/usr/bin/ruby

size = 2 # default

# get arguments and sanity/error checking on parameters
require 'getoptlong'

opts = GetoptLong.new( [ "--size", "-s", GetoptLong::OPTIONAL_ARGUMENT
] )
opts.each do |opt, arg|
if '--size' == opt
if arg.to_i.to_s != arg
puts 'Error: size param is not a number'
exit
end
size = arg.to_i
end
end

if 1 != ARGV.length
puts 'Usage: lcd.rb [-s <size>] <number>'
exit
end

value = ARGV[0].dup
if value.to_i.to_s != value
puts 'Error: argument is not a number'
exit
end

# bit patterns of which segments are off/on for each digit
bits = {
'0' => 0b01110111,
'1' => 0b00100100,
'2' => 0b01011101,
'3' => 0b01101101,
'4' => 0b00101110,
'5' => 0b01101011,
'6' => 0b01111011,
'7' => 0b00100101,
'8' => 0b01111111,
'9' => 0b01101111
}

# our lovely constant strings for off/on bars
HBar = [ ' ', '-' ].collect { |c| ' ' + c * size + ' ' }
LBar = [ ' ', '|' ]
RBar = [ ' ', '|' ].collect { |c| ' ' * size + c }

# turn each digit into its 7seg bit pattern
digits = value.split(//).collect { |o| bits[o] }

# for each segment, collect an array of 0 and 1 for all digits
seg = []
(0...7).each do |s|
seg[s] = digits.collect { |b| ((b >> s) & 0x01) }
end

# turn each horizontal segment into an array of horizontal bars
[0, 3, 6].each do |i|
seg[i].collect! { |x| HBar[x] }
end

# turn each vertical segment into an array of vertical bars
[ [1, 2], [4, 5] ].each do |t|
seg[ t[0] ].collect! { |x| LBar[x] } # left verticals
seg[ t[1] ].collect! { |x| RBar[x] } # right verticals (incl
center space)

# merge left and right bars into left, combining each string
pair
seg[ t[0] ] = seg[ t[0] ].zip(seg[ t[1] ]).collect { |s| s[0] +
s[1] }
end

# output!
puts seg[0].join(' ')
size.times do
puts seg[1].join(' ')
end
puts seg[3].join(' ')
size.times do
        puts seg[4].join(' ')
end
puts seg[6].join(' ')

I'm unhappy with the current Ruby Quiz Web site and intend to replace it as soon as I can find the time. Because of that, I'm not spending too much time fiddling with the CSS myself, but I'll accept a working patch if you're up to bug hunting.

I hope I don't sound uncaring. I'm not. I do want Ruby Quiz to have a great site, but the current version has some built-in weaknesses I want to get past, so I would rather spend my time replacing it.

I do thank you for the information.

James Edward Gray II

···

On Jan 7, 2005, at 9:02 AM, Robert McGovern wrote:

Also just wanted to say that the formatting on the quiz page

Gray Soft / Not Found

is broken for the examples.

In Internet Explorer 6 but fine in Firefox 1.0

Right, your comment is of course valid, but I assumed that the purpose
of the quiz was to find smart and/or elegant ways to achieve the core
problem, not to come up with a 100% foolproof script :stuck_out_tongue:

···

Sea&Gull <v@vsu.ru> wrote:

Maybe this is irrelevant, but
what if your script would be called such way:
...

--
Luc Heinrich - lucsky@mac.com