📌 주제

사용자 입력에 따라 N x N 크기의 2차원 배열을 생성하고, 이를 달팽이 모양으로 숫자로 채우는 C++ 프로그램 구현

  • 달팽이 배열이란, 배열의 가장 좌측 상단 (0,0)부터 시작하여 오른쪽 → 아래 → 왼쪽 → 위 순으로 회전하며 정수를 1부터 N²까지 순차적으로 채우는 형태입니다.
  • 이 문제는 단순한 배열 채우기를 넘어, 시뮬레이션 문제에서 필수적인 논리 구현인 방향 전환, 좌표 이동, 배열 경계 처리, 중복 방문 방지, 출력 포맷 제어 등을 포괄합니다.

📚 개념

이 문제를 제대로 구현하기 위해 반드시 익혀야 하는 개념들을 정리하면 다음과 같습니다:

  1. 2차원 배열

    • 배열[y][x] 형식으로 좌표를 행(y)과 열(x) 기준으로 탐색.
    • 2차원 반복문을 사용하여 요소에 접근하거나 출력함.
  2. 좌표 이동 제어

    • 현재 위치를 기준으로 다음 위치를 계산하기 위한 방향 벡터(dx, dy)를 사용.
    • 이동 후 위치가 유효한지 항상 확인해야 함.
  3. 시계방향 방향 제어

    • 방향은 총 4개: 오른쪽(RIGHT) → 아래(DOWN) → 왼쪽(LEFT) → 위(UP)
    • 이를 정수값으로 지정하거나 열거형(enum)으로 선언해 코드 가독성 향상.
  4. 배열 범위와 중복 체크

    • 배열의 경계를 벗어나는 이동 금지.
    • 이미 채워진 값이 있는 곳으로의 이동도 금지.
  5. 출력 정렬(iomanip)

    • 정렬된 포맷으로 배열을 보기 좋게 출력하기 위해 setw, setfill 사용.

🧾 용어 정리

용어설명
2차원 배열행과 열로 구성된 배열로, arr[y][x] 형태로 접근
열거형(enum)방향을 이름으로 명확히 정의하여 가독성과 유지보수성을 향상시키는 사용자 정의 자료형
시계방향RIGHT → DOWN → LEFT → UP 순서로 반복되는 방향 흐름
유효성 검사현재 좌표가 배열 범위 내에 있고 아직 방문하지 않았는지 확인하는 과정
iomanipC++에서 출력 포맷을 정렬하는 기능을 제공하는 헤더 (setw, setfill 등 포함)

🔍 코드 분석

1. 전역 변수 및 상수

const int MAX = 100;
int board[MAX][MAX];
int N;
  • MAX: 배열의 최대 크기. 미리 넉넉하게 할당해 두어 동적 할당을 피함.
  • board: 숫자가 채워질 실제 2차원 배열.
  • N: 배열의 실제 크기, 사용자로부터 입력 받음.

2. 방향 정의 (열거형)

enum DIR {
    RIGHT = 0,
    DOWN = 1,
    LEFT = 2,
    UP = 3
};
  • 시계방향 순서를 열거형으로 정의하여 방향을 의미 있는 이름으로 표현.
  • RIGHT → DOWN → LEFT → UP 순환을 가능하게 하며, 정수로 처리 가능.

3. 유효성 검사 함수

bool CanGo(int y, int x) {
    if (y < 0 || y >= N) return false;     // 배열 위 또는 아래 경계 초과
    if (x < 0 || x >= N) return false;     // 배열 좌 또는 우 경계 초과
    if (board[y][x] != 0) return false;    // 이미 숫자가 채워진 칸
    return true;
}
  • 중복 방문 방지와 경계 처리를 동시에 수행.
  • 다음 위치로 이동해도 되는지를 판단하는 핵심 함수.

4. 배열 출력 함수

