ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 23.7 지뢰찾기(어려움..)
    코딩도장 심사문제모음 2020. 10. 18. 17:51
    728x90

    표준 입력으로 2차원 리스트의 가로(col)와 세로(row)가 입력되고 그 다음 줄부터 리스트의 요소로 들어갈 문자가 입력됩니다. 이때 2차원 리스트 안에서 *는 지뢰이고 .은 지뢰가 아닙니다. 지뢰가 아닌 요소에는 인접한 지뢰의 개수를 출력하는 프로그램을 만드세요(input에서 안내 문자열은 출력하지 않아야 합니다).

    여러 줄을 입력 받으려면 다음과 같이 for 반복문에서 input을 호출한 뒤 append로 각 줄을 추가하면 됩니다(list 안에 문자열을 넣으면 문자열이 문자 리스트로 변환됩니다).

    matrix = []

    for i in range(row):    

    matrix.append(list(input()))

    이 문제는 지금까지 심사문제 중에서 가장 어렵습니다. 처음 풀어보는 경우 대략 두 시간은 걸립니다. 시간을 두고 천천히 고민해서 풀어보세요. 지금까지 학습한 내용을 모두 동원해야 풀 수 있으며 막힐 때는 지금까지 학습한 내용을 다시 복습하면서 힌트를 찾아보세요.

    사용한 코드

    ## map, int, input, split, appende, list, for 문, if문, 비교 연산자, print 많은 함수 및 메서드를 이용함

    첫 접근 방법

    여지껏 해왔던 문제들 중 가장 어려웠다.

    우선 입력한 값을 list와 append로 입력 값을 토대로 리스트를 만들어주는 방법은 홈페이지에서 제시해주지 않았다면 알지 못했다.

    만약 이 과정이 생략되었다면 다른 접근방법이 분명 존재한다고 생각한다.

    문제 해결하는데 거의 2틀 정도를 소모한것 같다. 결국 스터디 팀장님과 함께 코드 리뷰를 하며 이해할 수 있었다.

    기준을 어디에 두느냐에 따라 다양한 정답이 나올 수 있는 문제이며 첫번째 기준을 문자열 " . " 로 잡고 2차원 리스트의 인덱스 번호를 통해 접근하여 i -1, i+2 // j-1, j+2 (i, j 가로 세로 임의의변수) 로 인접한 8개의 요소를 체크할 수 있도록 for문과 결합하는 방식으로 진행하였다.

    해답을 보지 않고는 풀지 못했던 문제이므로 이러한 류의 문제를 많이 접하고 반복 학습을 해야겠다.

    풀이

    <!-- 들여쓰기 구분을 위해 이미지 사용-->

    1. 먼저 M x N 구조는 matrix 라는 구조로 matrix라는 변수에 빈 리스트를 만들고 시작한다.

    빈 리스트로 입력된 값을 다시 리스트로 추가하는 방식으로 2차원 리스트를 생성한다.

    입력값

    3 3

    **.

    *..

    .*.

    입력할 경우 [['*' , '*', '.'], ['*', '.', '.'], ['.', '*', '.']] 같은 2차원 리스트가 생성된다.  ( print(matrix) 로 확인 가능)

    이때 입력된 값을 기준으로 range의 범위를 지정해줘야하는데, 나는 x, y (가로, 세로) 순으로의 기준을 세워 range(y)를 지정해주었다.

    range(y)의 경우

    3 x 3 -> 가로 3 세로 3 줄 (0, 1, 2 반복)

    3 x 4 -> 가로 3 세로 4줄 (0, 1, 2, 3 반복) 출력이 된다.

    2. for문을 시작으로 입력된 값에 따라 range 범위를 정하고 인덱스 순서대로 검증에 들어간다.

    3. for문으로 변수 i, j의 반복 횟수를 정한 후 기준을 정해준다.

    지뢰가 아닐때(" . ") 를 기준으로 정하였다.

    지뢰가 아닐때를 기준으로 상하좌우 + 대각선으로 총 인접한 8개의 요소에 대해 하나하나 지뢰의 수를 카운트 해야하기 때문에

    count = 0 이라는 변수를 할당해 주었다.

    주변에 지뢰가 없다면 count 는 그대로 0 으로 남아있을것이며, 근처 지뢰가 있다면 하나하나 인접한 요소를 검증함에 따라 +1 씩 count 값이 상승할 것이다.

    4. 기준이 되는 x행 x열에서의 인접한 8개의 요소를 하나하나 검증하기 위해 5x5를 기준으로 인덱스 번호를 생각해보자.

    2행 2열을 기준으로 인접한 8개의 요소를 검증하기 위해 (코드에서의 변수 : a == 행,  b ==열)

    [2][2] --> i == 2/ j == 2 로 생각할 경우

    i -1, i+2 와 j -1, j+2 로 range 범위를 정해주면 기준을 포함한 인접 8개의 인덱스번호를 모두 검증할수 있다

    range(1, 4) 의 경우 4를 포함하지 않기 때문에 4를 포함하려면 range(1, 5)를 넣어줘야하는 것과 마찬가지로

    range(i-1, i+2) 

    range(j-1, j+2) // 끝 범위에 +1 을 해준다.

    5. 인접한 요소의 범위를 지정했다면 이제 인덱스 번호를 이용해 해당 x행x열에 " * " 이 있는지 없는지 확인해준다.

    이때 if not (a >0 or b >0 or a >= y or b >= x):

    if 만 사용했을 경우 --> () 안의 경우 일때 아래 코드블럭을 실행하지만

    if not을 사용했을 경우 --> () 안의 경우가 아닐때 아래 코드블럭을 실행한다.

    결국 ()안의 조건이 아닌 경우에만 아래 코드블럭을 실행한다는 의미이다.

    조건식을 걸어줘야하는데 이 부분에서 가장 중요한 부분으로 생각된다.

    범위를 정하는 것은 그려보거나 표현하면 확인이 가능하다 조건식은 개념이 박혀있지 않다면 도출 할 수 없다고 생각한다.

    for a in range(i-1, i+2):

         for b in range(j-1, j+2):

    5x5를 기준으로

    i = 0 ~ 4

    j = 0 ~ 4

    만약 i == 0, j ==0 일 경우 생각해보자 4행4열에 " ." 가 있을 경우 인덱스 번호로 8개의 인접한 요소에 지뢰 수를 종합하여하는데

    이때 a = -1, 0, 1 // b = -1, 0, 1 라는 수로 인덱스 번호를 찾아가야하는데 a, b가 음수가 나올 경우 -1행, -1 열이란 것은 존재하지 않으며

    만약 i == 4, j ==4 일 경우를 생각해보자 4행4열에 " ." 가 있을 경우 인덱스 번호로 8개의 인접한 요소에 지뢰 수를 종합하여하는데

    이때 a = 3, 4, 5 // b = 3, 4, 5라는 수로 5행 5열이라는 요소는 존재하지 않는 요소로

    해당 조건문이 삽입되지 않을 경우 정확한 count가 되지 않으며 코드 또한 error가 나게 된다.

     

    추가로 아래와 같은 조건으로 0보다 커야한다는 이유도 생각해볼수있다 (이점은 질문 사항에 포함시켜야겠다)

    인덱스 번호는 아래와 같이 2가지 방법으로 읽을 수 있다.

    A = [a, b, c, d]

    A라는 리스트 요소들의 인덱스 번호

    1. A[0] == a , A[1] == b, A[2] == c, A[3] == d

    2.A[-4] == a , A[-3] == b, A[-2] == c, A[-1] == d 

    이때문에 음수가 아니라는 조건이 들어간 것은 아닌지 생각해볼 필요가 있다.

    6. 인접 요소를 모두 확인하였다면 if 조건문을 한번 더 사용하여 해당 인덱스 번호에 지뢰가 있을 경우

    count 변수에 +1 을 해줘야한다.

    여기서 좌측 00 Line으로 리뷰를 하는게 보다 효율적이라 생각한다.

    다시 한번 [2][2]를 기준으로 생각해보자.

    먼저 12 Line a 는 1, 2, 3 의 범위로 시작한다

    a == 1일때 13 Line b 는 1, 2, 3 범위로 시작한다.

    a ==1 , b ==1 일때는 [1][1] 요소를 검증한다.

    [1][1] = " . " 일경우

    14 Line의 () 조건에 부합하므로 15 Line으로 넘어가 해당 요소에 지뢰가 있는지 검증한다.

    [1][1] 에는 지뢰가 있으므로 16 Line 코드 블럭을 실행하여 count = count +1 로 count = 1이 된다.

    count를 1 증가 시킨 후, 13 Line의 for 문으로 돌아가 [1] [2]를 동일한 방법으로 검증한다.

    [1][3]까지 검증을 마친 경우 ([1][2], [1][3] 모두 지뢰가 있었다 가정하자)

    count = 3이 되어있는 상태에서 12 Line for 반복문으로 넘어가 a =2 

    즉, [2][1] [2][2] [2][3]을 위와 같은 방법으로 검증한다.

    [1][1] = " * " 일경우

    11 Line if 조건문에 False 이므로 20, 21 Line으로 넘어가 " *" 을 출력하고 9 Line for 반복문으로 올라가

    [1][2] 를 검증한다.

    인전합 8개의 요소를 전부 다 검증한 경우 a, b 의 range 범위에 있는 모든 수를 꺼내 사용한 후

    11 Line의 코드블럭을 모두 실행 완료 하여 빠져나오고

    17 Line의 코드를 실행 이제까지 count 해왔던 수를 matrix[i][j] 변수에 할당해준다.

    할당 후 pirnt 함수로 matrix[i][j] 즉, count = 00(갯수) 를 출력하고 pirint 출력의 끝을 지정해주는 end 함수로 자동 줄바꿈이 되지 않고

    바로 우측에 뒤이에 출력되도록 걸어준다.

    출력을 완료 한 후 다시 9 Line for 반복문으로 올라가 위와 같이 코드를 다시 반복한다.

    언제까지?? -->range (5) 0 ~ 4 열까지 모두 출력할때까지

    01001 과 같이 0행을 모두 출력하였다면 더 이상 range(5) 의 범위에서 j 가 더 사용할 요소가 없으므로

    부모(?) 가장 상위에 걸려있는 8 Line for 반복문의 print() 로 내려가 아무것도 출력하지 않고 단순 줄바꿈해준다.

    그 후,

    8 Line의 for 반복문으로 올라간다 for i inr range(5):

    여지껏 range(5) : 0 1 2 3 4 중

    i == 0 일때를 반복한 것으로 i == 1로 동일하게 반복해주고 i == 4 를 모두 사용했다면 함수는 종료된다.

     

     

    ※ 실제 코딩 도장의 해법과 다를  수 있으며, 답은 여러가지가 존재합니다.

    코딩 지적 정말 감사히 받겠습니다.

     

     

    728x90
Designed by Tistory.