[SOLUTION] Ruby Quiz #14 LCD Numbers

  • Thread starter email55555 email55555
  • Start date
E

email55555 email55555

Here is my solution:

#!/usr/bin/env ruby
# Program : Ruby Quiz #14 LCD Numbers
(http://www.grayproductions.net/ruby_quiz/quiz14.html)
# Author : David Tran
# Date : 2005-01-07

class LCD
DEFAULT_SIZE = 2
LCD_CODES = [ # code for digits's each horizontal line (for size == 1)
[:h1, :v3, :h0, :v3, :h1], #0
[:h0, :v1, :h0, :v1, :h0], #1
[:h1, :v1, :h1, :v2, :h1], #2
[:h1, :v1, :h1, :v1, :h1], #3
[:h0, :v3, :h1, :v1, :h0], #4
[:h1, :v2, :h1, :v1, :h1], #5
[:h1, :v2, :h1, :v3, :h1], #6
[:h1, :v1, :h0, :v1, :h0], #7
[:h1, :v3, :h1, :v3, :h1], #8
[:h1, :v3, :h1, :v1, :h1], #9
]

def initialize(number, size)
@number = number.to_s.split(//).collect { |c| c.to_i }
@size = (size || DEFAULT_SIZE).to_i
@size = DEFAULT_SIZE if @size <= 0
@gap = ' ' # gap between each digit

line_codes = { # For size == 1
:h0 => ' ' + ' ' * @size + ' ', # h0 = " "
:h1 => ' ' + '-' * @size + ' ', # h1 = " - "
:v0 => ' ' + ' ' * @size + ' ', # v0 = " " (same as h0)
:v1 => ' ' + ' ' * @size + '|', # v1 = " |"
:v2 => '|' + ' ' * @size + ' ', # v2 = "| "
:v3 => '|' + ' ' * @size + '|', # v3 = "| |"
}

@lines = []
(0..4).each { |line| @lines << @number.inject('') { |s, d| s +=
line_codes[LCD_CODES[d][line]] + @gap } }
end

def each_line
return unless block_given?
last_line = (@size + 1) * 2
middle_line = last_line / 2
(0..last_line).each do |line|
index = case line
when 0: 0
when 1...middle_line: 1
when middle_line: 2
when last_line: 4
else 3
end
yield @lines[index]
end
end

end

key, size = ARGV.slice!(ARGV.index('-s'), 2) if ARGV.include?('-s')
raise "Usage: #$0 [-s size] number" if ARGV.empty?
LCD.new(ARGV.first, size).each_line { |line| puts line }


=========================
~~~ http://www.doublegifts.com ~~~
 
J

James Edward Gray II

My own solution. It looks a long but it's mostly the digits, arguments
and usage.

James Edward Gray II

#!/usr/bin/env ruby

DIGITS = [
[ " - ",
"| |",
" ",
"| |",
" - " ],
[ " ",
" |",
" ",
" |",
" " ],
[ " - ",
" |",
" - ",
"| ",
" - " ],
[ " - ",
" |",
" - ",
" |",
" - " ],
[ " ",
"| |",
" - ",
" |",
" " ],
[ " - ",
"| ",
" - ",
" |",
" - " ],
[ " - ",
"| ",
" - ",
"| |",
" - " ],
[ " - ",
" |",
" ",
" |",
" " ],
[ " - ",
"| |",
" - ",
"| |",
" - " ],
[ " - ",
"| |",
" - ",
" |",
" - " ]
]

def scale( num, size )
bigger = [ ]
num.each do |l|
row = l.dup
row[1, 1] = row[1, 1] * size
if row =~ /\|/
size.times { bigger << row }
else
bigger << row
end
end
bigger
end

s = 2
if ARGV.size >= 2 and ARGV[0] == '-s' and ARGV[1] =~ /^[1-9]\d*$/
ARGV.shift
s = ARGV.shift.to_i
end

unless ARGV.size == 1 and ARGV[0] =~ /^\d+$/
puts "Usage: #$0 [-s SIZE] DIGITS"
exit
end
n = ARGV.shift

num = [ ]
n.each_byte do |c|
num << [" "] * (s * 2 + 3) if num.size > 0
num << scale(DIGITS[c.chr.to_i], s)
end

num = ([""] * (s * 2 + 3)).zip(*num)
num.each { |l| puts l.join }

__END__
 
S

Sean Ross

# lcd.rb
require 'optparse'

opts = OptionParser.new
size = 2 # default
opts.on("-s","--size VAL", Integer){|val| size=val}
digit_entry = opts.parse(*ARGV).first

raise "size must be greater than zero (given #{size})" if size <= 0
raise "'#{digit_entry}' contains non-digit characters" if digit_entry =~ /\D/

# to hold LCD format information
LCD = Struct.new:)upper_crossbar, :upper_uprights,
:middle_crossbar,:lower_uprights,:lower_crossbar)

