ONCE AI PUBLISHING디지털 핸드북 시리즈 #01
CHAPTER 01

인베이더 게임으로 배우는 휴리스틱과 AI 브리지

순수 규칙 게임을 인공지능과 연결하기 위한 관찰, 행동, 통신 설계

고전 게임이 좋은 이유

스페이스 인베이더류 게임은 규칙이 단순하다. 플레이어는 좌우로 움직이고, 총알을 쏘고, 적의 총알을 피한다. 적은 천천히 내려오고, 벙커는 총알에 맞아 부서진다. 이 단순함은 학습 예제에서 큰 장점이다. 복잡한 3D 물리나 스토리 없이도 관찰, 행동, 보상, 정책이라는 인공지능의 핵심 요소를 모두 설명할 수 있기 때문이다.

이 프로젝트의 게임 엔진은 Qt/C++로 작성되어 있고, 기본적으로 사람 조작만으로도 돌아간다. 다시 말해 게임 본체는 AI가 아니다. AI는 게임 밖에서 들어온다. 이 구분을 분명히 해야 한다. 게임은 세계이고, 휴리스틱과 VLM은 그 세계를 바라보며 행동을 고르는 플레이어다.

프로젝트 구성

파일

역할

src/gameengine.h/.cpp

게임 규칙, 플레이어, 에일리언, 총알, 벙커, 충돌, 승패를 담당한다.

src/aiplayer.cpp

총알 회피, 적 정렬, 발사 규칙으로 만든 로컬 휴리스틱 플레이어다.

src/mainwindow.cpp

사람, 로컬 AI, VLM 모드를 선택하고 매 틱 행동을 게임에 넣는다.

src/tcpvlmclient.cpp

게임 화면 PNG와 14x11 격자를 외부 VLM 서버로 보내고 액션을 받는다.

invader_vlm_server.py

TCP 서버로 INV3 추론 요청과 INVL 로그 요청을 처리한다.

dataset_invader.py

JSONL 로그를 읽어 이미지와 액션 라벨 학습 데이터로 바꾼다.

download_vlm_model.py

Qwen3-VL 2B 모델을 vlm_models 아래에 내려받는다.

게임 상태와 행동

인공지능을 붙이려면 먼저 게임을 기계가 읽을 수 있는 형태로 정해야 한다. 이 프로젝트는 화면 전체를 PNG로 보낼 수도 있고, 동시에 14행 11열의 작은 격자 상태도 보낸다. 격자는 픽셀보다 정보가 거칠지만, 학습과 디버깅에는 훨씬 쉽다.

요소

값

격자 크기

14 x 11

Cell 0

빈칸

Cell 1

에일리언 또는 UFO

Cell 2

플레이어

Cell 3

플레이어 총알

Cell 4

적 총알

행동 0

왼쪽 이동

행동 1

오른쪽 이동

행동 2

발사

행동 3

대기

관찰 = 화면 PNG + 14x11 격자
행동 = 0:left, 1:right, 2:fire, 3:none
게임 루프 = tick(action)

휴리스틱이란 무엇인가

휴리스틱은 학습된 모델이 아니라 사람이 직접 만든 경험적 규칙이다. 정답을 수학적으로 보장하지는 않지만, 문제를 빨리 풀기 위해 쓸 만한 판단 기준을 적어 둔 것이다. 인베이더에서는 '적 총알이 가까우면 피한다', '적과 x좌표를 맞춘다', '위에 적이 있으면 쏜다' 같은 규칙이 휴리스틱이다.

휴리스틱의 장점은 이해하기 쉽고 빠르다는 점이다. 단점은 새로운 상황에 약하다는 점이다. 예를 들어 적 총알이 두 방향에서 동시에 오거나, 벙커가 애매하게 막고 있거나, UFO를 노릴지 일반 적을 노릴지 선택해야 하는 상황에서는 규칙이 금방 복잡해진다.

로컬 AI의 휴리스틱

aiplayer.cpp의 로컬 AI는 매우 짧고 좋은 예제다. 먼저 플레이어 근처로 내려오는 적 총알을 찾는다. 위험하면 왼쪽이나 오른쪽 중 더 안전한 쪽으로 이동한다. 위험이 없으면 아래쪽에 있고 x좌표가 가까운 에일리언을 목표로 잡고 그쪽으로 움직인다. 목표 x좌표에 거의 맞으면, 위에 적이 있고 플레이어 총알 수가 한도보다 적을 때 발사한다.

규칙

의미

bulletThreatNearX

플레이어 위쪽 가까운 x좌표에 적 총알이 내려오면 위험으로 판단한다.

bestAlienX

아래쪽에 있고 플레이어 x좌표와 가까운 적을 우선 목표로 잡는다.

alienAboveX

