LCD 패널 방식으로 숫자를 표시해보기 (파이썬)

LCD 처럼 숫자를 표시하는 코드를 만들어 보자

크기와 출력할 숫자를 입력받는다. 크기는 LCD 표시 요소 하나의 크기를 가리킨다. (크기는 1~10,  숫자는 0~99,999,999)  가로선은 -, 세로선은 | 문자를 통해서 표현하며, 사이즈만큼 길이가 길어진다. 따라서 하나의 문자를 표시하기 위해서는 가로는 size + 2, 세로는 size * 2 + 3 만큼의 공간이 필요하다.

예시 – 출력: 0123456789. size: 3

 ---         ---   ---         ---   ---   ---   ---   --- 
|   |     |     |     | |   | |     |         | |   | |   |
|   |     |     |     | |   | |     |         | |   | |   |
|   |     |     |     | |   | |     |         | |   | |   |
             ---   ---   ---   ---   ---         ---   --- 
|   |     | |         |     |     | |   |     | |   |     |
|   |     | |         |     |     | |   |     | |   |     |
|   |     | |         |     |     | |   |     | |   |     |
 ---         ---   ---         ---   ---         ---   ---

접근

왼쪽과 같이 LCD 숫자 하나를 표현하기 위해서는 총 7개의 패널이 필요하다. 각 패널의 번호를 왼쪽과 같이 지정한다고 하자. 어떤 숫자를 표현하고자 한다면 각 패널이 어떤 숫자에서는 켜질 것인지, 켜지지 않을 것인지를 구분해야 한다. 예를 들어 위쪽 가로 방향 패널인 0의 경우에는 1을 그려야 하는 시점에는 켤 필요가 없다. 하지만 0이나 2, 3 등을 그려야 하는 시점에서는 켜져야 한다.

즉 0번 패널이 켜져야 하는 숫자는 아래 그림에서 알 수 있듯이, 0, 2, 3, 4, 6, 7, 8, 9 가 된다.  같은 방식으로 각 패널마다 어떤 숫자에 켜져야 할 것인지를 미리 정해두도록 하자.

이렇게 각 패널마다 켜져야 하는 숫자들을 정리하는 것은 생각보다 간단하다. 위 그림을 이용해서 쉽게 리스트를 완성할 수 있다.

masks = ("02356789", "045689", "01234789", "2345689", "02689", "013456789", "0235689")

이제 숫자를 출력할 차례이다. 우선 한개의 숫자를 출력하는 과정을 생각해보자. 숫자를 출력하는 과정은 가로선을 표현하는 구간 3군데와 세로선을 표현하는 구간 2군데로 나뉜다.

가로선 표현

패널 1개의 크기가 S인 숫자의 폭은 S + 2 (양쪽의 1씩 세로선이 표시되어야 하므로)이다. 따라서 가로선의 경우 표시하려는 숫자의 해당 가로 패널이 켜지는 경우에는 (공백) + (-) * S + (공백)을 출력하게 된다. 만약 패널이 꺼져 있는 경우에는 (-) 대신에 공백이 출력될 것이다. 따라서 맨 위에 가로선을 표시하는 것은 출력하려는 숫자 d 에 따라서 다음과 같은 문자열을 만들게 된다.

' ' + ('-' if d in masks[0] else ' ') * s + ' '
## "#---#" 또는 "#####" 

세로선 표현

세로선을 표현할 때는 한 줄에 1번 2번 혹은 4번 5번 패널을 같이 판단해야 한다. 표시되는 문자의 상황은 가로선과 반대로 양끝에 패널이 있고 가운데는 크기 값 만큼의 공백이 들어온다. 따라서 사이즈 3일 때의 둘째줄은 다음과 같이 만들어진다.

('|' if d in masks[1] else ' ') + ' ' * s + ('|' if d in masks[2] else ' ')

그리고 이렇게 만들어지는 세로선은 사이즈 값만큼 반복하여 라인을 만들어야 한다. 사이즈 3인 경우에는 2,3,4 번 줄이 같은 내용을 반복 출력한다.

이후 가운데 가로선과, 다시 아래쪽 세로선, 마지막으로 바닥자리 가로선을 같은 식으로 표시한다.

정리

한 번에 한 글자에 대해서 한줄씩 문자열을 만드는 방법을 알아보았으니, 이번에는 여러 글자를 출력할 때 한줄은 어떻게 만드는지에 대해서 알아보자. 이미 모든 글자는 같은 규격으로 생성되며, 매번 줄을 만드는 방법을 알았다. 따라서 여러 글자의 경우에는 각 글자에서 해당줄의 문자열을 생성하고 공백으로 구분하여 하나로 합치면 된다. 이는 str.join() 을 이용하면 된다. 출력해야하는 숫자 문자열을 digits 라고 하면, 해당 코드는 리스트 축약을 통해서 손쉽게 표현할 수 있다.

## 가로줄
' '.join(
    [(' ' + ('-' if d in mask[0] else ' ') * s + ' ') for d in digits]
}

## 세로줄
' '.join(
    [('|' if d in mask[1] else ' ') + ' ' * s + ('|' if d in mask[2] else ' ')\
     for d in digits]
)

이렇게 각 줄을 생성하여 리스트에 담고 개행문자를 끼워서 하나로 합치면 출력해야하는 최종 문자열이 완성된다. 이제 코드를 정리해보자.

def make_presentation(digits, s=1):
  masks = ("02356789", "045689", "01234789", 
           "2345689", "02689", "013456789", "0235689")
  result = []  
  ## 윗줄
  result.append(' '.join([' '+('-' if d in masks[0] else '-') * s + ' '\
                          for d in digits]))
  ## 위쪽 세로줄
  for _ in range(s):
    result.append(' '.join([ ('|' if d in masks[1] else ' ') + ' ' * s +\
                             ('|' if d in masks[2] else ' ') + ' '\
                            for d in digits]))
  
  ## 가운데 가로줄
  result.append(' '.join([' '+('-' if d in masks[3] else '-') * s + ' '\
                          for d in digits]))

  ## 위쪽 세로줄
  for _ in range(s):
    result.append(' '.join([ ('|' if d in masks[4] else ' ') + ' ' * s +\
                             ('|' if d in masks[5] else ' ') + ' '\
                            for d in digits]))

  ## 바닥줄
  result.append(' '.join([' '+('-' if d in masks[6] else '-') * s + ' '\
                          for d in digits]))

  return '\n'.join(result)

def main():
  digits, size = input().split()[:2]
  size = int(size)
  print(make_presentation(digits, size))

정리

중복되는 복잡한 코드가 너무 많아서 이를 별도의 람다식으로 빼내었다.