# lcd segment formats
nothing = " #{' '*size} "
crossbar = " #{'-'*size} "
leftpost = "|#{' '*size} "
rightpost = " #{' '*size}|"
uprights = "|#{' '*size}|"

# digits in LCD format
LCDs = {'0'=>LCD[crossbar,uprights,nothing,uprights,crossbar],
'1'=>LCD[nothing,rightpost,nothing,rightpost,nothing],
'2'=>LCD[crossbar,rightpost,crossbar,leftpost,crossbar],
'3'=>LCD[crossbar,rightpost,crossbar,rightpost,crossbar],
'4'=>LCD[nothing,uprights,crossbar,rightpost,nothing],
'5'=>LCD[crossbar,leftpost,crossbar,rightpost,crossbar],
'6'=>LCD[crossbar,leftpost,crossbar,uprights,crossbar],
'7'=>LCD[crossbar,rightpost,nothing,rightpost,nothing],
'8'=>LCD[crossbar,uprights,crossbar,uprights,crossbar],
'9'=>LCD[crossbar,uprights,crossbar,rightpost,crossbar]}

# simulate LCD panel display
digits = digit_entry.split(//).collect{|d| LCDs[d]}
LCD.members.each_with_index do |segment_name, index|
panel_segment = digits.collect{|lcd| lcd[segment_name]}.join(' ')
repeat = index%2==0 ? 1 : size # only repeat 'upright' segments
repeat.times{puts panel_segment}
end
 
S

Sean Ross

[snip]
# lcd segment formats
nothing = " #{' '*size} "
crossbar = " #{'-'*size} "
leftpost = "|#{' '*size} "
rightpost = " #{' '*size}|"
uprights = "|#{' '*size}|"
[snip]

Needs a little refactoring:

gap = ' '*size
nothing = " #{gap} "
crossbar = " #{'-'*size} "
leftpost = "|#{gap} "
rightpost = " #{gap}|"
uprights = "|#{gap}|"
 
D

Dave Burt

You can see my solution at http://www.dave.burt.id.au/ruby/lcd_digits.rb

I used two functions, one to turn something like '9' into a big ASCII-art
digital-looking 9, and one like UNIX's paste command to stick them next to
each other.

Then like this:

number = ARGV[0].scan(/\d/)
puts paste(number.map {|digit| lcd_digit(digit, size) })

Cheers,
Dave
 
F

Florian Gross

Dave said:
You can see my solution at http://www.dave.burt.id.au/ruby/lcd_digits.rb

I used two functions, one to turn something like '9' into a big ASCII-art
digital-looking 9, and one like UNIX's paste command to stick them next to
each other.

Your solution is very similar to mine. We both represented the number
faces via bit masks and decided to first render the individual digits
and then stick them next to each other.

I'm keeping the lines of a digit as an Array and sticking them together
with this code:

ary.transpose.map do |line|
line.join(" ")
end.join("\n")

Maybe that would also be an option for you.
 
D

Dale Martenson

require 'getoptlong'

class LCD
attr_accessor( :size, :spacing )

#
# This hash is used to define the segment display for the
# given digit. Each entry in the array is associated with
# the following states:
#
# HORIZONTAL
# VERTICAL
# HORIZONTAL
# VERTICAL
# HORIZONTAL
# DONE
#
# The HORIZONTAL state produces a single horizontal line. There
# are two types:
#
# 0 - skip, no line necessary, just space fill
# 1 - line required of given size
#
# The VERTICAL state produces a either a single right side line,
# a single left side line or a both lines.
#
# 0 - skip, no line necessary, just space fill
# 1 - single right side line
# 2 - single left side line
# 3 - both lines
#
# The DONE state terminates the state machine. This is not needed
# as part of the data array.
#
@@lcdDisplayData = {
"0" => [ 1, 3, 0, 3, 1 ],
"1" => [ 0, 1, 0, 1, 0 ],
"2" => [ 1, 1, 1, 2, 1 ],
"3" => [ 1, 1, 1, 1, 1 ],
"4" => [ 0, 3, 1, 1, 0 ],
"5" => [ 1, 2, 1, 1, 1 ],
"6" => [ 1, 2, 1, 3, 1 ],
"7" => [ 1, 1, 0, 1, 0 ],
"8" => [ 1, 3, 1, 3, 1 ],
"9" => [ 1, 3, 1, 1, 1 ]
}

@@lcdStates = [
"HORIZONTAL",
"VERTICAL",
"HORIZONTAL",
"VERTICAL",
"HORIZONTAL",
"DONE"
]

def initialize( size=1, spacing=1 )
@size = size
@spacing = spacing
end

def display( digits )
states = @@lcdStates.reverse
0.upto(@@lcdStates.length) do |i|
case states.pop
when "HORIZONTAL"
line = ""
digits.each_byte do |b|
line += horizontal_segment( @@lcdDisplayData[b.chr] )
end
print line + "\n"

when "VERTICAL"
1.upto(@size) do |j|
line = ""
digits.each_byte do |b|
line += vertical_segment(
@@lcdDisplayData[b.chr] )
end
print line + "\n"
end
when "DONE"
break
end
end
end

def horizontal_segment( type )
case type
when 1
return " " + ("-" * @size) + " " + (" " * @spacing)
else
return " " + (" " * @size) + " " + (" " * @spacing)
end
end

def vertical_segment( type )
case type
when 1
return " " + (" " * @size) + "|" + (" " * @spacing)
when 2
return "|" + (" " * @size) + " " + (" " * @spacing)
when 3
return "|" + (" " * @size) + "|" + (" " * @spacing)
else
return " " + (" " * @size) + " " + (" " * @spacing)
end
end
end

##### Main

opts = GetoptLong.new(
[ "--size", "-s", GetoptLong::REQUIRED_ARGUMENT ],
[ "--spacing", "--sp", "-p", GetoptLong::REQUIRED_ARGUMENT ]
)

lcd = LCD.new

opts.each do |opt, arg|
case opt
when "--size"
lcd.size = arg.to_i

when "--spacing"
lcd.spacing = arg.to_i
end
end

lcd.display( ARGV.shift )
 
D

Dave Burt

Florian Gross said:
Your solution is very similar to mine. We both represented the number
faces via bit masks and decided to first render the individual digits and
then stick them next to each other.

I'm keeping the lines of a digit as an Array and sticking them together
with this code:

ary.transpose.map do |line|
line.join(" ")
end.join("\n")

Maybe that would also be an option for you.

My newsreader missed your post :(
I was able to read it on ruby-talk.com via the Ruby Quiz site (which is
pretty cool for all its failings) :)

Sticking together like this?

def paste(array_of_strings, delim = ' ')
array_of_strings.map {|s| s.split(/\n/)}.transpose.map do |line|
line.join(delim)
end.join("\n")
end

Yes, that's neater than my paste(), and plugs right in. These strings all
have the same number of lines, so it doesn't matter that it fails if they
don't.

It's an interesting one. The process we used seemed to me to be the obvious
one, yet everyone's come up with a different way, stretching, golfing, etc.

I should also borrow your comments for my bitmask hash.

Cheers,
Dave
 

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,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top