问题
I need to write a program to make a seven segment display. It will work like this:
def numbers(number, width):
# Code to make number
A typical output could look something like this:
numbers(100, 2)
-- --
| | | | |
| | | | |
| | | | |
| | | | |
-- --
numbers(24, 1)
-
| | |
- -
| |
-
numbers(1234567890, 1)
- - - - - - - -
| | | | | | | | | | | | | |
- - - - - - -
| | | | | | | | | | | | |
- - - - - - -
numbers(8453, 3)
--- --- ---
| | | | | |
| | | | | |
| | | | | |
--- --- --- ---
| | | | |
| | | | |
| | | | |
--- --- ---
Anyway, those are a few examples (which took quite a while to type, mind you). I know I can use things such as '-' * number
and such, but it is just frustrating as I cannot figure it out! I feel like I should be using classes or something, but I can't quite put my finger on it.
Thank you.
回答1:
Don't try to produce segments programmatically. Enter them manually, but in a generally encoded way. This encoding should allow you to produce different outputs. Do program these.
Please consider the following code
class SSDigit(object):
"""A 7-segment digit"""
def __init__(self):
self.lines= []
ssdig0= SSDigit()
ssdig1.lines.append(" ")
ssdig0.lines.append(" - ")
ssdig0.lines.append(" | | ")
ssdig0.lines.append(" ")
ssdig0.lines.append(" | | ")
ssdig0.lines.append(" - ")
ssdig1.lines.append(" ")
ssdig1= SSDigit()
ssdig1.lines.append(" ")
ssdig1.lines.append(" ")
ssdig1.lines.append(" | ")
ssdig1.lines.append(" ")
ssdig1.lines.append(" | ")
ssdig1.lines.append(" ")
ssdig1.lines.append(" ")
.....
class LineType(object):
"""Each of the 2 line types (1 horizontal segment or 2 vertical),
with their possible representations and segment positions"""
def __init__(self):
self.valueForRepr= {}
self.segmentPos= []
class Line(object):
"""Each of the 5 lines a SSDigit has, with its LineType"""
def __init__(self):
self.type= None
digits= [ ssdig0, ssdig1, ssdig2, ssdig3, ssdig4, ssdig5, ssdig6, ssdig7, ssdig8, ssdig9 ]
linetype1= LineType()
linetype1.valueForRepr[" "]= [0]
linetype1.valueForRepr[" - "]= [1]
linetype1.segmentPos= [3]
linetype2= LineType()
linetype2.valueForRepr[" "]= [0,0]
linetype2.valueForRepr[" | "]= [0,1]
linetype2.valueForRepr[" | "]= [1,0]
linetype2.valueForRepr[" | | "]= [1,1]
linetype2.segmentPos= [2,4]
typeforline= [ linetype1, linetype2, linetype1, linetype2, linetype1 ]
# Validate error-prone typing !!!
for digit in digits :
for linenum, linetype in enumerate(typeforline) :
if digit.lines[linenum] not in linetype.valueForRepr :
print("Error in digit {:d}, line {:d}".format(digit,linenum))
def printNumber(num):
num= str(num)
for linenum, linetype in enumerate(typeforline) :
line= ""
for d in num :
line+= digits[int(d)].lines[linenum]
print( line )
printNumber(3475649560458)
The strings entered for each SSDigit
are just canonical representations. Its structure is only for easy developer visualization. The information required to produce different sizes and forms is encoded through these representations and the other structures.
For example,
def printNumberDoubleSize(num):
num= str(num)
for linenum, linetype in enumerate(typeforline) :
line= ""
for d in num :
line+= digits[int(d)].lines[linenum]
print( line )
printNumberDoubleSize(3475649560458)
Next step is to realize that, allowing for spacing, the display consists of a 7x5 matrix:
01234
0
1 -
2 | |
3 -
4 | |
5 -
6
And that each line and column in the matrix are logical ones, i.e. can consist of several physical lines and/or columns, like in:
012 34
00012300
00
10 ----
20 | |
1 | |
30 ----
40 | |
1 | |
50 ----
60
Here, most logical rows and columns consist of only one physical row and column, respectively, except logical rows 2 and 4 (with 2 physical lines each), and logical column 2, with 4 physical columns.
This can be represented as a series of strings. And it can result very convenient to express for each element how we would like to see it in an off and on state. In the following definitions I indulged in some artistic liberty just for the sake of the example:
phyLineN= []
phyLineN.append([])
phyLineN[0]= []
phyLineN[0].append([ "....", ".", "....",".", "...." ])
phyLineN.append([])
phyLineN[1]= []
phyLineN[1].append([ ". ", " ", ". . "," ", " " ])
phyLineN.append([])
phyLineN[2]= []
phyLineN[2].append([ ". ", ".", " ",".", " " ])
phyLineN[2].append([ ". ", " ", " "," ", " " ])
phyLineN.append([])
phyLineN[3]= []
phyLineN[3].append([ ". ", " ", ". . "," ", " " ])
phyLineN.append([])
phyLineN[4]= []
phyLineN[4].append([ ". ", ".", " ",".", " " ])
phyLineN[4].append([ ". ", " ", " "," ", " " ])
phyLineN.append([])
phyLineN[5]= []
phyLineN[5].append([ ". ", " ", ". . "," ", " " ])
phyLineN.append([])
phyLineN[6]= []
phyLineN[6].append([ "....", ".", "....",".", "...." ])
phyLineY= []
phyLineY.append([])
phyLineY[0]= []
phyLineY[0].append([ " ", " ", " "," ", " " ])
phyLineY.append([])
phyLineY[1]= []
phyLineY[1].append([ " ", " ", "===="," ", " " ])
phyLineY.append([])
phyLineY[2]= []
phyLineY[2].append([ " ", "H", " ","H", " " ])
phyLineY[2].append([ " ", "H", " ","H", " " ])
phyLineY.append([])
phyLineY[3]= []
phyLineY[3].append([ " ", " ", "===="," ", " " ])
phyLineY.append([])
phyLineY[4]= []
phyLineY[4].append([ " ", "H", " ","H", " " ])
phyLineY[4].append([ " ", "H", " ","H", " " ])
phyLineY.append([])
phyLineY[5]= []
phyLineY[5].append([ " ", " ", "===="," ", " " ])
phyLineY.append([])
phyLineY[6]= []
phyLineY[6].append([ " ", " ", " "," ", " " ])
def printNumberNY(num,structN,structY):
phyRowH= [ len(structN[0]), len(structN[1]), len(structN[2]), len(structN[3]), len(structN[4]), len(structN[5]), len(structN[6]) ]
# Validate structure and compute phyColW
# This could be moved to an object constructor so is computed only once
first= 1
for line in structN :
for phyLine in line :
if first :
phyColW= [ len(phyLine[0]), len(phyLine[1]), len(phyLine[2]), len(phyLine[3]), len(phyLine[4]) ]
first= 0
else:
for i, _ in enumerate(phyLine) :
if len(phyLine[i]) != phyColW[i] : raise "Inconsistent physical column width"
# Real rendering of the (full) number in 7-segment form
num= str(num)
for linenum, linetype in enumerate(typeforline) :
for phyLine in range(phyRowH[linenum]) :
line= ""
for d in num :
for col, qq in enumerate(phyColW) :
if digits[int(d)].lines[linenum][col] != " " :
line+= structY[linenum][phyLine][col]
else:
line+= structN[linenum][phyLine][col]
print( line )
printNumberNY(3475649560458,phyLineN,phyLineY)
The code for printNumberNY
is not much more difficult than the one for the simple case of width*n.
The case of width*n is, in fact, a particular case of this setup, and can be constructed with:
def sizeVH(vSegHeight,hSegWidth,vSep,hSep):
hSepStr= " " *hSep
hSegN= " "* hSegWidth
hSegY= "-"* hSegWidth
phyLineN= []
phyLineN.append([])
phyLineN[0]= []
phyLineN.append([])
phyLineN[1]= []
phyLineN[1].append([ "", " ", hSegN," ", hSepStr ])
phyLineN.append([])
phyLineN[2]= []
for i in range(vSegHeight) :
phyLineN[2].append([ "", " ", hSegN," ", hSepStr ])
phyLineN.append([])
phyLineN[3]= []
phyLineN[3].append([ "", " ", hSegN," ", hSepStr ])
phyLineN.append([])
phyLineN[4]= []
for i in range(vSegHeight) :
phyLineN[4].append([ "", " ", hSegN," ", hSepStr ])
phyLineN.append([])
phyLineN[5]= []
phyLineN[5].append([ "", " ", hSegN," ", hSepStr ])
phyLineN.append([])
phyLineN[6]= []
for i in range(vSep) :
phyLineN[6].append([ "", " ", hSegN," ", hSepStr ])
phyLineY= []
phyLineY.append([])
phyLineY[0]= []
phyLineY.append([])
phyLineY[1]= []
phyLineY[1].append([ "", " ", hSegY," ", hSepStr ])
phyLineY.append([])
phyLineY[2]= []
for i in range(vSegHeight) :
phyLineY[2].append([ "", "|", hSegN,"|", hSepStr ])
phyLineY.append([])
phyLineY[3]= []
phyLineY[3].append([ "", " ", hSegY," ", hSepStr ])
phyLineY.append([])
phyLineY[4]= []
for i in range(vSegHeight) :
phyLineY[4].append([ "", "|", hSegN,"|", hSepStr ])
phyLineY.append([])
phyLineY[5]= []
phyLineY[5].append([ "", " ", hSegY," ", hSepStr ])
phyLineY.append([])
phyLineY[6]= []
for i in range(vSep) :
phyLineY[6].append([ "", " ", hSegN," ", hSepStr ])
return (phyLineN,phyLineY)
phyLineN, phyLineY= sizeVH(4,6,1,3)
printNumberNY(3475649560458,phyLineN,phyLineY)
I know that I didn't use some of the elements I defined at the beginning, but this is how I would have modeled it. They could be useful if we continue extending the solution.
回答2:
Haha, what a fun problem!
DISP = 7
# 1
#2 3
# 4
#5 6
# 7
def digit(cur, size = 5, ch = '*'):
def draw(led_code):
for a, b, c in led_code:
if a:
print ' ' + ch * size + ' '
if b and c:
print (ch + ' ' * size + ch + '\n') * size
continue
if b:
print (ch + ' ' * size + ' ' + '\n') * size
if c:
print (' ' + ' ' * size + ch + '\n') * size
digits = {
1 : [(0,0,1),(0,0,1),(0,0,0)],
0 : [(1,1,1),(0,1,1),(1,0,0)]
}
draw(digits.get(cur, digits[1]))
print
for x in bin(42).split('b')[1]:
digit(int(x))
回答3:
I will take this as a fun exercise (and maybe my solution gives you some ideas):
from collections import defaultdict
class Cell:
def __init__ (self, width = 4, height = 2, hChar = '*', vChar = '*'):
self.width = width
self.height = height
self.hChar = hChar
self.vChar = vChar
def showSegments (self, segments):
def char (segment):
if segment not in segments: return ' '
return self.hChar if segment in (0, 3, 6) else self.vChar
lines = []
lines.append (' ' + char (0) * self.width + ' ')
for _ in range (self.height):
lines.append (char (1) + ' ' * self.width + char (2) )
lines.append (' ' + char (3) * self.width + ' ')
for _ in range (self.height):
lines.append (char (4) + ' ' * self.width + char (5) )
lines.append (' ' + char (6) * self.width + ' ')
return lines
class Display:
def __init__ (self, encoding, cells, padding = 1, width = 4, height = 2, hChar = '*', vChar = '*'):
self.encoding = encoding
self.padding = padding
self.cells = [Cell (width, height, hChar, vChar) for _ in range (cells) ]
def show (self, string):
cellLines = []
for idx, c in enumerate (string):
if idx >= len (self.cells): break
cellLines.append (self.cells [idx].showSegments (self.encoding [c] ) )
if not cellLines: return
cellLines = zip (*cellLines)
print ('\n'.join ( (' ' * self.padding).join (line) for line in cellLines) )
encoding = defaultdict (lambda: {} )
encoding ['0'] = {0, 1, 2, 4, 5, 6}
encoding ['1'] = {2, 5}
encoding ['2'] = {0, 2, 3, 4, 6}
encoding ['3'] = {0, 2, 3, 5, 6}
d = Display (encoding, 5, 2)
d.show ('12301')
回答4:
I think the solution here is to just start small and work your way forward until the whole program is finished.
First write a function that can draw a single digit, say, drawTwo()
, which draws the digit two. Once you have this figured out, refactor this into drawTwo(width)
, which draws the digit with the right width. Now that you have this figured out, it shouldn't be too hard to write one for each digit zero through ten.
Once you have your ten functions, write a function that splits your input number into its digits and calls the correct function (possibly using a switch statement) for each digit.
Just take it one step at a time.
来源:https://stackoverflow.com/questions/18424973/calculator-7-segment-display-w-width