(C++) 스마트팩토리 - 24

내 이름 안찬찬·2023년 2월 26일
0
post-thumbnail

이번에 프로그래밍 한 건 마방진!

마방진은 1에서 n제곱까지의 수를 정사각형으로 배열해 가로, 세로, 대각의 합계가 모두 같도록 만드는 것이다.


마방진 규칙

사용자로부터 홀수 n을 입력받아 n * n의 마방진 만들기.

1) 1은 첫 행의 가운데에 위치한다.

2) 우상단으로 갈 수록 숫자가 1씩 늘어난다.

3) 우상단으로 이동하는 도중 이미 칸이 채워져 있으면 바로 아래칸에 다음 숫자가 채워진다.

4) 첫번째 행에서 우상단으로 이동할 때는 마지막 행의 다음 열로 이동한다.

5) 마지막 열에서 우상단으로 이동할 때는 첫번째 열의 이전 행으로 이동한다.

6) 첫번째 행의 마지막 열에선 우상단 이동이 아닌 바로 아래칸으로 이동


첫 작성 코드

#include <iostream>
#include <vector>

using namespace std;

int main() {
	int n;
	cout << "만들고자 하는 마방진의 행 또는 열의 수를 홀수로 입력해주세요: ";
	cin >> n;
	while (n % 2 == 0) {
		cout << "입력한 수가 홀수가 아닙니다. 홀수로 입력해주세요: ";
		cin >> n;
	}
	//2차원 벡터 배열 생성
	vector<vector<int>> magicSquare(n, vector<int>(n)); // 초기화

	//1은 첫 행의 가운데에 위치한다.
	int x = n / 2; //(열의 가운데)
	int y = 0; //첫 번째 행
	magicSquare[y][x] = 1;

	for (int i = 2; i <= n * n; i++) { // i=2 부터 증가

		// 오른쪽 대각선 위로 이동
		x = x + 1;
		y = y - 1;

		if (y < 0 && x >= n) {//첫번째 행의 마지막 열에서는 우상단으로 이동하는 것이 아니라 바로 아래칸으로 이동
			y = y + 2;
			x = x - 1;
		}

		if (y < 0) { // 첫번째 행에서 우상단으로 이동할 때는 마지막 행의 다음 열로 이동
			y = n - 1; //마지막 행으로 이동
		}

		if (x >= n) {// 마지막 열에서 우상단으로 이동할 때는 첫번째 열의 이전 행으로 이동
			x = 0; // 첫번째 열로 이동
		}

		if (magicSquare[y][x] != 0) { // 우상단으로 이동하는 도중 이미 칸이 채워져 있으면 바로 아래 칸으로 이동
			y = y + 2;
			x = x - 1;
		}

		magicSquare[y][x] = i; // 값이 비어있다면 i 저장
	}

	// 마방진 출력
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << magicSquare[i][j] << "  ";
		}
		cout << endl;
	}
	return 0;
}

개선사항


함수 분리

모든 코드를 main()함수에 작성하는 것은 코드의 가독성과 유지보수성이 떨어진다.

이전 문제와 마찬가지로!!
가독성과 유지보수성을 높이기 위해 각 기능에 따라 함수를 분리하자.


수정한 코드

#include <iostream>
#include <vector>

using namespace std;

// 입력값이 홀수인지 확인하는 함수
bool isOdd(int n) { return (n % 2 == 1); }

// 마방진 출력 함수
void printMagicSquare(vector<vector<int>> magicSquare) {
  int n = magicSquare.size();

  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      cout << magicSquare[i][j] << " ";
    }
    cout << endl;
  }
}

// 마방진 생성 함수
void generateMagicSquare(vector<vector<int>>& magicSquare, int n) {
  int x = n / 2;  // 열의 가운데
  int y = 0;      // 첫 번째 행
  magicSquare[y][x] = 1;

  for (int i = 2; i <= n * n; i++) {  // i=2 부터 증가
    // 오른쪽 대각선 위로 이동
    x = x + 1;
    y = y - 1;

    // 첫번째 행의 마지막 열에서는 우상단으로 이동하는 것이 아니라 바로
    // 아래칸으로 이동
    if (y < 0 && x >= n) {
      y = y + 2;
      x = x - 1;
    }

    // 첫번째 행에서 우상단으로 이동할 때는 마지막 행의 다음 열로 이동
    if (y < 0) {
      y = n - 1;  // 마지막 행으로 이동
    }

    // 마지막 열에서 우상단으로 이동할 때는 첫번째 열의 이전 행으로 이동
    if (x >= n) {
      x = 0;  // 첫번째 열로 이동
    }

    // 우상단으로 이동하는 도중 이미 칸이 채워져 있으면 바로 아래 칸으로 이동
    if (magicSquare[y][x] != 0) {
      y = y + 2;
      x = x - 1;
    }

    magicSquare[y][x] = i;  // 값이 비어있다면 i 저장
  }
}

