[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[SOLUTION] Ruby Quiz #14 LCD Numbers

email55555 email55555

1/9/2005 1:52:00 PM

Here is my solution:

#!/usr/bin/env ruby
# Program : Ruby Quiz #14 LCD Numbers
(http://www.grayproductions.net/ruby_quiz/q...)
# 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.doubl... ~~~


9 Answers

Antonio Cangiano

1/9/2005 2:20:00 PM

0

email55555 email55555 wrote:
> Here is my solution:
>
> #!/usr/bin/env ruby
> # Program : Ruby Quiz #14 LCD Numbers
> (http://www.grayproductions.net/ruby_quiz/q...)
> # Author : David Tran
> # Date : 2005-01-07 [cut]

David a few things that I have noticed while running the program.
It's missing a # in front of (http://...) but this is trivial of course :-).

If I launch the program without arguments I get:

../lcd.rb:61: Usage: ./lcd.rb [-s size] number (RuntimeError)

The (RuntimeError) shouldn't be there. Furthermore if you pass a string
like 123CIAO4 it will output 12300004. You can check more strictly for
the input given to the program and print something like "1234CIAO4 is
not a valid number" or as you wish.

HTH
Cheers,
Antonio
--
My programming blog: http://www.antonioca...

James Gray

1/9/2005 6:00:00 PM

0

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__



Jim Menard

1/9/2005 6:34:00 PM

0

Here's my solution: http://www.io....rubyqu...

Jim
--
Jim Menard, jimm@io.com, http://www.io....
"If at first you don't succeed, don't go skydiving." -- Unknown



Sean Ross

1/9/2005 10:58:00 PM

0

# 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


Sean Ross

1/9/2005 11:46:00 PM

0

"Sean Ross" <sross@connectmail.carleton.ca> wrote in message
news:8JiEd.3477$TN6.223560@news20.bellglobal.com...
[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}|"



Dave Burt

1/9/2005 11:51:00 PM

0

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

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


Florian Gross

1/10/2005 1:42:00 PM

0

Dave Burt wrote:

> You can see my solution at http://www.dave.burt.id.au/ruby/lcd...
>
> 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.

Dale Martenson

1/10/2005 3:17:00 PM

0

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][i] )
end
print line + "\n"

when "VERTICAL"
1.upto(@size) do |j|
line = ""
digits.each_byte do |b|
line += vertical_segment(
@@lcdDisplayData[b.chr][i] )
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 )



Dave Burt

1/10/2005 11:15:00 PM

0

"Florian Gross" <flgr@ccan.de> wrote:
> Dave Burt wrote:
>
>> You can see my solution at http://www.dave.burt.id.au/ruby/lcd...
>>
>> 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.

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