현재 x좌표 위에 적이 있으면 발사할 가치가 있다고 본다.

countPlayerBullets

동시에 쏠 수 있는 플레이어 총알 수 제한을 지킨다.

suggestAction

회피 -> 정렬 -> 발사 -> 대기 순서로 행동을 고른다.

if enemy bullet is near:
    move to safer side
else if target alien is left:
    move left
else if target alien is right:
    move right
else if alien is above and bullet limit allows:
    fire
else:
    none

휴리스틱의 교육적 가치

이 장에서 휴리스틱은 단순한 임시방편이 아니다. 휴리스틱은 첫 번째 선생님이다. VLM을 학습시키려면 처음에는 누군가의 행동 데이터가 필요하다. 사람의 플레이를 모아도 되고, 로컬 휴리스틱의 플레이를 모아도 된다. 로컬 휴리스틱은 완벽하지 않지만, 모델이 '무엇을 보면 무엇을 해야 하는가'를 처음 익히는 데 충분한 출발점이 된다.

관점

휴리스틱

학습 모델

만드는 방법

사람이 규칙을 직접 적는다.

데이터에서 패턴을 배운다.

장점

빠르고 설명 가능하다.

복잡한 상황을 더 유연하게 처리할 수 있다.

단점

상황이 늘면 규칙이 복잡해진다.

데이터가 부족하면 엉뚱한 행동을 한다.

역할

초기 교사, 기준선, 폴백

최종 정책 또는 보조 판단자

브리지가 필요한 이유

게임은 C++ Qt 프로그램이고, VLM은 Python 서버에서 돈다. 둘은 언어도 다르고 실행 환경도 다르다. 브리지는 이 둘 사이의 번역기다. 게임 쪽은 현재 화면과 격자 상태를 보낸다. AI 쪽은 0, 1, 2, 3 중 하나의 행동만 돌려준다. 이 단순한 계약이 있어야 게임을 고치지 않고도 여러 AI 모델을 갈아 끼울 수 있다.

Qt Game
  -> packGrid()
  -> grab screen as PNG
  -> TCP INV3 frame
  -> Python VLM server
  -> action digit 0..3
  -> GameEngine.tick(action)

프로토콜

용도

PING

서버 연결 확인. 응답은 PONG.

INV3

PNG와 격자를 보내고 VLM 액션을 받는 추론 요청.

RPLY

서버가 돌려주는 액션 응답. 성공 시 action 바이트 포함.

INVL

사람 또는 로컬 AI의 한 틱 행동을 서버에 기록하는 로그 요청.

LACK

로그를 받았다는 확인 응답.

VLM 서버의 역할

invader_vlm_server.py는 외부 플레이어다. INV3 요청을 받으면 PNG와 격자를 읽고, Qwen3-VL 같은 비전 언어 모델에게 '이 화면에서 어떤 행동을 할 것인가'를 묻는다. 모델은 반드시 한 글자 0, 1, 2, 3으로 답해야 한다. 파싱이 실패하면 재시도하고, 그래도 실패하면 mock 또는 로컬 폴백 행동으로 안전하게 빠질 수 있다.

이 설계에서 중요한 점은 VLM이 게임 규칙을 직접 실행하지 않는다는 것이다. VLM은 행동만 고른다. 충돌, 점수, 총알 이동, 적 이동은 여전히 GameEngine이 책임진다. 이렇게 해야 AI가 이상한 답을 해도 게임 세계의 규칙은 깨지지 않는다.

python invader_vlm_server.py --host 127.0.0.1 --port 9300 --device mps

# 모델 없이 통신만 확인할 때
python invader_vlm_server.py --port 9300 --mock

로그가 학습 데이터가 되는 과정

MainWindow는 사람, 로컬 AI, VLM의 행동을 모두 로그로 남길 수 있다. 각 로그에는 게임 이름, 시간, 액션, 액터, 모드, 상태, 순번, 14x11 보드가 들어간다. 이 로그는 그대로 행동 복제 학습의 재료가 된다. dataset_invader.py는 JSONL 로그를 읽고, 보드를 작은 이미지로 렌더링한 뒤, action 라벨과 함께 train.jsonl을 만든다.

python dataset_invader.py \
  --jsonl logs/invader_train.jsonl \
  --out-dir datasets/invader_sft \
  --save-images

데이터 원천

장점

주의점

사람 플레이

자연스럽고 창의적인 행동이 들어간다.

실수와 습관도 함께 들어간다.

로컬 휴리스틱

일관된 기준선 데이터를 빠르게 모을 수 있다.

휴리스틱의 한계를 그대로 배운다.

VLM 플레이

모델이 스스로 만든 행동을 다시 분석할 수 있다.

오답이 반복 학습되지 않도록 필터링해야 한다.