int main() {
  int n;

  // 사용자로부터 마방진 크기 입력 받기
  cout << "만들고자 하는 마방진의 행 또는 열의 수를 홀수로 입력해주세요: ";
  cin >> n;

  // 입력값이 홀수인지 확인
  while (!isOdd(n)) {
    cout << "입력한 수가 홀수가 아닙니다. 홀수로 입력해주세요: ";
    cin >> n;
  }

  // 초기화
  vector<vector<int>> magicSquare(n, vector<int>(n));

  // 마방진 생성
  generateMagicSquare(magicSquare, n);

  // 마방진 출력
  cout << "마방진: " << endl;
  printMagicSquare(magicSquare);

  return 0;
}

주요 기술


1. 벡터 (Vector)

벡터는 C++ 표준 라이브러리의 일부로, 동적 배열을 구현하는 데 사용된다.
벡터는 배열과 비슷하지만, 크기를 변경할 수 있으며,
벡터의 크기가 변경될 때 메모리를 재할당한다.

내가 작성한 코드에선 2차원 벡터를 사용하여 마방진을 구현하였다.

vector<vector<int>> magicSquare(n, vector<int>(n));

2. 함수

함수는 프로그램의 논리를 구성하는 데 사용된다.

내가 작성한 코드에서 사용된 함수

isOdd: 입력값이 홀수인지 확인하는 함수
printMagicSquare: 주어진 2차원 벡터를 출력하는 함수
generateMagicSquare: 주어진 2차원 벡터에 마방진을 생성하는 함수


3. while 루프

while 루프는 조건이 참인 동안 반복하여 코드 블록을 실행

내가 작성한 코드에선 입력값이 홀수인지 확인하기 위한 while루프가 사용되었다.

while (!isOdd(n)) {
    cout << "입력한 수가 홀수가 아닙니다. 홀수로 입력해주세요: ";
    cin >> n;
}

4. 조건문

조건문은 주어진 조건이 참이면 코드 블록을 실행하고, 거짓이면 실행하지 않는다.

내가 작성한 코드에선 조건문을 사용하여 마방진의 다음 위치를 계산하였다.

if (y < 0 && x >= n) {
  y = y + 2;
  x = x - 1;
}

if (y < 0) {
  y = n - 1;
}

if (x >= n) {
  x = 0;
}

if (magicSquare[y][x] != 0) {
  y = y + 2;
  x = x - 1;
}

5. 반복문

반복문은 동일한 코드 블록을 여러 번 실행하는 데 사용

내가 작성한 코드에선 for 반복문을 사용하여 마방진을 생성하였다.

for (int i = 2; i <= n * n; i++) {
  // 마방진 생성 코드
}

6. 입출력

입출력은 프로그램에서 데이터를 입력하고 출력하는 데 사용된다.

cin을 사용하여 사용자로부터 입력을 받고, cout을 사용하여 출력

cout << "만들고자 하는 마방진의 행 또는 열의 수를 홀수로 입력해주세요: ";
cin >> n;

cout << "마방진: " << endl;
printMagicSquare(magicSquare);



마무리

내가 수정한 코드는 함수 idOdd를 사용하여 사용자가 홀수를 입력할 때까지 루프를 반복하는데, 사용자가 잘못된 값을 입력한 경우에 루프를 빠져나오기 전에 또 다른 잘못된 값을 입력할 수 있다.

이를 위해 입력 예외 처리를 좀 더 업격하게 수행하는 방법이 있을 것이지만.. 오늘은 여기까지만..!

우선 마방진이라는 규칙에 대해서 이해하는데에 시간을 꽤나 할애했다..

알려주신 규칙 외에 n의 배수의 경우에 오른쪽 대각선 위가 아닌 바로 아래로 향하게 하는 규칙이 있다는 것도 알 수 있었다.
다른 분이 작성하신 코드 보여주셨을 때

또 다른 문제점이야 자각하고 있지만, 나름.. 깔끔하게 작성했다고 생각한다..!

끄읕!

profile
스마트팩토리 개발자가 되기 위한 □□ !!

0개의 댓글