본문 바로가기
백준 문제 풀이

<코테 챌린지> 빙고 (백준 2578번)

by _비니_ 2024. 10. 14.

❓ 문제

빙고 게임은 다음과 같은 방식으로 이루어진다.

먼저 아래와 같이 25개의 칸으로 이루어진 빙고판에 1부터 25까지 자연수를 한 칸에 하나씩 쓴다

 

다음은 사회자가 부르는 수를 차례로 지워나간다. 예를 들어 5, 10, 7이 불렸다면 이 세 수를 지운 뒤 빙고판의 모습은 다음과 같다.

 

차례로 수를 지워가다가 같은 가로줄, 세로줄 또는 대각선 위에 있는 5개의 모든 수가 지워지는 경우 그 줄에 선을 긋는다.

 

이러한 선이 세 개 이상 그어지는 순간 "빙고"라고 외치는데, 가장 먼저 외치는 사람이 게임의 승자가 된다.

 

철수는 친구들과 빙고 게임을 하고 있다. 철수가 빙고판에 쓴 수들과 사회자가 부르는 수의 순서가 주어질 때, 사회자가 몇 번째 수를 부른 후 철수가 "빙고"를 외치게 되는지를 출력하는 프로그램을 작성하시오.

📥 입력

첫째 줄부터 다섯째 줄까지 빙고판에 쓰여진 수가 가장 위 가로줄부터 차례대로 한 줄에 다섯 개씩 빈 칸을 사이에 두고 주어진다. 여섯째 줄부터 열째 줄까지 사회자가 부르는 수가 차례대로 한 줄에 다섯 개씩 빈 칸을 사이에 두고 주어진다. 빙고판에 쓰여진 수와 사회자가 부르는 수는 각각 1부터 25까지의 수가 한 번씩 사용된다.

📤 출력

첫째 줄에 사회자가 몇 번째 수를 부른 후 철수가 "빙고"를 외치게 되는지 출력한다.

📥 예제 입력

11 12 2 24 10
16 1 13 3 25
6 20 5 21 17
19 4 8 14 9
22 15 7 23 18
5 10 7 16 2
4 22 8 17 13
3 18 1 6 25
12 19 23 14 21
11 24 9 20 15

📤 예제 출력

15

 

👩🏻‍💻 내 코드

package baekjoon.코테챌린지;

import java.util.Scanner;

public class 빙고 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int[][] cheolsu = new int[5][5];
        boolean[][] marked = new boolean[5][5];

        // 철수 빙고판 채우기
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                cheolsu[i][j] = in.nextInt();
            }
        }

        // 선생님이 부르시는 숫자들
        for (int i = 0; i < 25; i++) {
            int teacherInt = in.nextInt();

            markedNum(cheolsu, marked, teacherInt);

            int bingoCount = countBingo(marked);

            if (bingoCount >= 3) {
                System.out.println(i + 1);
                break;
            }
        }
    }

    private static void markedNum(int[][] cheolsu, boolean[][] marked, int teacherInt){
        for(int i = 0; i < 5; i++) {
            for(int j = 0; j < 5; j++) {
                if(cheolsu[i][j] == teacherInt) {
                    marked[i][j] = true;
                    return;
                }
            }
        }
    }

    //빙고가 몇 줄인지 카운트
    private static int countBingo(boolean[][] marked) {
        int count = 0;

        //가로줄 체크
        for(int i = 0; i < 5; i++) {
            boolean rowBingo = true;

            for(int j = 0; j < 5; j++) {
                if(!marked[i][j]) { // 해당 칸이 체크되지 않았다면 (true가 아니라면)
                    rowBingo = false; // 현재 가로줄은 빙고가 아님
                    break; // 더 이상 확인할 필요가 없으므로 중단
                }
            }
            if(rowBingo)
                count++; // 현재 가로줄이 빙고일 경우, 빙고 줄 개수를 증가
        }

        //세로줄 체크
        for(int i = 0; i < 5; i++) {
            boolean columnBingo = true;

            for(int j = 0; j < 5; j++) {
                if(!marked[j][i]) { // 열 체크이므로 행열을 바꿔 체크해주면 됨.
                    columnBingo = false;
                    break;
                }
            }
            if(columnBingo)
                count++;
        }

        //대각선 체크 (왼쪽 상단 -> 오른쪽 하단)
        boolean diagBingo1 = true;
        for(int i = 0; i < 5; i++) {
            if(!marked[i][i]) { //왼쪽 상단 -> 오른쪽 하단 : 행열 번호가 같음!!
                diagBingo1 = false;
                break;
            }
        }

        if(diagBingo1)
            count++;

        boolean diagBingo2 = true;
        for(int i = 0; i < 5; i++) {
            if(!marked[i][4-i]) { //오른쪽 상단 -> 왼쪽 하단 : 행은 0~4 / 열은 4~0
                diagBingo2 = false;
                break;
            }
        }

        if(diagBingo2)
            count++;

        return count;

    }

}

 

