본문 바로가기
코딩테스트 준비/소프티어

[소프티어] 6255번 - 플레이페어 암호 [Java]

by mwzz6 2025. 2. 7.

https://softeer.ai/practice/6255

 

[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]
[소프티어] 6255번 - 플레이페어 암호 [Java]


1.  아이디어

 

문자열을 통한 구현 문제로 열심히 구현하면 간단하게 해결할 수 있다.


2. 문제풀이

 

먼저 주어진 메시지로 문자를 두 글자씩 나누는 조건을 구현했는데 for문에서 인덱스를 i+=2로 두 칸씩 건너가는 방식으로 두 글자를 뽑아서 다르면 StringBuilder에 넣고 같으면 X가 아니면 X를 넣고 X면 Q를 넣도록 했다. 이때 X 또는 Q를 넣으면 두번째 글자가 X 또는 Q로 대체되는 것이므로 i--로 인덱스를 하나 줄이도록 했다. 또 이때 삽입한 문자의 수를 저장해서 이후 기존 메시지와 삽입한 문자 수의 합이 홀수면 뒤에 X를 추가로 넣는 조건을 구현했다.

 

주어진 키를 표로 변환하는 것은 변환 후 남은 칸은 다시 A부터 없는 알파벳을 채워야하는데 이 구현을 편하게 하기 위해 미리 주어진 키 뒤에 A부터 J를 제외한 Z까지를 더한 후 이 키로 표를 채웠다. 이후 표의 정보로 각 알파벳의 위치를 저장한 맵까지 생성했다.

 

마지막으로 두 글자씩 뽑아서 암호화를 하면 되는데 두 글자의 위치를 맵에서 뽑아서 비교만하면 간단하게 구현할 수 있다.


3. 코드

 

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringBuilder sb = new StringBuilder();

        char[] message = br.readLine().toCharArray();
        char[] newMessage = makeNewMessage(message);

        // 구현의 편의를 위해 미리 J를 제외한 알파벳을 붙여서 키를 생성
        char[] key = (br.readLine() + "ABCDEFGHIKLMNOPQRSTUVWXYZ").toCharArray();

        // 주어진 키를 변환한 표
        char[][] map = init(key);

        // key에 알파벳, value에 표에서의 위치를 저장한 맵
        Map<Character, int[]> posMap = init(map);

        for (int i = 0; i < newMessage.length; i += 2) {
            char c1 = newMessage[i];
            char c2 = newMessage[i + 1];

            int rowC1 = posMap.get(c1)[0];
            int colC1 = posMap.get(c1)[1];
            int rowC2 = posMap.get(c2)[0];
            int colC2 = posMap.get(c2)[1];

            // 규칙 1
            if (rowC1 == rowC2) sb.append(map[rowC1][(colC1 + 1) % 5]).append(map[rowC2][(colC2 + 1) % 5]);
            // 규칙 2
            else if (colC1 == colC2) sb.append(map[(rowC1 + 1) % 5][colC1]).append(map[(rowC2 + 1) % 5][colC2]);
            // 규칙 3
            else sb.append(map[rowC1][colC2]).append(map[rowC2][colC1]);
        }

        bw.write(sb.toString());
        bw.flush();
    }

    // 주어진 메시지를 두 글자씩 나누는 로직 적용
    private static char[] makeNewMessage(char[] message) {
        StringBuilder sb = new StringBuilder();

        int cnt = 0;
        for (int i = 0; i < message.length - 1; i += 2) {
            char c1 = message[i];
            char c2 = message[i + 1];

            if (c1 != c2) {
                sb.append(c1).append(c2);
            } else {
                if (c1 == 'X') sb.append(c1).append('Q');
                else sb.append(c1).append('X');

                cnt++;
                i--;
            }
        }

        // 마지막에 한 글자가 남는 경우
        if ((message.length + cnt) % 2 == 1) sb.append(message[message.length - 1]).append('X');

        return sb.toString().toCharArray();
    }

    // 주어진 키를 표로 변환
    private static char[][] init(char[] key) {
        char[][] map = new char[5][5];
        boolean[] visited = new boolean[26];
        int idx = 0;

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                while (visited[key[idx] - 'A']) {
                    idx++;
                }

                map[i][j] = key[idx];
                visited[map[i][j] - 'A'] = true;
            }
        }

        return map;
    }

    // 알바벳의 위치를 저장한 맵 반환
    private static Map<Character, int[]> init(char[][] map) {
        Map<Character, int[]> posMap = new HashMap<>();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                posMap.put(map[i][j], new int[]{i, j});
            }
        }

        return posMap;
    }

}

4. 후기