이 글의 목적

타일 슬라이딩 퍼즐 AI 실험에 쓴 소스 코드 전체를 공개합니다. 파일을 펼칠 때만 코드를 불러옵니다.

사용한 모델

  • DQN: Stable-Baselines3. 관측은 4×4 타일 번호, 행동은 빈칸의 상하좌우 4가지, 보상은 타일마다 제자리까지 남은 맨해튼 거리를 더한 값의 음수입니다. 1편의 무한 반복은 이 보상에서 나왔습니다.
  • 모방 학습(BC): 사람이 직접 푼 기록과 C++ 교사(A*)가 만든 풀이를 DQN 정책에 먼저 학습
  • Planner·Executor: PyTorch CNN 두 개(합성곱 32→64 채널). Planner는 다음에 맞출 타일을, Executor는 그 타일을 옮길 한 수를 고릅니다. 정책이 틀린 국면을 교사 답으로 다시 라벨링하는 DAgger로 데이터를 보강했습니다.
  • 월드 모델: C++ 엔진으로 앞 수를 시뮬레이션하고, 판의 진행도(0~1)를 예측하는 ValueNet 점수로 수를 고릅니다.
  • VLM: Hugging Face의 Qwen2.5-VL-3B-Instruct. 퍼즐 판 이미지와 둘 수 있는 수 목록을 주고 다음 수를 JSON으로 받았습니다.

보조로 쓴 것

  • C++ 교사(PuzzleTeacher·Planner·Executor): 데모 생성과 채점 기준. 연구 모드에서는 에이전트가 낸 수를 덮어쓰지 않습니다.
  • agent_loop_guard: DQN·VLM이 같은 판을 되풀이하면 맨해튼 거리를 줄이는 수로 빠져나오게 하는 안전장치
  • 웹 게임의 AI 풀이: 학습 모델이 아니라 브라우저 안에서 도는 가중 A* 탐색(맨해튼 거리 + 선형 충돌)

다시 돌려 본 결과

모방 학습은 40번 반복해도 교사와 같은 수를 고른 비율이 71.1%에서 멈췄습니다.

모방 학습 정확도. 교사(A*) 풀이 71.1%, Executor 풀이 63.1%
모방 학습 정확도. 교사(A*) 풀이 71.1%, Executor 풀이 63.1%

80수 섞은 판을 같은 조건으로 다시 돌렸습니다. 학습한 모델은 한 판도 끝내지 못했고, 루프 규칙을 코드로 넣은 C++ Executor만 모두 풀었습니다.

80수 섞은 판을 끝까지 맞춘 비율. DQN·맨해튼·무작위 0/50, Planner·Executor 신경망 0/10, C++ Executor 50/50
80수 섞은 판을 끝까지 맞춘 비율. DQN·맨해튼·무작위 0/50, Planner·Executor 신경망 0/10, C++ Executor 50/50

Planner·Executor 신경망은 다음 타일 고르기에서 교사와 83%, 한 수 고르기에서 40% 일치했고 첫 줄도 끝까지 맞추지 못했습니다. 월드 모델은 10판을 모두 풀었지만 ValueNet을 끄고 돌려도 수순이 똑같았습니다. 판을 푼 것은 ValueNet이 아니라 안에서 도는 C++ Executor입니다.

Qwen2.5-VL-3B에게는 판 그림과 둘 수 있는 수를 주고 매 수 직접 물었습니다. 4수만 섞은 판도 풀지 못했습니다. 20판 모두 두 칸을 왕복하거나 2×2 네 칸을 끝없이 돌렸습니다. 루프를 돌릴 줄은 알지만 언제 멈춰야 하는지는 모릅니다.

Qwen2.5-VL-3B 반복 패턴. 4수 섞은 판 왕복 4·돌기 6, 10수 섞은 판 왕복 2·돌기 8, 완성 0
Qwen2.5-VL-3B 반복 패턴. 4수 섞은 판 왕복 4·돌기 6, 10수 섞은 판 왕복 2·돌기 8, 완성 0