void PrintBoard() {
    for (int y = 0; y < N; y++) {
        for (int x = 0; x < N; x++) {
            std::cout << std::setfill('0') << std::setw(2) << board[y][x] << " ";
        }
        std::cout << std::endl;
    }
}
  • setw(2): 숫자 너비를 2칸으로 고정
  • setfill('0'): 빈칸을 0으로 채워 가독성 향상 (3 → 03)
  • 예시 출력 (N=3):
01 02 03
08 09 04
07 06 05

5. 달팽이 배열 생성 함수 (SetBoard)

(1) switch문 기반 버전

void SetBoard() {
    int dir = RIGHT;
    int num = 1;
    int y = 0, x = 0;

    while (true) {
        board[y][x] = num;

        if (num == N * N) break;

        int nextX = x, nextY = y;
        switch (dir) {
            case RIGHT: nextX = x + 1; break;
            case DOWN:  nextY = y + 1; break;
            case LEFT:  nextX = x - 1; break;
            case UP:    nextY = y - 1; break;
        }

        if (CanGo(nextY, nextX)) {
            x = nextX;
            y = nextY;
            num++;
        } else {
            switch (dir) {
                case RIGHT: dir = DOWN; break;
                case DOWN:  dir = LEFT; break;
                case LEFT:  dir = UP; break;
                case UP:    dir = RIGHT; break;
            }
        }
    }
}

(2) 최적화 버전 – dx, dy 배열 사용

void SetBoard() {
    int dir = RIGHT;
    int num = 1;
    int y = 0, x = 0;

    int dx[] = { 1, 0, -1, 0 }; // RIGHT, DOWN, LEFT, UP
    int dy[] = { 0, 1, 0, -1 };

    while (true) {
        board[y][x] = num;

        if (num == N * N) break;

        int nextY = y + dy[dir];
        int nextX = x + dx[dir];

        if (CanGo(nextY, nextX)) {
            y = nextY;
            x = nextX;
            num++;
        } else {
            dir = (dir + 1) % 4; // 방향 순환
        }
    }
}
  • 동일한 로직을 훨씬 간결하고 유연하게 구현.
  • dx, dy 배열을 통해 좌표 연산을 수식으로 표현함으로써, switch문 제거.
  • 방향 전환도 (dir + 1) % 4로 수학적으로 처리해 코드 최적화.

6. main 함수

int main() {
    std::cin >> N;
    SetBoard();
    PrintBoard();
    return 0;
}
  • 사용자로부터 N을 입력받아, 그 크기에 맞는 달팽이 배열을 구성하고 출력합니다.
  • 메인 함수가 전체 흐름을 직관적으로 보여줍니다.

✅ 최종 코드 통합본

아래는 최적화된 코드로 구성된 달팽이 배열 생성 프로그램의 전체 소스 코드입니다.

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

const int MAX = 100;
int board[MAX][MAX];  // 달팽이 배열 저장
int N;                // 배열 크기

// 유효한 이동인지 검사
bool CanGo(int y, int x) {
    if (y < 0 || y >= N) return false;
    if (x < 0 || x >= N) return false;
    if (board[y][x] != 0) return false;
    return true;
}

// 달팽이 배열 채우기
void SetBoard() {
    int dir = 0;           // 0: RIGHT, 1: DOWN, 2: LEFT, 3: UP
    int num = 1;           // 시작 숫자
    int y = 0, x = 0;      // 시작 위치

    int dx[] = { 1, 0, -1, 0 }; // x축 이동량
    int dy[] = { 0, 1, 0, -1 }; // y축 이동량

    while (true) {
        board[y][x] = num;

        if (num == N * N) break;

        int nextY = y + dy[dir];
        int nextX = x + dx[dir];

        if (CanGo(nextY, nextX)) {
            y = nextY;
            x = nextX;
            num++;
        } else {
            dir = (dir + 1) % 4; // 방향 회전
        }
    }
}

