3 분 소요

처음에는 백준에 제출했다가 결과가 “틀렸습니다” 라고만 나오고 어디가 왜 틀렸는지를 알 수 없어서 정올로 바꿨다.
정올에서는 테스트케이스와 답, 내 출력을 알려줘서 좀 더 쉽게 디버깅할 수 있었다.
현재 코드는 완성된 코드가 아니다. 그런데 나중에 포스트하기 귀찮아질까봐 포스트 형식만 미리 맞춰놓았다.

2월부터 알고리즘 수업을 시작하면서 진도 따라가랴, 스터디 진행하랴 한달이 정신없이 지나갔다. 덕분에 깃헙 잔디는 푸릇푸릇해졌지만 블로그를 신경쓰지 못했다ㅠㅠㅠ 블로그 한달에 한번이라도 포스팅하면 다행일듯… 이 오목 문제도 한달전에 포스팅했더라~ 하하😂 tmi: 결국 백준으로 다시 돌아왔다

문제 제시

문제

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

omok

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

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

입력

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

출력

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

문제 풀이

출력 시 연속된 바둑알 중 가장 위에 있는 것 혹은 가장 왼쪽에 있는 바둑알을 출력해야하기때문에 for문에서 오른쪽위, 오른쪽, 오른쪽아래, 아래쪽만 탐색했다. 그리고 중간에 껴있는 바둑돌인지 체크하기 위해 현재 탐색하는 방향의 전에 있는 바둑돌이 같은 색이라면 탐색을 건너뛰도록 하였다.
탐색 시 배열 밖으로 나가는건 try~catch문을 사용해 처리해줬다.


제출 코드(Java)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;

		int N = 19;
		char[][] board = new char[N][];
		for (int i = 0; i < N; i++) {
			board[i] = br.readLine().replace(" ", "").toCharArray();
		}

		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (board[i][j] == '0') {
					continue;
				}

				for (int k = 0; k < 4; k++) {
					int nr = i + dr[k];
					int nc = j + dc[k];

					if (check(i, j, k, board)) {
						if (dfs(nr, nc, board[i][j], k, 1, board)) {
							sb.append(board[i][j]).append("\n");
							sb.append(i + 1).append(" ").append(j + 1);
							System.out.print(sb.toString());
							System.exit(0);
						}
					}
				}
			}
		}

		System.out.print(0);
	} // end of main

	static int[] dr = { -1, 0, 1, 1 }; // 오른쪽위, 오른쪽, 오른쪽아래, 아래
	static int[] dc = { 1, 1, 1, 0 };

	private static boolean dfs(int r, int c, char color, int way, int cnt, char[][] board) {
		boolean flag = false;
		try {
			if (cnt == 5) {
				if (r < 0 || r > 18 || c < 0 || c > 18) { // 바둑판의 가장자리에 붙어서 오목인 경우
					return true;
				} else if (board[r][c] == color) { // 6목일 경우
					return false;
				} else {
					return true;
				}
			}

			if (board[r][c] != color) {
				return false;
			}

			flag = dfs(r + dr[way], c + dc[way], color, way, cnt + 1, board);

		} catch (ArrayIndexOutOfBoundsException e) {
		}

		return flag;
	} // end of dfs

	private static boolean check(int r, int c, int way, char[][] board) {
		try {
			if (board[r][c] != board[r - dr[way]][c - dc[way]]) {
				return true;
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			return true;
		}

		return false;
	} // end of check

} // end of class


제출 결과

캡처


파일 입력 받아오는것부터 헤매여서 NoSuchElement 처리하는 데에만 몇시간은 쓴것같다ㅠㅜ.
코드 중간중간 제대로 동작하는지 확인하지 않는 습관때문에 제출한 이후에 하나씩 뜯어보느라 시간도 더 오래걸리고 알고리즘이 엉망진창이었다는것도 나중에 알아서 하나를 고치면 문제가 더 생기고 그랬었다.
앞으로 이런 코딩습관은 꼭 고쳐야지…