폴더 구성

  • src: Qt6/C++ 퍼즐 엔진, Python용 C API, Planner·Executor·Teacher, Qt 화면과 TCP 학습 서버
  • 루트의 .py: Gymnasium 환경, 데모 생성, DQN·BC·Planner/Executor·월드 모델 학습, Qt 연결 클라이언트, 평가 시뮬레이션
  • web: Next.js 웹 퍼즐 화면

서버 배포 설정, 감시·자동화 스크립트, 학습 데이터와 모델 가중치, 퍼즐 그림 파일은 공개 범위에서 제외했습니다. 광고 같은 웹 운영 코드와 설정 파일, 디버그용 도구도 빼서 일부 import와 README의 scripts 경로는 공개하지 않은 파일을 가리킵니다.

전체 소스

73개 파일 · 19,290줄 — 폴더를 펼친 뒤 파일을 누르면 코드를 불러옵니다.

프로젝트 루트41개 파일
agent_loop_guard.pypython · 275줄 · 9KB

코드를 불러오는 중입니다…

CMakeLists.txttext · 64줄 · 2KB

코드를 불러오는 중입니다…

dqn_sim.pypython · 257줄 · 9KB

코드를 불러오는 중입니다…

engine_world_model.pypython · 256줄 · 8KB

코드를 불러오는 중입니다…

generate_executor_demos.pypython · 128줄 · 4KB

코드를 불러오는 중입니다…

generate_pe_recovery_demos.pypython · 199줄 · 6KB

코드를 불러오는 중입니다…

generate_planner_demos.pypython · 77줄 · 2KB

코드를 불러오는 중입니다…

generate_teacher_demos.pypython · 207줄 · 6KB

코드를 불러오는 중입니다…

generate_wm_labels.pypython · 101줄 · 3KB

코드를 불러오는 중입니다…

local_puzzle_env.pypython · 223줄 · 8KB

코드를 불러오는 중입니다…

pe_dagger_collect.pypython · 217줄 · 8KB

코드를 불러오는 중입니다…

pe_nets.pypython · 145줄 · 5KB

코드를 불러오는 중입니다…

pe_segment_sim.pypython · 159줄 · 5KB

코드를 불러오는 중입니다…

pe_sim.pypython · 243줄 · 8KB

코드를 불러오는 중입니다…

pe_targets.pypython · 71줄 · 2KB

코드를 불러오는 중입니다…

plan_agent.pypython · 310줄 · 11KB

코드를 불러오는 중입니다…

plan_obs.pypython · 18줄 · 661B

코드를 불러오는 중입니다…

plan_puzzle_env.pypython · 101줄 · 4KB

코드를 불러오는 중입니다…

plan_sim.pypython · 262줄 · 8KB

코드를 불러오는 중입니다…

planner_obs.pypython · 17줄 · 556B

코드를 불러오는 중입니다…

PROJECT_PURPOSE.mdmarkdown · 149줄 · 7KB

코드를 불러오는 중입니다…

puzzle_c_bindings.pypython · 193줄 · 7KB

코드를 불러오는 중입니다…

qt_dqn_sim.pypython · 293줄 · 10KB

코드를 불러오는 중입니다…

qt_pe_client.pypython · 738줄 · 23KB

코드를 불러오는 중입니다…

qt_rl_client.pypython · 198줄 · 7KB

코드를 불러오는 중입니다…

qt_vlm_client.pypython · 494줄 · 18KB

코드를 불러오는 중입니다…

qt_vlm_sim.pypython · 324줄 · 11KB

코드를 불러오는 중입니다…

qt_wm_client.pypython · 200줄 · 7KB

코드를 불러오는 중입니다…

README.mdmarkdown · 139줄 · 5KB

코드를 불러오는 중입니다…

requirements-vlm.txttext · 8줄 · 153B

코드를 불러오는 중입니다…

requirements.txttext · 4줄 · 40B

코드를 불러오는 중입니다…

segment_plan_ko.pypython · 42줄 · 2KB

코드를 불러오는 중입니다…

train_bc_from_demos.pypython · 145줄 · 5KB

코드를 불러오는 중입니다…

