[Python] 백준 2615 오목 (Brute Force)

선주·2022년 1월 13일
1

Python PS

목록 보기
19/65
post-thumbnail

📌 문제

오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 19개의 가로줄과 19개의 세로줄이 그려져 있는데 가로줄은 위에서부터 아래로 1번, 2번, ... ,19번의 번호가 붙고 세로줄은 왼쪽에서부터 오른쪽으로 1번, 2번, ... 19번의 번호가 붙는다.

위의 그림에서와 같이 같은 색의 바둑알이 연속적으로 다섯 알을 놓이면 그 색이 이기게 된다. 여기서 연속적이란 가로, 세로 또는 대각선 방향 모두를 뜻한다. 즉, 위의 그림은 검은색이 이긴 경우이다. 하지만 여섯 알 이상이 연속적으로 놓인 경우에는 이긴 것이 아니다.

입력으로 바둑판의 어떤 상태가 주어졌을 때, 검은색이 이겼는지, 흰색이 이겼는지 또는 아직 승부가 결정되지 않았는지를 판단하는 프로그램을 작성하시오. 단, 검은색과 흰색이 동시에 이기거나 검은색 또는 흰색이 두 군데 이상에서 동시에 이기는 경우는 입력으로 들어오지 않는다.

입력

19줄에 각 줄마다 19개의 숫자로 표현되는데, 검은 바둑알은 1, 흰 바둑알은 2, 알이 놓이지 않는 자리는 0으로 표시되며, 숫자는 한 칸씩 띄어서 표시된다.

출력

첫줄에 검은색이 이겼을 경우에는 1을, 흰색이 이겼을 경우에는 2를, 아직 승부가 결정되지 않았을 경우에는 0을 출력한다. 검은색 또는 흰색이 이겼을 경우에는 둘째 줄에 연속된 다섯 개의 바둑알 중에서 가장 왼쪽에 있는 바둑알(연속된 다섯 개의 바둑알이 세로로 놓인 경우, 그 중 가장 위에 있는 것)의 가로줄 번호와, 세로줄 번호를 순서대로 출력한다.

예제 입력 1

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 2 0 0 2 2 2 1 0 0 0 0 0 0 0 0 0 0
0 0 1 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 2 2 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

예제 출력 1

1
3 2


📌 풀이

💬 Code

import sys
input = sys.stdin.readline

board = []
for i in range(19):
    board.append(list(map(int, input().split())))

# → ↓ ↘ ↗
dx = [0, 1, 1, -1]
dy = [1, 0, 1, 1]

for x in range(19):
    for y in range(19):
        if board[x][y] != 0:
            focus = board[x][y]

            for i in range(4):
                cnt = 1
                nx = x + dx[i]
                ny = y + dy[i]

                while 0 <= nx < 19 and 0 <= ny < 19 and board[nx][ny] == focus:
                    cnt += 1

                    if cnt == 5:
                        # 육목 체크
                        if 0 <= x - dx[i] < 19 and 0 <= y - dy[i] < 19 and board[x - dx[i]][y - dy[i]] == focus:
                            break
                        if 0 <= nx + dx[i] < 19 and 0 <= ny + dy[i] < 19 and board[nx + dx[i]][ny + dy[i]] == focus:
                            break
                        # 육목이 아니면 성공한거니까 종료
                        print(focus)
                        print(x + 1, y + 1)
                        sys.exit(0)

                    nx += dx[i]
                    ny += dy[i]

print(0)

💡 Solution

육목 체크까지 해야해서 까다로웠던 문제..🤮

  1. 문제에서 유심히 보아야 할 부분
    • 여섯 알 이상이 연속적으로 놓인 경우에는 이긴 것이 아니다.
    • 아직 승부가 결정되지 않았을 경우에는 0을 출력한다.
    • 승부가 결정되었을 경우에는 연속된 다섯 개의 바둑알 중 가장 왼쪽에 있는 바둑알의 좌표를 출력한다. → 방향을 (→ ↓ ↘ ↗)로 설정해야 하는 이유!
  1. (0, 0)부터 (18, 18)까지 모든 좌표에서 방향 갯수만큼 for문을 4번 돌려 → ↓ ↘ ↗ 방향으로 쭉쭉 5칸씩을 체크 (바둑돌이 놓여있는 경우에만=즉 좌표에 저장된 값이 0이 아닌 경우에만)
    • x, y는 현재 좌표
    • nx, ny는 현재 좌표에서 해당 방향으로 1만큼 이동시킨 좌표
  1. 5칸 연속으로 1 or 2가 놓여있었을 경우 육목인 케이스를 걸러줘야 한다.
    • 첫번째 바둑돌보다 한 칸 이전의 바둑돌 체크
    • 마지막 바둑돌보다 한 칸 이후의 바둑돌 체크

sys.exit(0)

4중 반복문을 사용하고 있는 코드여서, 승리판정시 더이상의 좌표를 탐색하지 않기 위해 이 모든 반복문을 빠져나올 방법이 필요했다.

         if isEnd:
             break
     if isEnd:
        break
if isEnd:
   break

처음엔 isEnd라는 불린값을 만들어서 이런 식으로(^^) 짰는데.. 에바 같아서 다른 방법을 물색해보다가 발견한 것이 sys.exit(0)이다. 얘는 뭐하는 앤지 알아보자!

a = 10
b = 11
print(a+b)

이러한 코드를 짜고 실행을 했을 때 위와 같은 결과창을 보게 된다. 성공적으로 수행된 프로그램은 보다시피 exit code가 0으로 반환된다.

a = 10
b = "f"
print(a+b)

만약 이러한 터무니없는 오류 코드를 짜고 실행을 하면 오류 문장을 출력하며 exit code가 1로 반환되는 것을 알 수 있다.

그렇기에 프로그램이 정상적으로 종료가 됐다는 것을 표시할 때는 인자값을 0으로 주고 비정상적으로 종료가 됐다는 것을 표시할 때는 인자값을 1을 주면 된다.

sys.exit(0)을 실행하면 굳이 불린값으로 종료체크를 하지 않아도 바로 프로그램을 정상종료시킬 수 있다!💡

profile
기록하는 개발자 👀

2개의 댓글

comment-user-thumbnail
2022년 2월 22일

참고 많이 되었습니다~!!
다중 for문 break 해결을 위해 찾아보고 있었는데
sys.exit(0)를 사용한 해결방법이 있었군용

1개의 답글