[SUMMARY] LCD Numbers (#14)

Discussion in 'Ruby' started by Ruby Quiz, Jan 13, 2005.

  1. Ruby Quiz

    Ruby Quiz Guest

    Clearly this problem isn't too difficult. As we've now seen, it can be solved
    in under 300 bytes. However, this classic challenge does address topics like
    scaling and joining multiline data that are applicable to many areas of computer
    programming. That always makes for an interesting quiz in my book.

    There were three main strategies used for solving the problem. Some used a
    template approach, where you have some kind of text representation of your
    number at a scale of one. Two might look like this, for example:

    [ " - ",
    " |",
    " - ",
    "| ",
    " - " ]

    Scaling that to any size is a two-fold process. First, you need to stretch it
    horizontally. The easy way to do that is to grab the second character of each
    string (a "-" or a " ") and repeat it -s times:

    digit.each { |row| row[1, 1] = row[1, 1] * scale }

    After that, the digit needs to be scaled vertically. That's pretty easy to do
    while printing it out, if you want. Just print any line containing a "|" -s
    times:

    digit.each do |row|
    if row =~ /\|/
    scale.times { puts row }
    else
    puts row
    end
    end

    The second strategy used was to treat each digit as a series of segments that
    can be "on" or "off". The numbers easily break down into seven positions:

    6
    5 4
    3
    2 1
    0

    Using that map, we can convert the two above to a binary digit, and some did:

    0b1011101

    Expansion of these representations is handled much as it was in the first
    strategy above.

    With either method, you will need to join the scaled digits together for output.
    This is basically a two dimensional join() problem. Building a routine like
    that is simple using either Array.zip() or Array.transpose(). (See the
    submissions for numerous examples of this.)

    The third strategy caught my eye, so I'll examine it here. Let's look at the
    primary class of Dale Martenson's solution:

    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

    The comment above gives you a nice clue to what is going on here. The class
    represents a state machine. For the needed size (set in initialize()), that
    class walks a series of states (defined in @@lcdStates). At each state,
    horizontal and vertical segments are built as needed (with horizontal_segment()
    and vertical_segment()).

    The process I've just described is run through display(), the primary interface
    method. You pass it a string of digits, it walks each state, and generates
    segments as needed.

    One nice aspect of this approach is that it's easy to handle output one line at
    a time and display() does this. The top line of all digits, generated by the
    first "HORIZONTAL" state, is printed as soon as it's built, as is each state
    that follows. This resource friendly system could scale well to much larger
    inputs.

    The rest of Dale's code (not shown), is just option parsing and the single call
    to display().

    My usual thanks to all who played with the quiz. More thanks to the "golfers"
    who taught me some interesting tricks about their sport and one more thank you
    to why the lucky stiff who notes our playing around in his blog, RedHanded.

    Tomorrow, you'll think up the quiz and your computer will solve it for you...
     
    Ruby Quiz, Jan 13, 2005
    #1
    1. Advertising

  2. Ruby Quiz

    Kero Guest

    > There were three main strategies used for solving the problem. Some used a
    > template approach, where you have some kind of text representation of your
    > number at a scale of one. Two might look like this, for example:
    >
    > [ " - ",
    > " |",
    > " - ",
    > "| ",
    > " - " ]

    [snip]
    > The second strategy used was to treat each digit as a series of segments that
    > can be "on" or "off". The numbers easily break down into seven positions:
    >
    > 6
    > 5 4
    > 3
    > 2 1
    > 0
    >
    > Using that map, we can convert the two above to a binary digit, and some did:
    >
    > 0b1011101

    [snip]

    So why not use:

    LCD = [
    "-|| ||-", # 0
    " | | ",
    "- |-| -",
    "- |- |-",
    " ||- | ",
    "-| - |-", # 5
    "-| -||-",
    "-|| | ",
    "-||-||-",
    "-||- |-",
    ]

    catching the bits and the shapes at the same time.

    [snip]
    > The third strategy caught my eye, so I'll examine it here. Let's look
    > at the primary class of Dale Martenson's solution:
    >
    > 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


    My main program looked like

    hor(0)
    ver(1, 2)
    hor(3)
    ver(4, 5)
    hor(6)

    replacing the statemachine.

    Ah well. This was actually the first Ruby Quiz I made.
    Partially because it looked like it was really short to work out.
    Thanks!

    (perhaps next time I'll even submit it :)

    +--- Kero ----------------------- ---+
    | all the meaningless and empty words I spoke |
    | Promises -- The Cranberries |
    +--- M38c --- http://httpd.chello.nl/k.vangelder ---+
     
    Kero, Jan 15, 2005
    #2
    1. Advertising

  3. On Jan 15, 2005, at 4:41 AM, Kero wrote:

    >> The second strategy used was to treat each digit as a series of
    >> segments that
    >> can be "on" or "off". The numbers easily break down into seven
    >> positions:
    >>
    >> 6
    >> 5 4
    >> 3
    >> 2 1
    >> 0
    >>
    >> Using that map, we can convert the two above to a binary digit, and
    >> some did:
    >>
    >> 0b1011101

    > [snip]
    >
    > So why not use:
    >
    > LCD = [
    > "-|| ||-", # 0
    > " | | ",
    > "- |-| -",
    > "- |- |-",
    > " ||- | ",
    > "-| - |-", # 5
    > "-| -||-",
    > "-|| | ",
    > "-||-||-",
    > "-||- |-",
    > ]
    >
    > catching the bits and the shapes at the same time.


    Well, it's trivial to infer the "-" or "|" from the position of the
    bit, but to directly answer your question, some did:

    http://www.io.com/~jimm/rubyquiz/quiz14/

    http://ruby-talk.com/blade/126180

    >> The third strategy caught my eye, so I'll examine it here. Let's look
    >> at the primary class of Dale Martenson's solution:
    >>
    >> 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

    >
    > My main program looked like
    >
    > hor(0)
    > ver(1, 2)
    > hor(3)
    > ver(4, 5)
    > hor(6)
    >
    > replacing the statemachine.
    >
    > Ah well. This was actually the first Ruby Quiz I made.
    > Partially because it looked like it was really short to work out.
    > Thanks!


    Thank you for following along.

    > (perhaps next time I'll even submit it :)


    I hope you will. We can't learn great tricks from it if you don't
    share.

    James Edward Gray II
     
    James Edward Gray II, Jan 16, 2005
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ruby Quiz

    [QUIZ] LCD Numbers (#14)

    Ruby Quiz, Jan 7, 2005, in forum: Ruby
    Replies:
    26
    Views:
    259
    Zach Dennis
    Jan 14, 2005
  2. email55555 email55555

    [SOLUTION] Ruby Quiz #14 LCD Numbers

    email55555 email55555, Jan 9, 2005, in forum: Ruby
    Replies:
    8
    Views:
    195
    Dave Burt
    Jan 10, 2005
  3. email55555 email55555

    [SOLUTION] Ruby Quiz #14 LCD Numbers ( solution #2 )

    email55555 email55555, Jan 9, 2005, in forum: Ruby
    Replies:
    16
    Views:
    286
    David Tran
    Jan 10, 2005
  4. Nathaniel Talbott

    [SOLUTION] Ruby Quiz #14 LCD Numbers

    Nathaniel Talbott, Jan 9, 2005, in forum: Ruby
    Replies:
    0
    Views:
    92
    Nathaniel Talbott
    Jan 9, 2005
  5. Vance A Heron

    [SOLUTION] LCD Numbers (#14)

    Vance A Heron, Jan 10, 2005, in forum: Ruby
    Replies:
    0
    Views:
    108
    Vance A Heron
    Jan 10, 2005
Loading...

Share This Page