브리지를 만들 때의 설계 원칙

  • 게임 엔진은 항상 결정적 규칙을 유지하고, AI는 행동 선택만 담당한다.
  • 관찰은 화면 PNG와 구조화된 격자를 함께 보낸다.
  • 행동 공간은 작고 명확하게 둔다. 이 프로젝트는 4개 행동만 사용한다.
  • AI 응답은 반드시 검증한다. 0~3 밖의 값은 None으로 처리하거나 폴백한다.
  • 응답이 늦을 때 게임이 무너지는 것을 막기 위해 타임아웃과 취소 버튼을 둔다.
  • 서버 실패 시 로컬 휴리스틱으로 대체해 게임이 계속 진행되도록 한다.
  • 모든 행동을 JSONL로 남겨 나중에 데이터셋으로 변환할 수 있게 한다.

AI 연결 이후의 발전 단계

이 프로젝트는 세 단계로 발전시킬 수 있다. 첫 단계는 휴리스틱 자동 플레이어다. 두 번째 단계는 VLM 서버가 화면을 보고 행동을 고르는 단계다. 세 번째 단계는 사람과 휴리스틱의 로그를 모아 VLM을 미세조정하거나 작은 정책망을 학습하는 단계다. 이때 게임은 그대로 두고 브리지와 모델만 바꾸면 된다.

단계

설명

1. 휴리스틱

총알 회피, 적 정렬, 발사 규칙으로 자동 플레이 기준선을 만든다.

2. 브리지

Qt 게임과 Python VLM 서버를 TCP 프로토콜로 연결한다.

3. 로깅

사람과 휴리스틱의 행동을 JSONL로 저장한다.

4. 데이터셋

JSONL을 이미지와 액션 라벨로 변환한다.

5. 학습

VLM 또는 작은 시각 정책 모델이 행동을 모방하게 학습한다.

6. 검증

점수, 생존 시간, 웨이브 클리어 수, 위험 회피율을 비교한다.

평가 기준

평가 항목

질문

생존 시간

모델이 얼마나 오래 버티는가?

점수

적을 얼마나 많이 맞히는가?

웨이브 진행

한 웨이브를 클리어하고 다음 웨이브로 넘어가는가?

총알 회피

적 총알이 가까울 때 피하는 행동을 하는가?

발사 효율

적이 위에 있을 때 쏘고, 의미 없는 발사를 줄이는가?

응답 안정성

VLM 응답이 0~3 형식을 잘 지키는가?

폴백 빈도

서버 실패나 파싱 실패로 휴리스틱 대체가 얼마나 자주 일어나는가?

책에서 강조할 메시지

이 장의 주인공은 거대한 모델이 아니다. 주인공은 연결 방식이다. 인공지능이 없는 고전 게임도 관찰과 행동의 인터페이스를 만들면 학습 환경이 된다. 휴리스틱은 첫 번째 교사이고, 브리지는 게임과 모델 사이의 언어다. 이 둘을 만들 수 있으면 어떤 오래된 프로그램도 AI 실험장으로 바꿀 수 있다.

실습 순서

  • Qt 프로그램을 실행해 사람 모드로 게임 규칙을 먼저 확인한다.
  • 로컬 AI 모드로 바꾸고 휴리스틱이 어떻게 움직이는지 관찰한다.
  • mock 서버를 실행해 TCP 브리지가 정상 동작하는지 확인한다.
  • VLM 서버를 실행하고 VLM 모드에서 액션이 돌아오는지 확인한다.
  • 사람 또는 로컬 AI의 플레이를 JSONL로 저장한다.
  • dataset_invader.py로 train.jsonl과 보드 이미지를 만든다.
  • 학습된 모델과 휴리스틱의 점수, 생존 시간, 발사 효율을 비교한다.

연습 문제

  • bulletThreatNearX의 거리 기준을 14에서 20으로 늘리면 생존 시간이 어떻게 바뀌는지 실험해 보자.
  • UFO가 나타났을 때 UFO를 우선 목표로 잡는 휴리스틱을 추가해 보자.
  • VLM 응답이 잘못된 형식일 때 재시도 프롬프트를 어떻게 바꾸면 좋을지 설계해 보자.
  • 14x11 격자 대신 더 촘촘한 28x22 격자를 쓰면 어떤 장단점이 생기는지 정리해 보자.
  • 휴리스틱 로그와 사람 로그를 섞어 학습할 때 어떤 비율이 좋을지 실험 계획을 세워 보자.
CHAPTER 01 · 인베이더 게임으로 배우는 휴리스틱과 AI 브리지1 / 1
책장을 누르거나 좌우로 밀어 넘기기
CHAPTER 01

인베이더 게임으로 배우는 휴리스틱과 AI 브리지

댓글 0

아직 댓글이 없습니다.