// 결과 출력
void PrintBoard() {
    for (int y = 0; y < N; y++) {
        for (int x = 0; x < N; x++) {
            cout << setfill('0') << setw(2) << board[y][x] << " ";
        }
        cout << endl;
    }
}

int main() {
    cin >> N;        // 사용자로부터 크기 입력
    SetBoard();      // 배열 채우기
    PrintBoard();    // 결과 출력
    return 0;
}

🎯 전체 실행 흐름 요약

1. 사용자로부터 배열 크기 N을 입력받음
2. board[N][N] 배열 생성 (초기값 0)
3. SetBoard() 함수 실행:
    - 시작 위치 (0,0)에 1을 채움
    - 현재 방향으로 다음 좌표 탐색
    - 갈 수 있으면 이동 및 숫자 증가
    - 못 가면 방향을 오른쪽으로 회전
    - N*N개의 숫자 모두 채워질 때까지 반복
4. PrintBoard() 함수 실행:
    - 이중 반복문으로 2차원 배열 출력
    - 숫자는 자릿수 맞춰 정렬해서 출력

📐 시각적 로직 흐름 설명

▶ 방향 배열의 순서

방향dxdy설명
RIGHT(0)+10오른쪽 이동
DOWN(1)0+1아래로 이동
LEFT(2)-10왼쪽 이동
UP(3)0-1위로 이동

▶ 예: N = 4일 때 달팽이 배열의 진행 경로

시작 위치: (0,0)

01 → 02 → 03 → 04
                 ↓
12 ← 13 ← 14   05
↑              ↓
11   16 ← 15   06
↑   ↑   ↑       ↓
10 ← 09 ← 08 ← 07
  • 오른쪽 끝 → 아래 → 왼쪽 → 위로 반복
  • 숫자를 채운 곳은 다시 접근하지 않음 (board[y][x] != 0)
  • 배열의 경계를 넘으면 방향 전환

🧾 출력 예시 및 설명

입력

4

출력

01 02 03 04
12 13 14 05
11 16 15 06
10 09 08 07

출력 형식 설명

  • 숫자는 setw(2), setfill('0')을 이용해 두 자리로 정렬
  • 줄 바꿈(endl)은 각 행(row)마다 수행

❓ 자주 묻는 질문 (Q&A)

Q1. 왜 board[y][x] 순으로 접근하나요?

  • C++에서는 2차원 배열이 행(y), 열(x) 순서로 선언되므로, board[y][x]가 올바른 접근 방식입니다.

Q2. 왜 dir = (dir + 1) % 4를 사용하나요?

  • 방향은 4가지(RIGHT, DOWN, LEFT, UP)이며, 0~3 사이의 값을 가지므로,
    • 3(UP)에서 +1 → 4 → %4 = 0 → 다시 RIGHT로 순환 가능하게 설계된 방식입니다.

Q3. CanGo() 함수는 꼭 필요할까요?

  • 네, 꼭 필요합니다. 이동하려는 좌표가 배열 범위를 넘는지, 또는 이미 숫자가 채워져 있는지를 검사하지 않으면 무한 루프 또는 배열 접근 오류가 발생합니다.

⭐ 핵심

항목요점
2차원 배열 순회board[y][x] 형태로 접근, 이중 반복문 사용
방향 제어dx[], dy[]를 통해 이동 방향 수식화
방향 전환(dir + 1) % 4로 간결하게 처리
유효성 검사CanGo() 함수로 경계와 중복 체크를 통합
출력 정렬setw, setfill을 사용해 가독성 향상

이 문제는 단순한 배열 채우기 이상의 시뮬레이션 알고리즘 설계 연습입니다. 이 구조를 잘 익혀두면, 로봇 시뮬레이션, 미로 탐색, 퍼즐 게임 등의 고급 문제에서도 같은 패턴을 재사용할 수 있습니다.


profile
李家네_공부방

0개의 댓글