[포스코x코딩온] 스마트팩토리 3주차 회고 | C++ 랜덤 숫자 맞추기, 홀수마방진 만들기

이남웅·2023년 4월 9일
0

1. 랜덤 숫자 맞추기

규칙 1. 컴퓨터가 1 ~ 25까지의 수 중 랜덤으로 중복되지 않는 6개의 수를 생성한다.
규칙 2. 사용자는 예상되는 6개의 숫자를 입력한다.
규칙 3. 모두 맞출 시 1등, 하나를 틀릴 시 2등으로 가며, 모두 맞추지 못하면 7등이 된다.

#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;

int chk_num_dup(int num, vector<int> num_arr)
{
    for (int i = 0; i < 6; i++)
        if (num == num_arr[i]) // 같을 때
            return (1);
    return (0);
}

int main(void)
{
    srand(time(NULL));
    int i = 0;
    int temp_num = 0, cor_num = 0; // 임시 저장, 맞춘 횟수
    vector<int> com_num_arr(6, 0);
    vector<int> hum_num_arr(6, 0);

    for (i = 0; i < 6; i++) // 랜덤 번호 생성
    {
        do
            temp_num = rand() % 25 + 1;
        while (chk_num_dup(temp_num, com_num_arr));
        com_num_arr[i] = temp_num;
    }

    cout << "숫자는 1 ~ 25까지의 숫자만 입력할 수 있습니다." << endl;
    for (i = 0; i < 6; i++)
    {
        do
        {
            cout << i + 1 << "번째 번호를 입력하세요: ";
            cin >> temp_num;
            if (temp_num < 1 || temp_num > 25)
                cout << "잘못된 숫자입니다. 다시 입력해주세요." << endl;
            else if (chk_num_dup(temp_num, hum_num_arr))
                cout << "이미 입력된 숫자입니다." << endl;
            else
            {
                hum_num_arr[i] = temp_num;
                break;
            }
        } while (1);
    }

    cout << "--------------------------" << endl;
    cout << "당첨번호 공개!" << endl;
    for (i = 0; i < 6; i++)
    {
        cout << com_num_arr[i] << " ";
        if (chk_num_dup(com_num_arr[i], hum_num_arr))
            cor_num++;
    }
    cout << endl
         << "1 ~ 7등까지 결과가 나올 수 있습니다." << endl;
    cout << "결과 : " << -(cor_num - 7) << "등입니다!";

    return (0);
}

프로그래밍을 하기 전에 규칙을 보면서 하나하나씩 프로그래밍을 하는 방식으로 접근해보자.

규칙 1. 컴퓨터가 1 ~ 25까지의 수 중 랜덤으로 중복되지 않는 6개의 수를 생성한다.

컴퓨터가 1 ~ 25까지의 랜덤한 수를 생성한다. 이렇게 하기 위해서는 랜덤 함수를 사용하여야 한다.

srand(time(NULL));
rand() % 25 + 1;

랜덤 함수를 사용하기 위해 cstdlib의 라이브러리를 불러온다. 랜덤함수를 사용하기 전 srand()함수를 현재까지 흘러간 초(time(NULL))를 인자로 넣어준다. 그리고 시작하는 수가 0이 아닌 1이므로 1을 더해준다. 이렇게 나온 랜덤한 수를 6개의 변수를 가진 벡터에 대입해준다. 대입하기 전 6개의 수가 모두 중복되지 않아야 한다. 벡터에서 입력된 수가 중복된 수인지 비교를 해주는 함수를 만들어준다.

int chk_num_dup(int num, vector<int> num_arr)
{
    for (int i = 0; i < 6; i++)
        if (num == num_arr[i]) // 같을 때
            return (1);
    return (0);
}

벡터의 수와 대입받은 수를 비교한 후 만약 벡터에 같은 수가 있다면 1을 반환해준다. 같은 수가 없다면 0을 반환해준다. 이렇게 규칙 1은 완성했으니 규칙 2로 넘어가자

규칙 2. 사용자는 예상되는 6개의 숫자를 입력한다.

    for (i = 0; i < 6; i++)
    {
        do
        {
            cout << i + 1 << "번째 번호를 입력하세요: ";
            cin >> temp_num;
            if (temp_num < 1 || temp_num > 25)
                cout << "잘못된 숫자입니다. 다시 입력해주세요." << endl;
            else if (chk_num_dup(temp_num, hum_num_arr))
                cout << "이미 입력된 숫자입니다." << endl;
            else
            {
                hum_num_arr[i] = temp_num;
                break;
            }
        } while (1);
    }

여기서는 사용자가 입력한 수를 벡터에 대입하기 전 2개의 예외처리를 해주어야 한다. if문을 통해 범위를 초과하는 수는 입력 받을 수가 잘못된 숫자라고 알려주고, 중복된 숫자를 입력 받을 시 아까 만든 함수를 이용하여 이미 입력된 숫자라고 알려준다.
이렇게 컴퓨터가 생성한 난수 벡터과 사용자가 입력한 숫자 벡터, 2개가 완성되었다. 이제 두 벡터를 비교하여 등수를 출력해주면 된다.

규칙 3. 모두 맞출 시 1등, 하나를 틀릴 시 2등으로 가며, 모두 맞추지 못하면 7등이 된다.

