포토샵 같은 그래픽 편집기를 이용하면, 이미지를 수정할 수 있습니다.

이미지 캔버스는 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

+ Recent posts