Company
교육 철학

LV04 Direct기법, 2중 포인터, 2차원 배열 패턴찾기

C++ 방향 배열, 포인터, 구조체 활용

방향을 표현하기 위한 코딩 방법 (Direct 기법)

방향 배열의 활용

방향 배열(Direction Array)은 게임 개발과 알고리즘에서 인접한 칸을 탐색할 때 사용하는 핵심 기법입니다.
왜 방향 배열을 사용할까?
만약 방향 배열 없이 상하좌우를 체크하려면 다음과 같이 코드를 작성해야 합니다:
// 방향 배열 없이 작성한 코드 (비효율적) if (y-1 >= 0) sum += arr[y-1][x]; // 상 if (y+1 < 3) sum += arr[y+1][x]; // 하 if (x-1 >= 0) sum += arr[y][x-1]; // 좌 if (x+1 < 3) s um += arr[y][x+1]; // 우
C++
복사
이 방식의 문제점:
코드가 길고 반복적입니다
8방향으로 확장하면 코드가 8배로 늘어납니다
방향을 추가/수정할 때 여러 곳을 고쳐야 합니다
유지보수가 어렵습니다
방향 배열을 사용하면:
// 방향 배열을 사용한 코드 (효율적) int direct[4][2] = { {-1,0}, {1,0}, {0,-1}, {0,1} }; for (int i = 0; i < 4; i++) { int newY = y + direct[i][0]; int newX = x + direct[i][1]; if (newY >= 0 && newY < 3 && newX >= 0 && newX < 3) { sum += arr[newY][newX]; } }
C++
복사
이 방식의 장점:
반복문으로 간결하게 처리 가능
4방향 → 8방향 확장이 쉽습니다 (배열만 수정)
코드 재사용성이 높습니다
방향을 데이터로 관리할 수 있습니다
실제 게임에서의 활용 사례:
스타듀밸리: 낚시할 때 주변 8칸 탐색, 호미로 땅 팔 때 앞 3칸 탐색
젤다의 전설: 3D 게임이지만 내부적으로는 2D 그리드 기반 탐색 (NavMesh)
포켓몬스터: 플레이어 이동, NPC 시야 범위, 풀숲 인카운터 체크
체스/장기: 말의 이동 가능한 위치 계산
지뢰찾기: 주변 8칸의 지뢰 개수 세기

Direct 방향 배열 구현

Direct 기법이란?
Direct(방향) 기법은 좌표의 변화량을 미리 배열에 저장해두고, 반복문으로 인접 칸을 탐색하는 방법입니다.
핵심 개념:
기준점: 현재 위치 (y, x)
방향 벡터: 각 방향으로의 이동량 (dy, dx)
새 좌표: 기준점 + 방향 벡터
#include <iostream> using namespace std; int main() { int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 기준점을 (0,0) 으로 뒀을 때 좌표값의 배열 int direct[4][2] = { -1, 0, // 상 1, 0, // 하 0, -1, // 좌 0, 1 // 우 }; int y = 1; int x = 1; // 입력받을 경우 // int x, y; // cin >> y >> x; int sum = 0; // 4X2 배열 direct 에서 for (size_t i = 0; i < 4; i++) { int newY = y + direct[i][0]; int newX = x + direct[i][1]; // ex) newX = 기준의 좌표값에 direct 배열의 x 좌표값을 더한다. // ex) newY = 1 + direct[0][0] (= 1) => 0 // ex) newX = 1 + direct[0][1] (=0) -> 1 // ex) newY, newX = 0, 1 // ex) arr[0][1] = 2 if (newX >= 0 && newX <= 2 && newY >= 0 && newY <= 2) { sum += arr[newY][newX]; } } cout << sum << endl; return 0; }
C++
복사
동작 원리:
1.
기준점 설정: (1, 1) 위치에서 시작
2.
방향 배열: 상(-1,0), 하(1,0), 좌(0,-1), 우(0,1)
3.
좌표 계산: 기준점 + 방향 벡터 = 새로운 좌표
4.
경계 검사: 배열 범위를 벗어나지 않는지 확인
5.
값 누적: 유효한 좌표의 값들을 합산
실행 결과: 기준점 (1,1)의 상하좌우 값들의 합 = 2 + 8 + 4 + 6 = 20

8방향 탐색 확장