💡 코드 접근

  1. 먼저 철수의 5x5 빙고판 숫자 배열을 입력받고, 그 후 선생님이 부른 숫자들 25개를 입력받는다.
Scanner in = new Scanner(System.in);
    int[][] cheolsu = new int[5][5];
    boolean[][] marked = new boolean[5][5];

    // 철수 빙고판 채우기
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            cheolsu[i][j] = in.nextInt();
        }
    }

    // 선생님이 부르시는 숫자들
    for (int i = 0; i < 25; i++) {
        int teacherInt = in.nextInt();

 

 

 

2. 우선 선생님이 부른 숫자를 철수의 빙고판에서 찾아 해당 위치를 체크하는 함수를 만든다.

private static void markedNum(int[][] cheolsu, boolean[][] marked, int teacherInt){
    for(int i = 0; i < 5; i++) {
        for(int j = 0; j < 5; j++) {
            if(cheolsu[i][j] == teacherInt) {
                marked[i][j] = true;
                return;
            }
        }
    }
}
  • marked 배열을 이용해 철수의 빙고판의 숫자가 teacherInt와 같다면, marked를 true로 바꿔준다.

 

3. 빙고가 되는 조건을 따져가며 빙고 수를 카운트하는 함수를 만들어줘야 한다.

 

우선 빙고가 되는 경우는 가로, 세로, 대각선 (왼쪽 상단→ 오른쪽 하단 / 오른쪽 상단 → 왼쪽 하단) 이렇게 있다.

 

  • 가로 / 세로 빙고를 보자.
//가로줄 체크
for(int i = 0; i < 5; i++) {
    boolean rowBingo = true;

    for(int j = 0; j < 5; j++) {
        if(!marked[i][j]) { // 해당 칸이 체크되지 않았다면 (true가 아니라면)
            rowBingo = false; // 현재 가로줄은 빙고가 아님
            break; // 더 이상 확인할 필요가 없으므로 중단
        }
    }
    if(rowBingo)
        count++; // 현재 가로줄이 빙고일 경우, 빙고 줄 개수를 증가
}

 

각각의 가로 줄을 따지는 코드이다.

rowBingo 라는 boolean형 변수를 true로 설정해주고,각각의 가로줄을 체크해주며,

  • 만약 그 줄에 한 칸이라도 marked가 되지 않았다면, 더 이상 확인할 필요도 없이 빙고가 될 수 없다!!
    • 즉 rowBingo를 false로 바꿔주고,
    • break 로 즉시 빠져나와준다.
  • 만약 if 문에 걸리지 않았으면, 즉 rowBingo가 true로 결졍됐다면, count를 올려준다. 즉 빙고가 된 수를 올려주는 것이다.

세로도 마찬가지로 count 해준다.!! (세로이므로 marked[j][i]로 i와 j의 순서를 바꿔주면 된다.)

 

 

  • 다음은 대각선이다.

각각의 칸의 숫자 두 개가 행 열 을 뜻한다고 하고 아래의 표를 보면, 대각선의 행/열을 쉽게 따질 수 있다.

00 01 02 03 04
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
  • 위에 표시한 색은 왼쪽 상단 → 오른쪽 하단의 대각선이다.
  • 즉 marked[i][i] 로 대각선을 표시할 수 있다.

 

00 01 02 03 04
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
  • 위에 표시한 색은 오른쪽 상단 → 왼쪽 하단의 대각선이다.
  • 행은 0에서 4까지 증가하고 열은 4에서 0까지 줄어든다
  • 즉 marked[i][4-i] 로 대각선을 표시할 수 있다.

 

💡 공부한 내용

  • 함수로 분리하기
  • 조기 종료 로직
    • 빙고가 3줄 이상일 경우, 즉시 종료(break)하는 방식으로 불필요한 계산을 방지하여 효율을 높일 수 있음
반응형