train_pe.pypython · 327줄 · 11KB

코드를 불러오는 중입니다…

train_plan_bc.pypython · 152줄 · 5KB

코드를 불러오는 중입니다…

train_puzzle_rl.pypython · 358줄 · 13KB

코드를 불러오는 중입니다…

train_world_model.pypython · 135줄 · 5KB

코드를 불러오는 중입니다…

wm_nets.pypython · 54줄 · 2KB

코드를 불러오는 중입니다…

world_model_agent.pypython · 183줄 · 7KB

코드를 불러오는 중입니다…

world_model_sim.pypython · 135줄 · 4KB

코드를 불러오는 중입니다…

world_obs.pypython · 38줄 · 1KB

코드를 불러오는 중입니다…

src/19개 파일
src/demo_sim.cppc++ · 540줄 · 18KB

코드를 불러오는 중입니다…

src/main_window.cppc++ · 2,089줄 · 66KB

코드를 불러오는 중입니다…

src/main_window.hc++ · 196줄 · 7KB

코드를 불러오는 중입니다…

src/main.cppc++ · 68줄 · 2KB

코드를 불러오는 중입니다…

src/puzzle_c_api.cppc++ · 400줄 · 12KB

코드를 불러오는 중입니다…

src/puzzle_engine.cppc++ · 546줄 · 15KB

코드를 불러오는 중입니다…

src/puzzle_engine.hc++ · 110줄 · 4KB

코드를 불러오는 중입니다…

src/puzzle_executor.cppc++ · 519줄 · 19KB

코드를 불러오는 중입니다…

src/puzzle_executor.hc++ · 53줄 · 2KB

코드를 불러오는 중입니다…

src/puzzle_plan_log.hc++ · 24줄 · 547B

코드를 불러오는 중입니다…

src/puzzle_planner.cppc++ · 4,414줄 · 152KB

코드를 불러오는 중입니다…

src/puzzle_planner.hc++ · 53줄 · 2KB

코드를 불러오는 중입니다…

src/puzzle_solve_waves.cppc++ · 110줄 · 3KB

코드를 불러오는 중입니다…

src/puzzle_solve_waves.hc++ · 33줄 · 1KB

코드를 불러오는 중입니다…

src/puzzle_teacher.cppc++ · 748줄 · 22KB

코드를 불러오는 중입니다…

src/puzzle_teacher.hc++ · 31줄 · 940B

코드를 불러오는 중입니다…

src/puzzle_tile_action.hc++ · 95줄 · 3KB

코드를 불러오는 중입니다…

src/puzzle_widget.cppc++ · 148줄 · 4KB

코드를 불러오는 중입니다…

src/puzzle_widget.hc++ · 47줄 · 1KB

코드를 불러오는 중입니다…

web/13개 파일
web/app/globals.csscss · 50줄 · 912B

코드를 불러오는 중입니다…

web/app/layout.tsxtsx · 33줄 · 969B

코드를 불러오는 중입니다…

web/app/page.module.csscss · 173줄 · 3KB

코드를 불러오는 중입니다…

web/app/page.tsxtsx · 95줄 · 3KB

코드를 불러오는 중입니다…

web/app/play/page.tsxtsx · 338줄 · 9KB

코드를 불러오는 중입니다…

web/app/play/play.module.csscss · 152줄 · 2KB

코드를 불러오는 중입니다…

web/components/PuzzleBoard.module.csscss · 27줄 · 396B

코드를 불러오는 중입니다…

web/components/PuzzleBoard.tsxtsx · 37줄 · 1KB

코드를 불러오는 중입니다…

web/lib/levels.tstypescript · 134줄 · 4KB

코드를 불러오는 중입니다…

web/lib/progress.tstypescript · 37줄 · 1KB

코드를 불러오는 중입니다…

web/lib/puzzle.tstypescript · 145줄 · 4KB

코드를 불러오는 중입니다…

web/lib/solver.tstypescript · 181줄 · 5KB

코드를 불러오는 중입니다…

web/package.jsonjson · 25줄 · 557B

코드를 불러오는 중입니다…