코스 8: Seven 2D Arrays - 2D 배열과 그리드
코스 개요
이 코스에서 학생들은 2차원 배열(2D Array)을 배웁니다. 2D 배열은 행과 열로 이루어진 격자 구조로, 게임 맵, 인벤토리 칸, 스프레드시트 등 격자 형태의 데이터를 표현할 때 사용됩니다. 이 개념을 마스터하면 마인크래프트 같은 블록 기반 게임, 체스, 스도쿠 등을 만들 수 있습니다.
예상 소요 시간: 12~24시간
소요 시간은 학생의 학년, 사전 경험, 학습 속도에 따라 크게 달라집니다. 또한 기본 개념만 익히고 넘어가는 경우와 추가 실습 문제나 창의적 프로젝트를 더 진행하는 경우에 따라서도 차이가 납니다. 위 시간은 평균적인 범위이며, 자녀의 페이스에 맞추어 유연하게 진행하시기 바랍니다.
어떤 능력을 키우게 되나요?
테이블 형태의 데이터(Tabular Data)를 다루는 능력을 훈련합니다. 엑셀 시트, 데이터베이스 테이블, CSV 파일 - 세상 데이터의 80%는 행과 열로 이루어진 2차원 구조입니다. 이 구조를 자유자재로 다루는 것이 데이터 분석의 핵심입니다.
어떤 원리를 배우나요?
- (테이블 데이터) 2D 배열로 행×열 구조를 만들면서, 엑셀처럼 데이터를 표로 정리하고 특정 셀에 접근하는 법을 배웁니다.
data[행][열]은 엑셀의 셀 주소와 같은 개념입니다. - (전체 데이터 처리) 중첩 반복문으로 모든 셀을 순회하면서, 테이블 전체에 연산을 적용하는 법을 배웁니다. "모든 행의 합계 구하기", "조건에 맞는 셀 찾기" 등 데이터 분석의 기본 작업입니다.
AI 시대 사고력: 컴퓨팅 (문제해결) | 데이터 기반 | 확률적 사고력
컴퓨팅 사고력 (Computational Thinking)
| 스킬 | 설명 | 활동 예시 |
|---|---|---|
| 🔲 격자 사고 | 행×열 구조로 데이터 조직 | 게임 맵을 2D 배열로 표현 |
| 📍 좌표 접근 | (행, 열)로 위치 지정 | grid[2][3] → 3행 4열 |
| ↔️ 값 교환 | 두 위치의 값 스왑 | 인벤토리 아이템 이동 |
| 🔄 전체 순회 | 모든 칸 방문하여 처리 | 맵 전체 렌더링 |
수학적 연결고리
| 수학 개념 | 프로그래밍 적용 | 학습 효과 |
|---|---|---|
| 행렬 | grid[i][j] |
행렬의 원소 표기 a_ij |
| 좌표 평면 | (x, y) → (col, row) |
2차원 좌표계 |
| 곱셈 원리 | 3행 × 4열 = 12칸 | 총 원소 개수 계산 |
| 인덱스 변환 | 1D ↔ 2D 변환 | i = row * cols + col |
2D 배열 = 행렬 (Matrix)
수학 행렬: 프로그래밍 2D 배열:
| 1 2 3 | grid = [
| 4 5 6 | [1, 2, 3],
| 7 8 9 | [4, 5, 6],
[7, 8, 9]
a₂₃ = 6 ]
grid[1][2] = 6
인덱스 계산
| 표현 | 의미 | 예시 (3×4 배열) |
|---|---|---|
grid[0][0] |
첫 번째 행, 첫 번째 열 | 좌상단 |
grid[2][3] |
세 번째 행, 네 번째 열 | 우하단 |
grid[row][col] |
일반적 접근 | 수학의 a_ij와 동일 |
2D 배열 순회 과정
flowchart LR
A[row = 0] --> B[col 0→n]
B --> C[row = 1]
C --> D[col 0→n]
D --> E[...]
E --> F[완료]
좌표 변환 공식
2D → 1D 변환 (펼치기):
index = row × 열개수 + col
예: 3×4 배열에서 (1, 2) 위치
index = 1 × 4 + 2 = 6
1D → 2D 변환 (접기):
row = index // 열개수
col = index % 열개수
예: index=6, 열개수=4
row = 6 // 4 = 1
col = 6 % 4 = 2 → (1, 2)
실생활 2D 구조
| 예시 | 행 | 열 | 접근 방법 |
|---|---|---|---|
| 영화관 좌석 | A~J열 | 1~20번 | seat[row][col] |
| 엑셀 시트 | 1, 2, 3... | A, B, C... | cell[row][col] |
| 체스판 | 1~8 | a~h | board[rank][file] |
| 픽셀 이미지 | 높이 | 너비 | pixel[y][x] |
💻 코드 예시 & 시각화
예시 1: 2D 배열 생성과 접근
# 3x4 2D 배열 생성
grid = [
[1, 2, 3, 4], # row 0
[5, 6, 7, 8], # row 1
[9, 10, 11, 12] # row 2
]
# 특정 위치 접근
print(grid[0][0]) # 1 (0행 0열)
print(grid[1][2]) # 7 (1행 2열)
print(grid[2][3]) # 12 (2행 3열)
# 값 변경
grid[1][1] = 99
print(grid[1][1]) # 99
2D 배열 시각화:
col 0 col 1 col 2 col 3
┌───────┬───────┬───────┬───────┐
row 0 │ 1 │ 2 │ 3 │ 4 │
├───────┼───────┼───────┼───────┤
row 1 │ 5 │ 99 │ 7 │ 8 │
├───────┼───────┼───────┼───────┤
row 2 │ 9 │ 10 │ 11 │ 12 │
└───────┴───────┴───────┴───────┘
grid[1][2] = grid[row][col] = 7
인덱스 계산:
grid[row][col] → 2D 배열의 특정 위치
예시 2: 중첩 반복문으로 전체 순회
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# 모든 요소 출력
for row in range(3):
for col in range(3):
print(f"grid[{row}][{col}] = {grid[row][col]}")
실행 순서:
row=0: col=0 → grid[0][0]=1
col=1 → grid[0][1]=2
col=2 → grid[0][2]=3
row=1: col=0 → grid[1][0]=4
col=1 → grid[1][1]=5
col=2 → grid[1][2]=6
row=2: col=0 → grid[2][0]=7
col=1 → grid[2][1]=8
col=2 → grid[2][2]=9
순회 순서 (화살표):
┌───┬───┬───┐
│ 1 → 2 → 3 │ ─┐
├───┼───┼───┤ │
│ 4 → 5 → 6 │ ←┘─┐
├───┼───┼───┤ │
│ 7 → 8 → 9 │ ←──┘
└───┴───┴───┘
예시 3: 마인크래프트 스타일 맵
from ursina import *
app = Ursina()
# 맵 데이터 (0=공기, 1=흙, 2=돌, 3=물)
world = [
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 1, 1],
[2, 2, 1, 1, 1, 1, 2, 2],
[2, 2, 2, 3, 3, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2]
]
colors = {
0: None, # 공기 (투명)
1: color.brown, # 흙
2: color.gray, # 돌
3: color.blue # 물
}
# 2D 배열 → 3D 월드
for row in range(len(world)):
for col in range(len(world[0])):
block_type = world[row][col]
if block_type != 0: # 공기가 아니면
Entity(
model='cube',
color=colors[block_type],
position=(col, -row, 0)
)
EditorCamera()
app.run()
맵 데이터 → 시각화:
2D 배열: 3D 월드:
[0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0] ██ ██
[1,1,0,0,0,0,1,1] → ██████████████████
[2,2,1,1,1,1,2,2] ████████████████████
[2,2,2,3,3,2,2,2] ████████████████████
[2,2,2,2,2,2,2,2] ████████████████████
██ = 흙 (brown) ▓▓ = 돌 (gray) ░░ = 물 (blue)
예시 4: 인벤토리 그리드
# 4x5 인벤토리 (None = 빈 칸)
inventory = [
["검", "방패", None, None, None],
["물약", "물약", "물약", None, None],
[None, None, None, None, None],
[None, None, None, None, "열쇠"]
]
# 특정 칸 확인
def check_slot(row, col):
item = inventory[row][col]
if item:
print(f"[{row}][{col}]: {item}")
else:
print(f"[{row}][{col}]: 빈 칸")
check_slot(0, 0) # [0][0]: 검
check_slot(2, 2) # [2][2]: 빈 칸
check_slot(3, 4) # [3][4]: 열쇠
# 아이템 이동 (스왑)
def move_item(from_pos, to_pos):
r1, c1 = from_pos
r2, c2 = to_pos
# 두 위치의 값 교환
inventory[r1][c1], inventory[r2][c2] = \
inventory[r2][c2], inventory[r1][c1]
move_item((0, 0), (2, 2)) # 검을 (2,2)로 이동
인벤토리 시각화:
col 0 col 1 col 2 col 3 col 4
┌───────┬───────┬───────┬───────┬───────┐
row 0│ ⚔️ │ 🛡️ │ │ │ │
├───────┼───────┼───────┼───────┼───────┤
row 1│ 🧪 │ 🧪 │ 🧪 │ │ │
├───────┼───────┼───────┼───────┼───────┤
row 2│ │ │ │ │ │
├───────┼───────┼───────┼───────┼───────┤
row 3│ │ │ │ │ 🔑 │
└───────┴───────┴───────┴───────┴───────┘
아이템 이동 후:
┌───────┬───────┬───────┬───────┬───────┐
row 0│ │ 🛡️ │ │ │ │
├───────┼───────┼───────┼───────┼───────┤
row 2│ │ │ ⚔️ │ │ │
└───────┴───────┴───────┴───────┴───────┘
예시 5: 지형 생성 (높이 맵)
from ursina import *
import random
app = Ursina()
# 높이 맵 생성 (랜덤)
size = 10
height_map = []
for row in range(size):
height_row = []
for col in range(size):
# 간단한 높이 계산 (중앙이 높음)
center_dist = abs(row - size//2) + abs(col - size//2)
height = max(0, 5 - center_dist + random.randint(-1, 1))
height_row.append(height)
height_map.append(height_row)
# 높이 맵 → 3D 지형
for row in range(size):
for col in range(size):
height = height_map[row][col]
for y in range(height):
Entity(
model='cube',
color=color.green if y == height-1 else color.brown,
position=(col, y, row)
)
EditorCamera()
app.run()
높이 맵 원리:
높이 맵 (숫자 = 블록 높이):
┌───┬───┬───┬───┬───┐
│ 1 │ 2 │ 2 │ 2 │ 1 │
├───┼───┼───┼───┼───┤
│ 2 │ 3 │ 4 │ 3 │ 2 │
├───┼───┼───┼───┼───┤
│ 2 │ 4 │ 5 │ 4 │ 2 │ ← 중앙이 가장 높음
├───┼───┼───┼───┼───┤
│ 2 │ 3 │ 4 │ 3 │ 2 │
├───┼───┼───┼───┼───┤
│ 1 │ 2 │ 2 │ 2 │ 1 │
└───┴───┴───┴───┴───┘
3D 시각화 (측면):
██
████████
████████████
████████████████
████████████████████
2D 배열이란?
개념 설명
2D 배열은 리스트 안에 리스트가 있는 구조입니다:
| 실생활 예시 | 프로그래밍 활용 |
|---|---|
| 체스판 (8×8) | 말의 위치 저장 |
| 엑셀 시트 | 데이터 테이블 |
| 영화관 좌석 | 예약 상태 관리 |
| 픽셀 이미지 | 색상 값 저장 |
프로젝트 1: Digging Grid - 2D 배열 접근과 수정
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 2D 배열의 특정 위치에 접근하기 |
| 핵심 개념 | 인덱싱, 행/열 개념 |
grid[row][col]로 특정 위치의 값에 접근합니다. grid[0][0]은 첫 번째 행의 첫 번째 열입니다. 학생들은 행(row)과 열(column) 개념을 확실히 이해합니다. 이것은 수학의 행렬, 좌표 평면과 직접 연결됩니다. 게임에서 플레이어가 서 있는 칸의 타입을 확인하거나, 그 칸을 수정할 때 이 접근 방식을 사용합니다.
값 수정하기
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 격자의 특정 칸 변경하기 |
| 핵심 개념 | 동적 수정, 상태 변화 |
grid[2][3] = 5로 특정 위치의 값을 변경할 수 있습니다. 게임에서 블록을 캐면 grid[y][x] = 0(빈 공간)으로 바꿉니다. 학생들은 데이터가 실시간으로 변할 수 있다는 것을 체험합니다. 이 변경이 화면에 즉시 반영되어 블록이 사라지는 것을 봅니다. 데이터(숫자 배열)와 시각적 표현(3D 블록)의 연결을 이해합니다.
프로젝트 2: Inventory Grid - 인벤토리 시스템
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 게임 인벤토리 구현하기 |
| 핵심 개념 | 데이터 관리, UI 연동 |
인벤토리는 2D 그리드 형태의 아이템 저장소입니다. inventory[row][col]로 각 칸에 어떤 아이템이 있는지 저장합니다. 학생들은 데이터 구조와 사용자 인터페이스(UI)를 연결하는 방법을 배웁니다. 아이템을 집고, 놓고, 이동하는 상호작용을 구현합니다. 이것은 RPG, 서바이벌 게임 등 대부분의 게임에 있는 핵심 시스템입니다.
아이템 이동
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 격자 안에서 데이터 옮기기 |
| 핵심 개념 | 스왑, 드래그 앤 드롭 |
아이템을 A 칸에서 B 칸으로 옮기려면 양쪽 값을 교환(swap)합니다. 빈 칸으로 옮기는 것과 다른 아이템과 교환하는 것은 로직이 다릅니다. 학생들은 사용자 행동을 데이터 조작으로 번역하는 방법을 배웁니다. 경계 조건(배열 범위를 벗어나지 않도록)을 체크하는 습관도 기릅니다. 이것은 방어적 프로그래밍의 중요한 실습입니다.
프로젝트 3: Minecraft Terrain - 지형 생성
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 절차적 지형 생성 |
| 핵심 개념 | 알고리즘, 노이즈, 절차적 생성 |
마인크래프트 스타일의 블록 지형을 자동으로 생성합니다. 2D 배열의 각 위치에 블록 타입(돌, 흙, 공기)을 저장합니다. 학생들은 알고리즘으로 콘텐츠를 생성하는 절차적 생성 개념을 배웁니다. 높이 맵, 노이즈 함수 등을 사용해 자연스러운 지형을 만듭니다. 같은 알고리즘이라도 시드(seed) 값에 따라 다른 세계가 생성됩니다.
중첩 반복문과 2D 배열
| 항목 | 내용 |
|---|---|
| 무엇을 배우나요? | 격자 전체 순회하기 |
| 핵심 개념 | 중첩 루프, 순회, 일괄 처리 |
이 패턴으로 격자의 모든 칸을 방문합니다. 바깥 루프는 행을, 안쪽 루프는 열을 담당합니다. 학생들은 2차원 구조를 1차원 순서로 펼치는 방법을 이해합니다. 이것은 이미지 처리, 게임 맵 렌더링, 데이터 분석 등에서 가장 많이 사용되는 패턴입니다. 시간 복잡도 개념의 첫 접촉이기도 합니다 - O(n×m).
이 코스를 마치면...
학습 성과
학생들은 다음 능력을 갖추게 됩니다:
- 2D 배열을 생성하고 접근할 수 있음
- 중첩 반복문으로 격자 전체를 처리할 수 있음
- 게임 맵과 인벤토리를 데이터로 표현할 수 있음
- 절차적 지형 생성의 기초를 이해함
- 행렬, 이미지, 테이블 등 격자 형태 데이터를 다룰 수 있음
- 종합 프로젝트를 진행할 준비가 됨