[QUIZ] LCD Numbers (#14)

S

Sea&Gull

Cool! :eek:)

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

;-)
 
M

Matthew D Moss

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 = digits.collect { |b| ((b >> s) & 0x01) }
end

# turn each horizontal segment into an array of horizontal bars
[0, 3, 6].each do |i|
seg.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(' ')
 
L

Laurent Julliard

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.join(' ')+"\n")*(i%2 == 1 ? s : 1))
end
 
L

Luís Miguel Lourenço

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 :eek:ut

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
 
G

Glenn Parker

--------------030909030706050101080809
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

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.

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

--------------030909030706050101080809
Content-Type: text/plain;
name="lcd.rb.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="lcd.rb.txt"

#!/usr/bin/env ruby -w

require 'getoptlong'

$size = 2
GetoptLong.new(
["-s", GetoptLong::REQUIRED_ARGUMENT]
).each do |opt, val|
case opt
when '-s': $size = val.to_i
end
end
$digits = ARGV[0] || ''

# 0-
# 1| 2|
# 3-
# 4| 5|
# 6-

SEGMENTS = [
# 0 1 2 3 4 5 6
[ '-', '|', '|', ' ', '|', '|', '-' ], # 0
[ ' ', ' ', '|', ' ', ' ', '|', ' ' ], # 1
[ '-', ' ', '|', '-', '|', ' ', '-' ], # 2
[ '-', ' ', '|', '-', ' ', '|', '-' ], # 3
[ ' ', '|', '|', '-', ' ', '|', ' ' ], # 4
[ '-', '|', ' ', '-', ' ', '|', '-' ], # 5
[ '-', '|', ' ', '-', '|', '|', '-' ], # 6
[ '-', ' ', '|', ' ', ' ', '|', ' ' ], # 7
[ '-', '|', '|', '-', '|', '|', '-' ], # 8
[ '-', '|', '|', '-', ' ', '|', '-' ], # 9
]

def horz(w)
$digits.each_byte do |d|
mark = SEGMENTS[d - ?0][w * 3]
print ' ' + (mark * $size) + ' ' + (' ' * $size)
end
print "\n"
end

def vert(w)
$size.times do
$digits.each_byte do |d|
mark1 = SEGMENTS[d - ?0][(w * 3) + 1]
mark2 = SEGMENTS[d - ?0][(w * 3) + 2]
print mark1 + (' ' * $size) + mark2 + (' ' * $size)
end
print "\n"
end
end

horz(0)
vert(0)
horz(1)
vert(1)
horz(2)

--------------030909030706050101080809--
 
Z

Zach Dennis

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top