프로그래머스 - 혼자서 하는 틱택토

Lee·2023년 3월 23일
0

알고리즘

목록 보기
6/34
post-thumbnail

문제 출처

문제 출처 : 혼자서 하는 틱택토

문제 이해하기

  • 지문이 좀 길어서 이해하기까지 시간이 좀 오래 걸렸다. 정리하자면 입력으로 들어온 board 배열을 기준으로 틱택토 규칙에 맞게 게임을 진행할 수 있냐 없냐를 따지는 문제이다.

주요 조건 이해하기 ⭐️

문제에 주어진 틱택토 규칙은 간단하다.

  • 선공은 O, 후공은 X 순서로 진행한다. (틱택토를 완성하지 못한 경우)
  • 선공 혹은 후공이 틱택토를 완성할 경우 게임은 종료된다. (틱택토를 완성한 경우)

이 조건을 가지고 틱택토 규칙을 어긴 경우의 수를 생각할 수 있다.

  • 틱택토를 완성하지 못한 경우 (순서를 어긴 경우)
    • X가 O보다 많은 경우 (선공/후공 순서를 지키지 않은 경우)
    • O가 X보다 2개 이상 많은 경우 (1턴씩 번갈아가면서 진행하지 않은 경우)
  • 틱택토를 완성한 경우 (종료하지 못한 경우)
    • O로 완성한 경우 (O의 갯수가 X와 동일하다면, O로 빙고인 경우는 X의 갯수보다 1개 더 크기 때문에 종료되지 않은 경우)
    • X로 완성한 경우 (X의 갯수가 O의 갯수보다 1개 이상 많다면, X가 후공인 상태에서 X가 완성될 경우 게임이 종료되어야 하지만, O의 갯수가 X보다 1개 이상 많다는 것은 게임이 종료되지 않았다는 경우)
  • 문제를 잘 이해했다면 결국 게임의 진행 여부는 O의 갯수와 X의 갯수로 판단한다는 것을 알 수 있다.

주의할 점

  • O, X 동시에 틱택토가 완성되는 경우도 게임의 룰을 어긴것이다.

구현 스케치

public int solution(String[] board) {
		int answer = 1;

		// O, X의 갯수를 먼저 파악
		getCount(board);

		// 갯수를 기준으로 규칙을 어긴 케이스 판별
		if (!breakRuleOfCount()) {
			answer = 0;
		}

		boolean oWin = breakRuleOfComplete(board, 'O');
		boolean xWin = breakRuleOfComplete(board, 'X');

		// 둘다 빙고면 문제 있음
		if (oWin && xWin) {
			answer = 0;
		}

		// 둘 중 하나가 완성된 경우 규칙을 어긴 케이스 판별
		if (oWin && OCount == XCount || xWin && OCount > XCount) {
			answer = 0;
		}

		return answer;
	}

최종 소스 파일

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *     * X 가 O 보다 많을 경우
 *     * O 가 X 보다 2개 이상 많을 경우
 *     * O가 완성되었을 때 X가 O와 같은 경우
 *     * X가 완성되었을 때 O가 X보다 1개 많은 경우
 */
public class TicTacTo {

	int OCount = 0;
	int XCount = 0;

	// 스트림으로 처리하면 2중 for가 필요없다.
	private void getCount(String[] board) {
		Map<Character, Long> collect = Arrays.stream(board)
			.flatMap(row -> row.chars()
				.mapToObj(word -> (char) word))
			.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

		OCount = collect.getOrDefault('O', 0L).intValue();
		XCount = collect.getOrDefault('X', 0L).intValue();
	}

	// 갯수를 기준으로 규칙을 어긴 케이스 판별
	private boolean breakRuleOfCount() {

		// X가 O보다 많은 경우 또는 O가 X보다 2개 이상 많은 경우
		if (XCount > OCount || OCount - XCount >= 2) {
			return false;
		}

		return true;
	}

	private boolean breakRuleOfComplete(String[] board, char word) {
		// 가로 완성
		for (int i = 0; i < 3; i++) {
			if (board[i].charAt(0) == word && board[i].charAt(1) == word && board[i].charAt(2) == word) {
				return true;
			}
		}

		// 세로 완성
		for (int i = 0; i < 3; i++) {
			if (board[0].charAt(i) == word && board[1].charAt(i) == word && board[2].charAt(i) == word) {
				return true;
			}
		}

		// 좌->우 대각선 완성
		if (board[0].charAt(0) == word && board[1].charAt(1) == word && board[2].charAt(2) == word) {
			return true;
		}

		// 우->좌 대각선 완성
		if (board[0].charAt(2) == word && board[1].charAt(1) == word && board[2].charAt(0) == word) {
			return true;
		}

		return false;
	}


	public int solution(String[] board) {
		int answer = 1;

		// O, X의 갯수를 먼저 파악
		getCount(board);

		// 갯수를 기준으로 규칙을 어긴 케이스 판별
		if (!breakRuleOfCount()) {
			answer = 0;
		}

		boolean oWin = breakRuleOfComplete(board, 'O');
		boolean xWin = breakRuleOfComplete(board, 'X');

		// 둘다 빙고면 문제 있음
		if (oWin && xWin) {
			answer = 0;
		}

		// 둘 중 하나가 완성된 경우 규칙을 어긴 케이스 판별
		if (oWin && OCount == XCount || xWin && OCount > XCount) {
			answer = 0;
		}

		return answer;
	}

	public static void main(String[] args) {
//		System.out.println(solution(new String[]{"O.X", ".O.", "..X"}));
//		System.out.println(solution(new String[]{"OOO", "...", "XXX"}));
//		System.out.println(solution(new String[]{"...", ".X.", "..."}));
//		System.out.println(solution(new String[]{"...", "...", "..."}));




	}
}

0개의 댓글