for (i = 0; i < 6; i++)
{
	cout << com_num_arr[i] << " ";
    if (chk_num_dup(com_num_arr[i], hum_num_arr))
    	cor_num++;
}
cout << endl
     << "1 ~ 7등까지 결과가 나올 수 있습니다." << endl;
cout << "결과 : " << -(cor_num - 7) << "등입니다!";

컴퓨터가 생성한 난수와 사용자가 입력한 숫자를 if문을 통해 숫자 비교 함수를 활용하여 cor_num을 증가 시켜주고, 마지막에 등수를 출력해준다.

2. 홀수 마방진 만들기

규칙 1. 홀수 n의 숫자를 입력받아 n*n의 크기의 마방진을 출력한다.

#include <iostream>
#include <vector>
using namespace std;

int main(void)
{
    int ent_num = 0;
    int i = 0, j = 0;
    int x = 0, y = 0;

    cout << "마방진의 형 혹은 열의 수를 자연수(홀수)로 입력해주세요.";
    cin >> ent_num;
    vector<vector<int> > num_arr(ent_num, vector<int>(ent_num, 0));
    x = 0, y = ent_num / 2, num_arr[x][y] = 1;

    for(i = 2; i <= (num_arr.size() * num_arr[0].size()); i++)
    {
        x--;
        y--;
        if (x < 0)
            x = ent_num - 1;
        if (y < 0)
            y = ent_num - 1;
        if (num_arr[x][y] != 0)
            x++;
        num_arr[x][y] = i;
    }

    for(i = 0; i < num_arr.size(); i++)
    {
        for(j = 0; j < num_arr[0].size(); j++)
        {
            if (num_arr[i][j] >= 100)
                cout << " ";
            else if (num_arr[i][j] >= 10)
                cout << "  ";
            else
                cout << "   ";
            cout << num_arr[i][j];
        }
        cout << endl;
    }
}

먼저 마방진은 정사각형 숫자 배열의 가로, 세로, 대각선의 숫자의 합이 모두 비슷한 것을 말한다.

마방진을 푸는 방식은 여러가지가 있지만 다음과 같은 방식으로 풀었다.

  1. 첫번째 열의 가운데에 1을 집어넣는다.
  2. 왼쪽으로 한칸, 위쪽으로 한칸 이동하고, 그 다음 숫자를 넣는다.
  3. 만약 칸이 없다면 그 너머의 칸인 반대칸에 숫자를 대입한다.
  4. 칸에 숫자가 있다면 아래로 한칸 이동한 숫자를 넣는다.

크기가 큰 마방진을 보면서 따라가 보면 이해하기가 편하다.

25*25의 크기의 마방진을 보면 숫자가 대각선으로 증가하는 모습을 볼 수 있다.

마방진을 만드는 규칙을 보면서 하나하나씩 마방진을 풀어보자.

  1. 첫번째 열의 가운데에 1을 집어넣는다.
x = 0, y = ent_num / 2, num_arr[x][y] = 1;
for(i = 2; i <= (num_arr.size() * num_arr[0].size()); i++)

2차원 벡터를 생성해준 뒤, x, y의 값을 첫번째 열의 가운데로 설정하고 1을 대입해준다.
그 후 n x n개의 숫자를 대입해주어야 한다. 방금 1을 대입해주었으므로, 2로 시작하고 n x n만큼 반복하는 반복문을 만들어준다.

  1. 왼쪽으로 한칸, 위쪽으로 한칸 이동하고, 그 다음 숫자를 넣는다.
x--;
y--;

반복해줄때 마다 왼쪽으로 한칸, 위쪽으로 한칸 이동하므로 x, y를 감소해준다.

  1. 만약 칸이 없다면 그 너머의 칸인 반대칸에 숫자를 대입한다.
if (x < 0)
	x = ent_num - 1;
if (y < 0)
	y = ent_num - 1;

만약 x, y가 음수 값이 되면 칸이 넘어간 것으로 마지막 칸인 n번째 칸으로 넘어간다.

  1. 칸에 숫자가 있다면 아래로 한칸 이동한 숫자를 넣는다.
if (num_arr[x][y] != 0)
	x++;

대입하려고 하는 칸이 0이 아니라면 숫자가 대입되있는 것으로 아래 칸으로 이동한다.

칸의 너비를 적절히 설정해 주어 출력을 하면 다음과 같은 마방진이 출력되게 된다.

코드를 실행하게 되면 마방진의 숫자가 비슷하게 나오는 것을 알 수 있다. 마방진을 푸는 방식은 여러가지이므로 다른 방식으로 코드를 짜게 되면 다른 마방진이 나오게 된다. 1번 문제와 같이 랜덤 함수를 이용하여 2차 배열을 생성한 후 가로, 세로, 대각선의 합을 비교하여 마방진을 만들 수 있지만 이렇게 되면 경우의 수가 너무 많아지기 때문에 3 x 3 이상의 마방진은 생성하기가 어렵다. 5 x 5 크기의 마방진을 생성하게 되면 30분 넘게 걸린다고 하니 다음과 같은 규칙을 활용하여 마방진을 만들면 쉽게 만들 수 있을 것 같다.

0개의 댓글