알고리즘/codewars

codewars: Simple Encryption #3 - Turn The Bits Around

꾸준함. 2018. 3. 3. 00:18

문제 링크입니다: https://www.codewars.com/kata/simple-encryption-number-3-turn-the-bits-around/train/cpp


/*

암호화를 위해 다음의 순서대로 64개의 허용된 문자가 있다.

1. 모든 알파벳(오름차순으로 대문자, 소문자) -> 52

2. 모든 한자리수 숫자(오름차순) -> 10

3. " " "." -> 2

 

따라서 모든 문자는 6자리 비트로 표현 가능하다!

 

미리 체크해야할 사항

1. 허용된 문자가 안나온다면 예외처리를 진행해야한다

2. NULL이거나 빈 string이라면 그대로 반환해준다

 

암호화를 하기 위해서는 다음과 같은 규칙을 따른다

1. 해당 문자의 5번째 비트와 다음 문자의 첫비트를 바꾼다(다음문자가 존재한다면)

2. 2번째 비트와 4번째 비트를 뒤바꾼다

3. 1, 2, 3번째 비트와 4, 5, 6번째 비트를 서로 바꾼다

4. 모든 홀수번째 비트와 짝수번째 비트를 서로 바꾼다(i <=> i+1)

5. 비트를 거꾸로 뒤집는다

6. 첫번째 비트와 세번째 비트를 맞바꾼다

*/

#include <iostream>

#include <string>

#include <algorithm>

using namespace std;

 

//허용된 문자

string range = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .";

 

std::string encrypt(std::string text)

{

        if (text.empty())

               return text;

 

        int nextChar = -1;

        for (int i = 0; i < text.length(); i++)

        {

               if (range.find(text.substr(i, 1)) == string::npos) //허용된 문자가 아니라면

                       throw exception();

               int idx = range.find(text.substr(i, 1));

 

               int bits[6];

               int divisor = 32; //첫 번째 비트는 2^5

               for (int j = 0; j < 6; j++)

               {

                       bits[j] = idx / divisor;

                       idx %= divisor;

                       divisor /= 2;

               }

 

               //1번 조건

               //해당 문자의 5번째 비트와 다음 문자의 첫비트를 바꾼다

               if (nextChar != -1)

                       bits[0] = nextChar;

               if (i < text.length() - 1)

               {

                       nextChar = bits[4];

                       bits[4] = range.find(text.substr(i + 1, 1)) / 32; //첫번째 비트는 2^5이므로

               }

               //2번 조건

               //2번째 비트와 4번째 비트를 뒤바꾼다

               bits[1] = 1 - bits[1];

               bits[3] = 1 - bits[3];

               //3번 조건

               //1, 2, 3번째 비트와 4, 5, 6번째 비트를 서로 바꾼다

               swap(bits[0], bits[3]);

               swap(bits[1], bits[4]);

               swap(bits[2], bits[5]);

               //4번 조건

               //모든 홀수번째 비트와 짝수번째 비트를 서로 바꾼다

               for (int j = 0; j < 6; j+=2)

                       swap(bits[j], bits[j + 1]);

               //5번 조건

               //비트를 거꾸로

               for (int j = 0; j < 3; j++)

                       swap(bits[j], bits[5 - j]);

               //6번 조건

               //첫번째 비트와 세번째 비트를 맞바꾼다

               swap(bits[0], bits[2]);

 

               int newChar = 0;

               divisor = 32;

               for (int j = 0; j < 6; j++)

               {

                       newChar += bits[j] * divisor;

                       divisor /= 2;

               }

               text.replace(i, 1, range.substr(newChar, 1)); //해당 문자를 찾는다

        }

        return text;

}

 

std::string decrypt(std::string encryptedText)

{

        if (encryptedText.empty())

               return encryptedText;

 

        //encrypt와 반대로

        for (int i = encryptedText.length() - 1; i >= 0; i--)

        {

               if (range.find(encryptedText.substr(i, 1)) == string::npos) //허용된 문자가 아니라면

                       throw exception();

               int idx = range.find(encryptedText.substr(i, 1));

 

               int bits[6];

               int divisor = 32;

               for (int j = 0; j < 6; j++)

               {

                       bits[j] = idx / divisor;

                       idx %= divisor;

                       divisor /= 2;

               }

 

               //6번 조건

               swap(bits[0], bits[2]);

               //5번 조건

               for (int j = 0; j < 3; j++)

                       swap(bits[j], bits[5 - j]);

               //4번 조건

               for (int j = 0; j < 6; j += 2)

                       swap(bits[j], bits[j + 1]);

               //3번 조건

               swap(bits[0], bits[3]);

               swap(bits[1], bits[4]);

               swap(bits[2], bits[5]);

               //2번 조건

               bits[1] = 1 - bits[1];

               bits[3] = 1 - bits[3];

 

               int newChar = 0;

               divisor = 32;

               for (int j = 0; j < 6; j++)

               {

                       newChar += bits[j] * divisor;

                       divisor /= 2;

               }

               encryptedText.replace(i, 1, range.substr(newChar, 1));

        }

 

        int beforeChar = -1;

        for (int i = encryptedText.length() - 1; i >= 0; i--)

        {

               if (range.find(encryptedText.substr(i, 1)) == string::npos) //허용된 문자가 아니라면

                       throw exception();

               int idx = range.find(encryptedText.substr(i, 1));

 

               int bits[6];

               int divisor = 32;

               for (int j = 0; j < 6; j++)

               {

                       bits[j] = idx / divisor;

                       idx %= divisor;

                       divisor /= 2;

               }

 

               //1번 조건

               if (beforeChar != -1)

                       bits[4] = beforeChar;

               if (i > 0)

               {

                       beforeChar = bits[0];

                       //5번째 비트(2^1)가 켜져있는지 꺼져있는지만 알고싶으므로

                       //MOD 4를 진행한 후 2로 나누어 판별

                       bits[0] = (range.find(encryptedText.substr(i - 1, 1)) % 4) / 2;

               }

 

               int newChar = 0;

               divisor = 32;

               for (int j = 0; j < 6; j++)

               {

                       newChar += bits[j] * divisor;

                       divisor /= 2;

               }

               encryptedText.replace(i, 1, range.substr(newChar, 1));

        }

        return encryptedText;

}

 

int main(void)

{

        cout << encrypt("A") << endl;

        cout << decrypt("K") << endl;

        cout << encrypt("Abc") << endl;

        cout << decrypt("KyU") << endl;

        cout << encrypt("B9") << endl;

        cout << decrypt("rw") << endl;

        return 0;

}


개발환경:Visual Studio 2017


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~

반응형

'알고리즘 > codewars' 카테고리의 다른 글

codewars Factorial decomposition  (0) 2018.02.26
codewars Matrix Determinant  (0) 2018.02.26
codewars: Count ones in a segment  (0) 2018.02.23
codewars: Sum by Factors  (0) 2018.02.20
codewars: Path Finder #2: shortest path  (0) 2018.02.20