포토샵 같은 그래픽 편집기를 이용하면, 이미지를 수정할 수 있습니다.
이미지 캔버스는 M x N 크기의 배열로 표현되며, 각 픽셀마다 색이 주어집니다.
간단한 대화형 그래픽 편집기를 흉내 내는 프로그램을 만들어 봅시다.
입력
입력은 한 줄에 하나씩의 그래픽 편집기 명령으로 구성됩니다.
각 명령은 줄 맨 앞에 있는 대문자 한개로 표현된다. 매개 변수가 필요한 경우에는 그 명령과 같은 줄에 스페이스로 분리되어 매개변수가 입력됩니다.
픽셀 좌표는 1 이상 M 이하의 열 번호와 1 이상 N 이하의 행 번호, 이렇게 두 개의 정수로 표현됩니다.
이 때 1 ≤ M, N ≤ 250 의 범위를 가집니다. 좌표 (0, 0)은 2차원 배열의 왼쪽 위입니다. 사용하는 문자는 모두 대문자를 사용합니다.
명령의 형식은 다음과 같습니다.
명령 | 설명 |
I M N | 모든 픽셀이 흰색(O)으로 칠해진 M x N 이미지를 새로 만든다. |
C | 모든 픽셀을 흰색(O)으로 칠해서 표를 지운다. 이미지의 크기는 바뀌지 않는다. |
L X Y C | (X, Y) 픽셀을 주어진 색(C) 로 칠한다. |
V X Y1 Y2 C | X 열에 Y1 행과 Y2 행(Y1, Y2 포함) 사이에 주어진 색(C)으로 수직 방향 직선을 긋는다. |
H X1 X2 Y C | Y 행에 X1 열과 X2 열(X1, X2 포함) 사이에 주어진 색(C)으로 수평 방향 직선을 긋는다. |
K X1 Y1 X2 Y2 C | 주어진 색(C)으로 채워진 직사각형을 그린다. (X1, Y1)은 왼쪽 위 끝점, (X2, Y2)는 오른쪽 아래 끝 점을 의미한다. |
F X Y C | R 영역을 주어진 색(C)으로 채우는데, 영역 R은 다음과 같이 정의한다. (X, Y) 픽셀은 R에 속한다. (X, Y) 픽셀과 색이 같고 R에 포함된 픽셀과 맞닿은 부분이 하나라도 있다면 그 픽셀도 R 영역에 포함된다. |
S Name | 파일명을 MSDOS 8.3 형식으로 출력하고, 그 뒤에 현재 이미지의 내용을 출력한다. |
X | 세션을 종료한다. |
출력
S NAME 이라는 명령이 있을 때마다 NAME으로 주어진 파일명을 출력하고 현재 이미지의 내용을 출력한다. 각 행은 각 픽셀의 색을 나타내는 문자로 표시됩니다. 출력 예를 참고해주세요.
I, C, L, V, H, K, F, S, X를 제외한 문자로 정의된 명령이 있으면 그 줄 전체를 무시하고 다음 명령으로 넘어간다. 다른 오류에 대해서는 프로그램의 행동을 예측할 수 없습니다.
예제
※ 중간에 "G 2 3 J" 는 없는 명령어입니다. 출력 부분에 정의되지 않는 명령어는 무시하라고 되어 있습니다.
해설
2차원 배열을 다루는 문제입니다.
이 중 제법 난이도가 있는 것은 'F' 채우기 명령입니다. 그 외에는 평이한 수준입니다.
다만 입력의 자유도가 있다보니, 틀린 입력을 처리하는 예외 처리문 때문에 코드가 좀 지저분해집니다.
# GEditor.py , 0005 quiz
# written by badsaram
import sys
class GEditor(object):
def __init__(self):
self.canvas = []
self.width = 0
self.height = 0
def inputCommand(self):
str = input()
arr = str.split(' ')
if (len(arr) == 0):
print("Error : Input Command")
# command options over the specification is just ignored
if (arr[0] == 'X'):
# exit
sys.exit()
elif (arr[0] == 'I'):
# create canvas
if ((len(arr) < 3) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False)):
print("Error : I M N, (1 <= M, N <= 250)")
else:
temp_width = int(arr[1])
temp_height = int(arr[2])
if ((temp_width < 0) or (temp_width > 250) or (temp_height < 0) or (temp_height > 250)):
print("Error : I M N, (1 <= M, N <= 250)")
else:
self.createCanvas(temp_width, temp_height)
elif (arr[0] == 'C'):
# in case of 'C', ignore other options
self.clearCanvas()
elif (arr[0] == 'L'):
# put pixel
if ((len(arr) < 4) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False) or (arr[3].isalpha() == False)):
print("Error : L X Y C, X & Y is a number, C is a character")
else:
temp_x = int(arr[1])
temp_y = int(arr[2])
if ((temp_x < 0) or (temp_x > self.width) or (temp_y < 0) or (temp_y > self.height)):
print("Error : X, Y are smaller than canvas size")
else:
self.putPixel(temp_x, temp_y, arr[3])
elif (arr[0] == 'V'):
# draw vertical line
if ((len(arr) < 5) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False) or (arr[3].isdigit() == False) or \
(arr[4].isalpha() == False) or (len(arr[4]) != 1)):
print("Error : V X Y1 Y2 C, X & Y is a number, C is a character")
else:
temp_x = int(arr[1])
temp_y1 = int(arr[2])
temp_y2 = int(arr[3])
if ((temp_x < 0) or (temp_x > self.width) or (temp_y1 < 0) or (temp_y1 > self.height) or \
(temp_y2 < 0) or (temp_y2 > self.height)):
print("Error : X, Y1, Y2 are smaller than canvas size")
else:
self.drawVerticalLine(temp_x, temp_y1, temp_y2, arr[4])
elif (arr[0] == 'H'):
# draw vertical line
if ((len(arr) < 5) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False) or (arr[3].isdigit() == False) or \
(arr[4].isalpha() == False) or (len(arr[4]) != 1)):
print("Error : V X1 X2 Y C, X & Y is a number, C is a character")
else:
temp_x1 = int(arr[1])
temp_x2 = int(arr[2])
temp_y = int(arr[3])
if ((temp_x1 < 0) or (temp_x1 > self.width) or (temp_x2 < 0) or (temp_x2 > self.width) or \
(temp_y < 0) or (temp_y > self.height)):
print("Error : X1, X2, Y are smaller than canvas size")
else:
self.drawHorizontalLine(temp_x1, temp_x2, temp_y, arr[4])
elif (arr[0] == 'K'):
# draw rectangle
if ((len(arr) < 6) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False) or (arr[3].isdigit() == False) or \
(arr[4].isdigit() == False) or (arr[5].isalpha() == False) or (len(arr[5]) != 1)):
print("Error : K X1 Y1 X2 Y2 C, X & Y is a number, C is a character")
else:
temp_x1 = int(arr[1])
temp_y1 = int(arr[2])
temp_x2 = int(arr[3])
temp_y2 = int(arr[4])
if ((temp_x1 < 0) or (temp_x1 > self.width) or (temp_x2 < 0) or (temp_x2 > self.width) or \
(temp_y1 < 0) or (temp_y1 > self.height) or (temp_y2 < 0) or (temp_y2 > self.height)):
print("Error : X1, X2, Y1, Y2 are smaller than canvas size")
else:
self.drawRectangle(temp_x1, temp_y1, temp_x2, temp_y2, arr[5])
elif (arr[0] == 'F'):
# fill range
if ((len(arr) < 4) or (arr[1].isdigit() == False) or (arr[2].isdigit() == False) or (arr[3].isalpha() == False) or (len(arr[3]) != 1)):
print("Error : F X Y C, X & Y is a number, C is a character")
else:
temp_x = int(arr[1])
temp_y = int(arr[2])
if ((temp_x < 0) or (temp_x > self.width) or (temp_y < 0) or (temp_y > self.height)):
print("Error : X, Y are smaller than canvas size")
else:
self.fillRangeNoRecursive(temp_x, temp_y, arr[3])
# there are 2 kinds of fill range
# 1) recursive, 2) non-recursive
# recursive type has a beautiful code. but it uses stack for recursive call
# to prevent an issue which is caused by stack overflow, I use non-recursive type
elif (arr[0] == 'S'):
# print canvas
if (len(arr) < 2):
print("Error : S Name")
else:
self.printCanvas(arr[1])
def createCanvas(self, m, n):
if ((m <= 0) or (m > 250) or (n <= 0) or (n > 250)):
return False
try:
self.canvas = [['O'] * m for i in range(n)]
self.width = m
self.height = n
except:
self.canvas = []
self.width = 0
self.height = 0
return False
return True
def clearCanvas(self):
for i in range(self.height):
for j in range(self.width):
self.canvas[i][j] = 'O'
def putPixel(self, x, y, c):
if ((x < 0) or (x >= self.width) or (y < 0) or (y >= self.height)):
return False
self.canvas[y][x] = c
return True
def drawVerticalLine(self, x, y1, y2, c):
if ((x < 0) or (y1 < 0) or (y1 >= self.height) or (y2 < 0) or (y2 >= self.height)):
return False
if (y1 > y2):
y2, y1 = y1, y2 # swap
for i in range(y1, y2 + 1):
self.canvas[i][x] = c
return True
def drawHorizontalLine(self, x1, x2, y, c):
if ((x1 < 0) or (x1 >= self.width) or (x2 < 0) or (x2 >= self.width) or (y < 0) or (y >= self.height)):
return False
if (x1 > x2):
x2, x1 = x1, x2 # swap
for i in range(x1, x2 + 1):
self.canvas[y][i] = c
def drawRectangle(self, x1, y1, x2, y2, c):
if ((x1 < 0) or (x1 >= self.width) or (x2 < 0) or (x2 >= self.width) or \
(y1 < 0) or (y1 >= self.height) or (y2 < 0) or (y2 >= self.height)):
return False
from_x = x1
to_x = x2
if (from_x > to_x):
from_x, to_x = to_x, from_x # swap
from_y = y1
to_y = y2
if (from_y > to_y):
from_y, to_y = to_y, from_y # swap
for i in range(from_y, to_y + 1):
for j in range (from_x, to_x + 1):
self.canvas[i][j] = c
return True
def fillRangeRecursive(self, x, y, c):
if ((x < 0) or (x >= self.width) or (y < 0) or (y >= self.height)):
return False
org_c = self.canvas[y][x]
self.fillPixelRecursive(x, y, org_c, c)
return True
def fillPixelRecursive(self, x, y, org_c, c):
if ((x < 0) or (x >= self.width) or (y < 0) or (y >= self.height)):
return False
if (self.canvas[y][x] == org_c):
self.canvas[y][x] = c
self.fillPixelRecursive(x - 1, y, org_c, c)
self.fillPixelRecursive(x + 1, y, org_c, c)
self.fillPixelRecursive(x, y - 1, org_c, c)
self.fillPixelRecursive(x, y + 1, org_c, c)
return True
def fillRangeNoRecursive(self, x, y, c):
if ((x < 0) or (x >= self.width) or (y < 0) or (y >= self.height)):
return False
org_c = self.canvas[y][x]
#search up
new_y = y
while (True):
new_y -= 1
if (new_y < 0):
break
if (self.fillPixelHorizon(x, new_y, org_c, c) == False):
break
#search same line
self.fillPixelHorizon(x, y, org_c, c)
#search down
new_y = y
while (True):
new_y += 1
if (new_y >= self.height):
break
if (self.fillPixelHorizon(x, new_y, org_c, c) == False):
break
return True
def fillPixelHorizon(self, x, y, org_c, c):
if ((x < 0) or (x >= self.width) or (y < 0) or (y >= self.height)):
return False
if(self.canvas[y][x] != org_c):
return False
self.canvas[y][x] = c
# search left
new_x = x
while (True):
new_x -= 1
if (new_x < 0):
break
if (self.canvas[y][new_x] != org_c):
break
self.canvas[y][new_x] = c
#search right
new_x = x
while (True):
new_x += 1
if (new_x >= self.width):
break
if (self.canvas[y][new_x] != org_c):
break
self.canvas[y][new_x] = c
return True
def printCanvas(self, filename):
print(filename)
for i in range(self.height):
for j in range(self.width):
print(self.canvas[i][j], end='')
print('')
if __name__ == "__main__":
obj = GEditor()
while (True):
obj.inputCommand()
'코딩 테스트' 카테고리의 다른 글
문제 7 : 체크 확인 (Check the Check) (0) | 2022.07.29 |
---|---|
문제 6 : 인터프리터(Interpreter) (0) | 2022.07.28 |
문제 4 : LCD 디스플레이 (0) | 2022.07.26 |
문제 3 : 여행 경비 계산 (0) | 2022.07.20 |
문제 2 : 지뢰 찾기 (0) | 2022.07.18 |