4방향(상하좌우)에서 8방향(대각선 포함)으로 확장할 수 있습니다. 이는 체스의 킹, 지뢰찾기, RPG의 범위 공격 등에 활용됩니다.
int direct8[8][2] = { -1, -1, // 좌상 -1, 0, // 상 -1, 1, // 우상 0, -1, // 좌 0, 1, // 우 1, -1, // 좌하 1, 0, // 하 1, 1 // 우하 };
C++
복사

2중 포인터 변수

포인터의 포인터 개념

2중 포인터는 포인터 변수의 주소를 저장하는 포인터입니다. 메모리 구조를 이해하는 것이 핵심입니다.
왜 2중 포인터가 필요할까?
1.
함수에서 포인터 자체를 변경하고 싶을 때
2.
2차원 배열을 동적 할당할 때
3.
문자열 배열(char)을 다룰 때
4.
연결 리스트, 트리 같은 자료구조에서 노드의 포인터를 수정할 때
1중 포인터 vs 2중 포인터 비교:
// 1중 포인터: 값을 변경할 수 있음 void changeValue(int* p) { *p = 200; // OK: 원본 값 변경 가능 } // 1중 포인터: 포인터 자체는 변경 불가 void changePointer(int* p, int* newTarget) { p = newTarget; // 실패: 복사본만 변경됨 } // 2중 포인터: 포인터 자체를 변경할 수 있음 void changePointer(int** pp, int* newTarget) { *pp = newTarget; // OK: 원본 포인터 변경 가능 }
C++
복사

메모리 구조 시각화

메모리 주소 값 변수명 0x12 100 num (변수) 0x25 0x12 ptr (포인터) 0x61 0x25 pptr (포인터의 포인터)
Plain Text
복사

2중 포인터 기본 사용법

메모리 구조를 단계별로 이해하기:
#include <iostream> using namespace std; // 포인터 변수 = 주소값(주소 타입)을 저장하는 변수 타입 // int* P = &a; (a의 주소값을 포인터 변수의 값으로 가진다) // int 변수 = 정수형 숫자를 저장하는 변수 타입 // char 변수 = 문자를 글자를 저장하는 변수 타입 // 2중 포인터 변수 // (int a = 100) == (int* P = &a) == (int** PP = &P) == (&P = 0X17) int main() { int a = 100; int* p = &a; int** pp = &p; *(*pp) = 200; // 결과 a의 값이 변한다. return 0; }
C++
복사
2중 포인터 사용 과정:
1.
int a = 100: 정수 변수 a에 100 저장
2.
int* p = &a: 포인터 p가 a의 주소 저장
3.
int** pp = &p: 포인터의 포인터 pp가 p의 주소 저장
4.
(*pp) = 200: pp를 통해 a의 값을 200으로 변경
접근 과정:
pp: p의 주소를 가리킴 (0x25)
*pp: p가 저장한 값, 즉 a의 주소 (0x12)
**pp: a가 저장한 값 (100)
**pp = 200: a의 값을 200으로 변경

2중 포인터의 실용적 활용

실전 예제: 함수에서 포인터 변경하기
#include <iostream> using namespace std; void ChangeValue(int** ptr) { **ptr = 500; // 원본 값 변경 } void ChangePointer(int** ptr, int* newTarget) { *ptr = newTarget; // 포인터가 가리키는 대상 변경 } int main() { int a = 100; int b = 300; int* p = &a; cout << "초기값: *p = " << *p << endl; // 100 ChangeValue(&p); cout << "값 변경 후: *p = " << *p << endl; // 500 ChangePointer(&p, &b); cout << "포인터 변경 후: *p = " << *p << endl; // 300 return 0; }
C++
복사

구조체, 클래스를 이용한 배열

구조체를 이용한 데이터 관리

구조체 배열은 관련된 데이터를 묶어서 관리할 때 유용합니다.
언제 사용할까?
게임에서 여러 플레이어의 정보 관리
학생 성적 관리 시스템
좌표와 속성을 함께 저장 (예: 위치 + 체력)
더 실용적인 예제:
struct Player { int x, y; // 위치 int hp; // 체력 int attack; // 공격력 char name[20]; // 이름 }; Player players[4]; // 4명의 플레이어 // 첫 번째 플레이어 초기화 players[0].x = 5; players[0].y = 5; players[0].hp = 100; players[0].attack = 20; // 모든 플레이어 정보 출력 for (int i = 0; i < 4; i++) { cout << players[i].name << ": (" << players[i].x << ", " << players[i].y << ")\n"; }
C++
복사
#include <iostream> using namespace std; // 구조체, 클래스를 이용한 배열 struct ABC { public: // 생성자 (해당사항 없음) // 소멸자 (해당사항 없음) // 멤버 함수들 (해당사항 없음) // 멤버 변수들 int mA; int mB; }; int main() { ABC arr[3]; arr[0].mA = 100; arr[0].mB = 200; cin >> arr[0].mA >> arr[0].mB; cout << arr[0].mA << arr[0].mB; return 0; }
C++
복사

패턴찾기 → 2중 for문에서 패턴찾기

2차원 배열에서 패턴 매칭

2차원 배열에서 특정 패턴을 찾는 알고리즘입니다.
패턴 매칭이란?
큰 배열(map) 안에서 작은 배열(pattern)과 일치하는 부분을 찾는 것입니다.
활용 분야:
이미지 처리: 특정 모양 찾기
게임: 특정 배치 패턴 인식 (예: 3-match 퍼즐)
보안: 악성 코드 시그니처 탐지
DNA 분석: 특정 염기서열 찾기
시간 복잡도 분석:
map 크기: N × M
pattern 크기: P × Q
시간 복잡도: O((N-P+1) × (M-Q+1) × P × Q)
최악의 경우: O(N × M × P × Q)
최적화 방법:
KMP 알고리즘 응용 (1차원 문자열 매칭)
해싱 기법 사용
첫 번째 요소로 빠른 필터링
#include <iostream> using namespace std; // 패턴찾기 -> 2중 For문에서 패턴찾기 int map[5][5] = { 1, 3, 5, 1, 5, 3, 7, 9, 5, 8, 4, 5, 3, 9, 7, 2, 7, 6, 1, 9, 1, 6, 2, 3, 8 }; int pattern[2][2] = { 3, 5, 7, 9 }; int IsPattern(int dy, int dx) { for (size_t y = 0; y < 2; y++) { for (size_t x = 0; x < 2; x++) { if (map[dy + y][dx + x] != pattern[y][x]) { return 0; } } } return 1; } int main() { for (size_t y = 0; y < 4; y++) { for (size_t x = 0; x < 4; x++) { int result = IsPattern(y, x); if (result == 1) { cout << "존재" << endl; return 0; } } } cout << "노존재" << endl; return 0; }
C++
복사
패턴 매칭 과정 상세 설명:
1.
시작 위치 설정: (dy, dx)에서 패턴 검사 시작
map의 (0,0)부터 (3,3)까지 순회 (5x5 배열에서 2x2 패턴)
경계를 벗어나지 않도록 y < 4, x < 4까지만 검사
1.
패턴 크기만큼 반복: 2x2 패턴이면 4번 비교
pattern[0][0]과 map[dy+0][dx+0] 비교
pattern[0][1]과 map[dy+0][dx+1] 비교
pattern[1][0]과 map[dy+1][dx+0] 비교
pattern[1][1]과 map[dy+1][dx+1] 비교
1.
일치 여부 확인: 모든 위치의 값이 일치하는지 검사
하나라도 다르면 즉시 0 반환 (조기 종료)
모두 일치하면 1 반환
1.
결과 처리: 첫 번째 발견 시 즉시 종료
모든 위치를 찾고 싶다면 continue 사용
코드 개선 팁:
// 모든 패턴 위치 찾기 vector<pair<int,int>> found; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (IsPattern(y, x)) { found.push_back({y, x}); } } }
C++
복사

문자 패턴 찾기

#include <iostream> using namespace std; char map[3][4] = { {'A', 'B', 'G', 'K'}, {'T', 'T', 'A', 'B'}, {'A', 'C', 'C', 'D'} }; char pattern[2][2]; char IsPattern(char y, char x) { for (size_t y = 0; y < 2; y++) { for (size_t x = 0; x < 2; x++) { if (map[y][x] != pattern[y][x]) { return 0; } } } return 1; } char main() { for (size_t i = 0; i < 2; i++) { cin >> pattern[i][0]; cin >> pattern[i][1]; } for (size_t i = 0; i < 2; i++) { for (size_t j = 0; j < 3; j++) { int result = IsPattern(i, j); if (result == 1) { cout << "발견\n"; } else { cout << "미발견\n"; } } } return 0; }
C++
복사

실무에서의 활용

게임 개발에서의 방향 배열

RPG 게임에서의 활용:
enum Direction { UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3 }; class Player { public: Player(int y, int x) : mY(y), mX(x) {} void Move(Direction dir) { int newY = mY + mDirections[dir][0]; int newX = mX + mDirections[dir][1]; if (IsValidPosition(newY, newX)) { mY = newY; mX = newX; } } bool IsValidPosition(int y, int x) { return (y >= 0 && y < MAP_HEIGHT && x >= 0 && x < MAP_WIDTH); } private: static const int mDirections[4][2]; int mY, mX; static const int MAP_HEIGHT = 10; static const int MAP_WIDTH = 10; }; const int Player::mDirections[4][2] = { {-1, 0}, // UP { 1, 0}, // DOWN { 0, -1}, // LEFT { 0, 1} // RIGHT };
C++
복사

패턴 매칭의 실무 활용

이미지 처리에서의 템플릿 매칭:
특정 패턴의 객체 찾기
얼굴 인식, 문자 인식
게임에서 아이템 배치 패턴 인식
데이터 마이닝:
시계열 데이터에서 특정 패턴 찾기
로그 분석에서 이상 패턴 탐지
바이오인포매틱스에서 DNA 서열 분석

메모리 효율성 고려사항

2중 포인터 사용 시 주의점:
1.
메모리 누수 방지: 동적 할당 시 반드시 해제
// 2차원 배열 동적 할당 int** arr = new int*[rows]; for (int i = 0; i < rows; i++) { arr[i] = new int[cols]; } // 사용 후 반드시 해제 for (int i = 0; i < rows; i++) { delete[] arr[i]; // 각 행 해제 } delete[] arr; // 포인터 배열 해제
C++
복사
1.
NULL 포인터 체크: 포인터 사용 전 유효성 검사
int** pp = nullptr; if (pp != nullptr && *pp != nullptr) { cout << **pp << endl; }
C++
복사
1.
깊은 복사 vs 얕은 복사: 포인터 복사 시 주의
// 얕은 복사 (주소만 복사) int* p1 = new int(100); int* p2 = p1; // 같은 메모리를 가리킴 // 깊은 복사 (값을 복사) int* p1 = new int(100); int* p2 = new int(*p1); // 새로운 메모리에 값 복사
C++
복사

핵심 정리

Direct 기법의 핵심

방향을 데이터로 관리하면 코드가 간결하고 확장성이 높아집니다
4방향, 8방향, 체스 말 이동 등 다양하게 응용 가능
게임 개발, 알고리즘 문제 풀이의 필수 기법

2중 포인터의 핵심

포인터 자체를 변경하고 싶을 때 사용
2차원 배열 동적 할당, 문자열 배열에 필수
메모리 관리를 정확히 이해해야 함

패턴 매칭의 핵심

2중 반복문으로 모든 시작 위치 탐색
조기 종료로 효율성 향상
이미지 처리, 게임 로직의 기초 알고리즘
방향 배열과 패턴 매칭은 게임 개발, 이미지 처리, 데이터 분석 등 다양한 분야에서 핵심적으로 활용되는 기법입니다. 특히 2D 게임의 맵 탐색이나 이미지 인식 알고리즘에서 필수적인 도구로 사용됩니다.

“강의는 많은데, 왜 나는 아직도 코드를 못 짤까?”

혼자 공부하다 보면 누구나 이런 고민을 하게 됩니다.
강의는 다 들었지만 막상 손이 안 움직이고,
복습을 하려 해도 무엇을 다시 봐야 할지 모르겠고,
질문할 곳도 없고,
유튜브는 결국 정답을 따라 치는 것밖에 안 되는 것 같고.
문제는 ‘연습’이 빠졌기 때문입니다.
단순히 강의를 듣는 것만으로는 실력이 늘지 않습니다.
실제 문제를 풀고, 고민하고, 직접 구현해보는 시간이 반드시 필요합니다.

그래서, 얌얌코딩 코칭은 다릅니다.

그냥 가르치지 않습니다.
스스로 설계하고, 코딩할 수 있게 만듭니다.
얌얌코딩 코칭에서는 단순한 예제가 아닌,
스스로 문제를 분석하고 구현해야 하는 연습문제를 제공합니다.
이 연습문제들은 다음과 같은 역량을 키우기 위해 설계되어 있습니다:
문제를 스스로 쪼개고 설계하는 힘
다양한 조건을 만족시키는 실제 구현 능력
기능 단위가 아닌, 프로그램 단위로 사고하는 습관
마침내 자신의 힘으로 코드를 끝까지 작성하는 경험

지금 필요한 건 더 많은 강의가 아닙니다.

코드를 스스로 완성해 나가는 훈련,
그것이 지금 실력을 끌어올릴 가장 현실적인 방법입니다.
자세한 안내 보기: 프리미엄 코칭 안내 바로가기
또는 카카오톡 상담방: 얌얌코딩 상담방