7-segment ASCII graphics

Richard Suchenwirth 2004-04-23: Yet another tiny fun project, here's how to convert a string of digits and some other characters to a multiline string that in a fixed-pitch font looks like a 7-segment LCD/LED display:

proc num->7seg string {
    foreach i {a b c} {set $i " "}
    array set 7segment {
    0 {{ _ } {| |} {|_|}}
    1 {{   } {  |} {  |}}
    2 {{ _ } { _|} {|_ }}
    3 {{ _ } { _|} { _|}}
    4 {{   } {|_|} {  |}}
    5 {{ _ } {|_ } { _|}}
    6 {{ _ } {|_ } {|_|}}
    7 {{ _ } {  |} {  |}}
    8 {{ _ } {|_|} {|_|}}
    9 {{ _ } {|_|} { _|}}
    - {{   } { _ } {   }}
    E {{ _ } {|_ } {|_ }}
    r {{   } { _ } {|  }}
    o {{   } { _ } {|_|}}
    A {{ _ } {|_|} {| |}}
    B {{   } {|_ } {|_|}}    
    C {{ _ } {|  } {|_ }}
    D {{   } { _|} {|_|}}
    F {{ _ } {|_ } {|  }}
    }
    foreach char [split $string ""] {
        if {$char eq "."} {
            set c [string replace $c end end .]
        } else {
            foreach i {a b c} row $7segment($char) {
                append $i $row " "
            }
        }
    }
    return $a\n$b\n$c
}
% num->7seg 12345.67890-Error
   _   _       _   _   _   _   _   _       _                  
|  _|  _| |_| |_  |_    | |_| |_| | |  _  |_   _   _   _   _  
| |_   _|   |  _|.|_|   | |_|  _| |_|     |_  |   |   |_| |   

MPJ: "Drive-by hacking" ... I added A,B,C,D,F so hex displays look right ;-)

RS: Thanks Mike, but that B is indistinguishable from 8, and D from 0... We'd have to use lowercase for these two:

B {{   } {|_ } {|_|}}
D {{   } { _|} {|_|}}
% num->7seg 012345.6789ABCDEF
 _       _   _       _   _   _   _   _   _       _       _   _  
| |   |  _|  _| |_| |_  |_    | |_| |_| |_| |_  |    _| |_  |_  
|_|   | |_   _|   |  _|.|_|   | |_|  _| | | |_| |_  |_| |_  |   

MPJ: You're right; I just saw that on LCD hexa panel.

TV: Such things can also be applied to hardware LED display driven by the parallel port under tcl control, my routine wasn't as neatly defining the segments, just a list of decimal numbers...


FW: I thought of a (seemingly) clever way to store these characters, to make a little obfuscated puzzler, but the result is really not that much shorter, and not even as obfuscated as I had hoped. Ah well ;) It just replaces the "array set" construct with this:

foreach {char pc} [split "0o1\t2^3\[495s6w7I8\1779{_\20Evr\24o\27A}B7CfD Ft" ""] {
    binary scan $pc B8 bin
    set b2 ""
    for {set i 1} {$i < 8} {incr i} {
        append b2 [expr {[string index $bin $i] ? ([lsearch {1 3 6} $i] != -1 ? "_" : "|") : " "}]
    }
    set 7segment($char) [list " [string index $b2 0] " [string range $b2 1 3] [string range $b2 4 6]]
}