Card-Forge/forge. 세계에서 가장 유명한 카드 게임 매직 더 개더링(MTG)의 복잡한 규칙을 통째로 코드로 구현한 오픈소스 규칙 엔진이다. 핵심은 카드 한 장 한 장의 효과를 자바 코드가 아니라 사람이 읽을 수 있는 텍스트 스크립트로 적어두고, 엔진이 그 텍스트를 읽어 실제 게임으로 작동시킨다는 점. 카드 스크립트만 33,000장 이상, 누적 커밋 약 74,000건의 20년 묵은 커뮤니티 프로젝트이며, AI 상대·온라인 대전·RPG(Adventure) 모드까지 한 채에 들어 있다. (저장소: Card-Forge/forge · 언어 Java 17 · ★2.4k · 라이선스 GPL-3.0 · 크로스플랫폼 Windows·Mac·Linux·Android · TrendShift 라이브 멘션 등재)
"규칙을 코드에 박는 대신, 카드 한 장을 '텍스트 한 장'으로 적어두고 엔진이 읽게 했다."
매직 더 개더링은 "세상에서 가장 규칙이 복잡한 게임"으로 꼽힌다 — 카드마다 고유한 효과가 있고, 그 효과들이 서로 맞물려 예외에 예외를 만든다. Forge는 이 난장판을 "규칙 엔진" 하나로 길들였다. 그리고 영리하게도, 카드 효과를 자바 코드로 일일이 짜는 대신 사람이 읽을 수 있는 텍스트 파일로 적어두고, 엔진이 그 텍스트를 읽어 게임으로 바꾼다.
구체적으로 보면 Forge는 비공식 프로젝트다(매직 더 개더링의 저작권자 Wizards of the Coast와 무관한 커뮤니티 팬 프로젝트). 자바(Java)로 짜였고, 누적 커밋 약 74,000건에 달하는 20년 가까운 역사를 가진, 오픈소스 게임치고는 보기 드물게 거대하고 오래 살아남은 코드베이스다. 데스크톱(Windows·Mac·Linux)뿐 아니라 안드로이드에서도 돌고, 혼자 AI와 두는 모드부터 온라인 대전, 심지어 카드를 모으며 맵을 탐험하는 RPG(Adventure) 모드까지 들어 있다.
이 문서가 주목하는 건 게임 자체가 아니라 그 안의 설계다. "수만 가지 예외 규칙을 어떻게 코드로 감당하는가", "AI는 어떻게 다음 수를 고르는가", "하나의 게임 로직을 데스크톱과 모바일에서 어떻게 같이 쓰는가" — 소프트웨어 엔지니어가 배울 게 가득한, 살아있는 교과서다.
게임이 재미있어서가 아니라, "이걸 코드로 어떻게 해냈지?"가 놀라워서.
매직 더 개더링을 디지털로 옮긴 시도는 많았다. 하지만 Forge가 개발자들 사이에서 오래 회자되는 이유는 따로 있다.
Forge의 카드는 forge-gui/res/cardsfolder/ 아래에 알파벳 폴더로 나뉜 텍스트 파일 33,289개로 들어 있다. 새 카드를 추가할 때 자바 코드를 짜고 다시 컴파일할 필요가 없다 — 텍스트 한 장만 적으면 끝이다. 덕분에 프로그래머가 아닌 자원봉사자도 카드를 기여할 수 있고, 3만 장이라는 규모가 가능해졌다.
턴의 11단계(언탭→유지→뽑기→메인1→전투 5단계→메인2→종료→정리), 스택(stack) 기반 주문 해결, 상태 기반 행동(state-based action), 유발·대체·정적 능력의 우선순위 처리까지 — MTG 종합 규칙서에 적힌 흐름을 코드로 재현한다. 단순한 "카드 대결"이 아니라 규칙 처리기를 통째로 만든 것이다.
휴리스틱 기반 AI 상대, 자체 서버를 통한 온라인 대전, 그리고 카드를 모으며 오버월드를 탐험하는 Adventure 모드(고전 게임 '섄달라' 풍의 RPG)까지 들어 있다. 헤드리스로 AI끼리 수천 판을 자동 대전시켜 밸런스를 측정하는 CLI 도구도 있다.
게임 규칙(forge-game)은 화면과 완전히 분리돼 있어서, 데스크톱(자바 Swing)과 모바일(libGDX)이 같은 엔진을 공유한다. "UI는 갈아끼우되 핵심은 한 번만 만든다"는 교과서적 분리를 대규모로 실천한 사례다.
| 항목 | Forge | MTG Arena (공식) | XMage (오픈소스) |
|---|---|---|---|
| 성격 | 오프라인 중심 규칙 엔진 + AI | 상용 온라인 게임 | 온라인 대전 중심 엔진 |
| AI 상대 | 강함 (싱글플레이 핵심) | 제한적 | 약함 |
| 카드 정의 | 텍스트 스크립트(DSL) | 비공개 | 카드마다 자바 클래스 |
| 라이선스 | 오픈소스(GPL-3.0) | 비공개·상용 | 오픈소스(GPL/MIT) |
| 특수 모드 | Adventure RPG·Quest·드래프트 | 랭크·이벤트 | 대전 위주 |
XMage는 카드 하나에 자바 클래스 하나를 쓴다(컴파일 필요). Forge는 텍스트 한 장이면 된다. 같은 "오픈소스 MTG 엔진"이라도, 데이터와 코드를 가른 이 선택이 3만 장이라는 규모와 비개발자 기여를 가능하게 했다.
20년 묵은 코드베이스답게 거대 단일 클래스가 있다 — 게임 내 카드를 표현하는 Card.java는 무려 8,000줄이 넘는다. 처음 읽는 사람에겐 압도적이고, 리팩터링도 어렵다. 또 AI는 "학습된" 게 아니라 사람이 짠 휴리스틱(heuristic, 경험칙) 기반이라, 어그로·미드레인지엔 강하지만 콤보·컨트롤 덱엔 약하다. 그리고 GPL-3.0이라 코드를 가져다 폐쇄형 상용으로 쓰긴 어렵다.
"자바 한 언어로, 파서·게임 엔진·AI·데스크톱 GUI·모바일 게임 엔진까지 전부."
Forge는 98%가 자바인 Maven 멀티모듈 프로젝트다. 웹의 "프론트엔드/백엔드" 구분 대신, 코어 데이터 · 규칙 엔진 · AI · 공유 GUI · 플랫폼별 화면으로 나뉜다. 루트 pom.xml이 12개 모듈을 묶는 지도 역할을 한다.
pom.xml 하나가 자식 모듈들을 함께 빌드하는 구조. "큰 레고 세트를 부품 봉지별로 나눠 담은 것"과 같아서, 모듈 사이의 의존 방향(누가 누구를 쓰는지)이 분명해진다.| 모듈 | 역할 | 한 줄 설명 |
|---|---|---|
| forge-core | 코어 데이터 | 카드 메타데이터·마나·덱·카드 DB. 파서의 1차 입구(147개 자바 파일) |
| forge-game | 규칙 엔진 본체 | 게임 상태·스택·페이즈·능력·효과. 가장 큰 모듈(803개 파일) |
| forge-ai | 컴퓨터 상대 | 능력별 평가 + 선택적 게임 시뮬레이션(187개 파일) |
| forge-gui | UI-비의존 공유 | 게임 모드 로직 + 카드 스크립트 리소스(res/)(434개 파일) |
| 모듈 | 기술 | 한 줄 설명 |
|---|---|---|
| forge-gui-desktop | Java Swing | 데스크톱 GUI. MigLayout으로 배치(501개 파일) |
| forge-gui-mobile | libGDX | 모바일 게임 화면 로직. 안드로이드·iOS가 공유(357개 파일) |
| forge-gui-android / -ios | libGDX 런처 | 플랫폼 진입점만 얇게(안드로이드는 8개 파일) |
| adventure-editor | libGDX 툴 | Adventure(RPG) 모드 콘텐츠 편집기 |
forge-gui-mobile 하나로 안드로이드와 iOS를 동시에 커버한다. 데스크톱 GUI는 더 오래된 자바 기본 GUI인 Swing을 쓴다.| 구성 | 쓰임 |
|---|---|
| Java 17 | 전체 언어. CI는 Java 17·21 양쪽에서 테스트 |
| Google Guava | 코어 전반의 컬렉션·유틸(불변 맵 등) |
| JGraphT | 그래프 알고리즘 (의존·관계 계산) |
| Commons-Math3 | AI의 통계·수학 계산 |
| Netty · Jetty | 온라인 대전 서버·통신 |
| libGDX (gdx-ai·box2d·freetype) | 모바일 렌더·입력·폰트 |
| TestNG · Mockito | 테스트 (JUnit이 아니라 TestNG 사용) |
"내가 라이트닝 볼트를 시전하면, 그 텍스트 한 장이 화면 속 3 데미지가 되기까지 Forge 안에서 무슨 일이 벌어지나."
Forge를 이해하는 가장 좋은 방법은 카드 한 장이 살아 움직이는 길을 끝까지 따라가는 것이다. 먼저 전체 그림을 한 장으로 보자 — 디스크의 텍스트 파일이 어떤 단계를 거쳐 실제 게임 동작이 되는지다.
Forge의 심장은 카드 스크립트 언어(DSL)다. 카드 효과를 적는 작은 전용 언어로, 자바를 몰라도 읽고 쓸 수 있게 설계됐다. 실제 파일 세 장을 보자.
# g/grizzly_bears.txt — 능력 없는 평범한 크리처(바닐라)
Name:Grizzly Bears
ManaCost:1 G
Types:Creature Bear
PT:2/2
Oracle:
# l/lightning_bolt.txt — "아무 대상에게 3 데미지" 순간마법
Name:Lightning Bolt
ManaCost:R
Types:Instant
A:SP$ DealDamage | ValidTgts$ Any | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to any target.
Oracle:Lightning Bolt deals 3 damage to any target.
# e/elvish_visionary.txt — "전장에 나오면 카드 1장 뽑기" 유발 능력
Name:Elvish Visionary
ManaCost:1 G
Types:Creature Elf Shaman
PT:1/1
T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
Oracle:When Elvish Visionary enters, draw a card.
읽는 법은 의외로 쉽다. 각 줄은 키:값 꼴이고, 능력 줄은 파이프(|)로 항목을 나누고, 각 항목 안에서 달러($)로 이름과 값을 가른다. 그래서 A:SP$ DealDamage | NumDmg$ 3은 "이건 주문(SP) 능력이고, 종류는 DealDamage, 데미지 수치(NumDmg)는 3"이라는 뜻이다. CARDNAME은 출력할 때 카드 이름으로 치환된다.
| 앞머리 | 의미 | 예 |
|---|---|---|
| A:AB$ | 기동 능력(활성화해서 씀) | {T}: 1 데미지 |
| A:SP$ | 주문(카드 자체를 시전) | 라이트닝 볼트 |
| T: | 유발 능력(조건이 되면 자동) | 전장에 나오면 뽑기 |
| S: / R: | 정적 능력 / 대체 효과 | "항상 +1/+1" 등 |
| SVar:...DB$ | 연쇄 하위 효과(drawback) | 효과를 줄줄이 연결 |
파싱은 두 클래스가 맡는다. CardRules.Reader가 줄의 첫 글자를 보고 Name·ManaCost·Types·PT·A·T·SVar로 분기하고, 능력 줄(A:·T:)은 AbilityFactory가 받아 실제 능력 객체(SpellAbility)로 바꾼다. 이때 DealDamage 같은 값이 ApiType이라는 enum으로 매핑되고, 그 enum이 forge/game/ability/effects/ 폴더의 Effect 클래스 205종 중 하나(DealDamageEffect)에 연결된다.
카드 텍스트는 요리 레시피 카드다. CardRules.Reader는 레시피를 읽어 "재료와 단계"로 정리하는 사람이고, ApiType→Effect는 주방의 실제 조리 기구다. "DealDamage"라고 적힌 레시피가 들어오면, 엔진은 'DealDamage 기구'(DealDamageEffect)를 꺼내 실행한다. 레시피(텍스트)가 3만 장이어도, 기구(Effect)는 200여 종이면 충분하다 — 대부분의 카드가 같은 동작의 조합이기 때문이다.
카드를 시전하면 즉시 효과가 나는 게 아니라, 먼저 스택(stack)에 쌓인다. 상대가 대응할 기회를 준 뒤, 맨 위(나중에 쌓인 것)부터 차례로 해결된다. Forge에서 이건 forge.game.zone.MagicStack이 담당하고, 내부적으로 양쪽에서 넣고 뺄 수 있는 큐(Deque)로 구현돼 있다. resolveStack()이 맨 위 항목을 꺼내 그 능력의 resolve()를 호출한다.
GameAction.checkStateEffects()가 이 검사 루프를 돈다.턴 진행은 PhaseHandler가 맡는다. PhaseType enum이 MTG 정식 11단계(언탭·유지·뽑기·메인1·전투 5단계·메인2·종료·정리)를 그대로 정의하고, 단계마다 누구에게 우선권(priority)을 줄지 관리한다. 여기에 유발 능력(TriggerHandler), 대체 효과(ReplacementHandler), 정적 능력(StaticEffects) 세 핸들러가 스택 해결 사이사이에 끼어들어, 진짜 MTG 규칙의 복잡한 흐름을 재현한다.
위 부품들이 어떻게 맞물리는지, 가장 단순한 흐름 하나(엣지 케이스는 생략한 '해피 패스')로 따라가 보자.
// "라이트닝 볼트로 상대 얼굴에 3 데미지" 한 판의 내부 순서 (개념 단순화)
① 게임 시작 전: CardStorageReader 가 lightning_bolt.txt 를 읽어
CardRules 로 만들어 둔다 (3만 장 전부 메모리에)
② 내가 카드를 손에서 시전 → AbilityFactory 가 만든 SpellAbility 발동
③ 대상 선택: ValidTgts$ Any → 상대 플레이어를 타깃으로 지정
④ MagicStack.add(...) — 볼트가 스택에 올라간다 (아직 데미지 없음)
⑤ 양쪽이 더 안 하면 → resolveStack() 이 맨 위(볼트)를 꺼냄
⑥ DealDamageEffect.resolve() 실행 — 상대 생명점 -3
⑦ GameAction.checkStateEffects() — "생명점 0 이하인 사람 있나?" 검사
⑧ 있으면 checkGameOverCondition() 으로 승패 판정 → 없으면 다음 우선권
여기서 배울 핵심은 "데이터(텍스트)와 실행(엔진)이 깔끔히 갈려 있다"는 점이다. 볼트의 "3"이라는 숫자는 텍스트에서 왔지만, "스택에 올리고·해결하고·생명점을 깎고·승패를 검사하는" 흐름은 카드와 무관한 엔진의 일반 규칙이다. 그래서 카드가 3만 장이어도 이 흐름 코드는 한 벌이면 된다.
"모듈 12개가 무섭지만, 사실 '두뇌 4개 + 얼굴 여럿 + 리소스'로 묶인다."
루트에는 부모 pom.xml과 모듈 폴더들이 있다. 코드의 대부분은 4대 핵심 모듈에, 카드 텍스트 같은 리소스는 forge-gui/res/에 모여 있다.
처음 읽는다면 길잡이는 이렇다. 카드가 궁금하면 forge-gui/res/cardsfolder/의 텍스트 몇 장 → forge-core의 CardRules → forge-game의 AbilityFactory 순으로. 게임 흐름이 궁금하면 forge-game의 Game.java(전체 뼈대) → PhaseHandler(턴) → MagicStack(스택) 순으로 따라가면 된다.
forge-game(규칙)은 forge-gui-desktop(화면)을 모른다 — 반대로 화면이 규칙을 가져다 쓴다. 이렇게 "아래(코어)는 위(화면)를 모른다"를 모듈 경계로 못 박으면, 데스크톱 화면을 통째로 바꿔도 규칙 엔진은 안전하다. 같은 forge-game을 Swing 데스크톱과 libGDX 모바일이 공유할 수 있는 것도 이 분리 덕분이다."Forge 한 채에 '데이터 주도 설계·규칙 엔진·게임 AI·크로스플랫폼'이 다 들어 있다."
Forge는 게임을 안 좋아해도 배울 게 많다. 분야별로 무엇을 배울지 + 작게 실습할 아이디어를 정리했다.
배울 것: "코드에 박지 말고 데이터로 빼라"는 원칙의 진수. 3만 장의 카드를 자바 코드가 아니라 텍스트로 둔 덕에 어떻게 규모·기여·유지보수가 가능해졌는지. DSL을 설계하고 파싱하는 법.
실습: cardsfolder에서 간단한 카드 5장을 골라 키/값을 직접 해석해 보기. "이 줄이 무슨 동작이지?"를 Oracle: 줄(실제 카드 문구)과 대조하면 DSL이 빠르게 읽힌다.
배울 것: 줄 단위로 텍스트를 읽어 분기하는 파서(CardRules.Reader)와, 문자열을 실행 가능한 객체로 바꾸는 팩토리(AbilityFactory → ApiType → Effect). "문자열 → enum → 클래스" 매핑은 실무에서 자주 쓰는 패턴이다.
실습: AbilityFactory가 |로 항목을, $로 키·값을 가르는 부분을 따라 읽고, 같은 방식의 미니 파서를 직접 짜 보기(예: set$ hp | amount$ 10을 객체로).
배울 것: 턴·페이즈를 enum 상태 기계로(PhaseType·PhaseHandler), 스택(LIFO)으로 "대응의 대응"을, 상태 기반 행동으로 "매 순간 자동 검사"를 구현하는 법. 예외투성이 도메인을 핸들러로 쪼개 다스리는 설계.
실습: checkStateEffects()가 어떤 조건들을 검사하는지 목록으로 뽑아 보기. "왜 이걸 매번 검사해야 하나"를 게임 규칙과 연결하면 상태 기계 감각이 생긴다.
배울 것: "학습 없이도" 그럭저럭 두는 AI를 만드는 법. 능력별 평가 클래스(SpellAbilityAi의 151개 자식)와, 게임 상태를 통째로 복제해 수를 미리 둬 보는 시뮬레이션(GameSimulator·GameStateEvaluator). 보드를 점수로 환산하는 평가 함수 설계.
실습: DealDamageAi 같은 작은 *Ai 클래스 하나를 읽고 "AI가 언제 이 능력을 쓰기로 판단하나"의 조건을 정리. docs/AI.md가 설계 철학을 친절히 설명한다.
배울 것: 핵심 로직(forge-game)을 화면에서 떼어내고, IGuiBase·IGuiGame 같은 인터페이스로 데스크톱(Swing)·모바일(libGDX)을 갈아끼우는 법. "의존 역전"과 모듈 경계의 실전판.
실습: forge-gui의 인터페이스가 무엇을 약속하는지 메서드 목록을 보고, 데스크톱과 모바일이 각각 어떻게 구현했는지 한 메서드만 골라 비교.
배울 것: 12개 모듈을 묶는 Maven 멀티모듈 구조, TestNG 기반 테스트, 그리고 GUI를 화면 없는 서버에서 테스트하는 기법 — GitHub Actions가 Xvfb(가상 프레임버퍼)로 헤드리스 환경에서 Swing 테스트를 돌린다.
실습: .github/workflows/test-build.yaml을 읽고 "Java 17·21 매트릭스 + Xvfb"가 무슨 뜻인지 풀어 보기. 멀티모듈 빌드가 어떻게 한 번에 도는지 pom.xml의 모듈 목록과 연결.
"플레이는 가볍지만, 3만 장을 메모리에 올리고 소스에서 빌드하는 건 묵직하다."
| 플랫폼 | 요구사항 |
|---|---|
| 데스크톱 | Java 17 이상 설치. 릴리스 또는 일일 스냅샷 빌드를 받아 압축 해제(새 폴더 권장 — 버전 충돌 방지) |
| 안드로이드 | Android 11 이상 + RAM 6GB 이상 권장. "알 수 없는 앱 설치" 허용 필요. 첫 실행 시 카드 에셋을 자동 다운로드 |
| 공통 | 카드 3만 장 + 이미지라 저장 공간·메모리를 넉넉히. 업그레이드 시 기존 플레이어 데이터는 보존됨 |
개발하려면 JDK 17과 Maven이 필요하다. 멀티모듈이라 루트에서 한 번에 빌드하고, 데스크톱 모듈을 실행한다.
# 소스에서 Forge 데스크톱 빌드·실행
git clone https://github.com/Card-Forge/forge
cd forge
mvn -U -B clean install -DskipTests # 12개 모듈 전체 빌드 (첫 빌드는 길다)
# 데스크톱 GUI 실행 (빌드 후 forge-gui-desktop 산출물)
cd forge-gui-desktop/target
java -jar forge-gui-desktop-*-jar-with-dependencies.jar
# 화면 없이 AI끼리 자동 대전(밸런스 측정) — docs/AI.md
sim -d deck1.dck deck2.dck -n 3 # 두 덱을 3판 시뮬레이션
복사해서 그대로 쳐도 된다. 핵심은 mvn clean install 한 번이면 12개 모듈이 통째로 빌드된다는 것 — 다만 부품이 많고 카드 리소스가 커서 첫 빌드는 시간이 걸린다. sim 명령은 화면 없이 AI 대 AI를 돌려 결과만 뽑는, "성능·밸런스를 데이터로 본다"는 이 프로젝트의 성격이 드러나는 도구다.
"읽기만 하면 안 남는다 — 난이도별로 손을 움직여 보자."
cardsfolder의 grizzly_bears.txt를 본떠 나만의 능력 없는 크리처를 적어 본다(Name·ManaCost·Types·PT·Oracle 다섯 줄). 알파벳 폴더에 넣고 게임에서 검색해 보면 "텍스트 한 장이 진짜 카드가 되는" 데이터 주도 설계를 체감한다.
빌드 후 sim 명령으로 기본 덱 둘을 여러 판 붙여 본다. 승률·평균 턴 수가 출력되는 걸 보며 "게임을 데이터로 측정한다"는 감각을 얻는다. 화면 없이 도는 헤드리스 실행도 경험.
lightning_bolt.txt를 변형해 "아무 대상에게 N 데미지" 카드를 만들어 본다. NumDmg$ 숫자를 바꾸거나, ValidTgts$ Creature로 대상을 크리처로 제한해 보며 DSL 키를 익힌다. 한 칸 바꾸면 게임 동작이 어떻게 바뀌는지 확인.
forge-ai/.../ability/에서 DrawAi나 DealDamageAi 하나를 골라, "AI가 이 능력을 언제 쓰기로 판단하나"의 조건을 따라 읽는다. ComputerUtilCard 같은 평가 보조와 어떻게 엮이는지 메모. 게임 AI의 휴리스틱 감각을 얻는다.
MagicStack.resolveStack() → DealDamageEffect.resolve() → GameAction.checkStateEffects()로 이어지는 "주문 한 발의 일생"을 디버거/로그로 따라간다. 그 뒤 CONTRIBUTING.md를 읽고 새 카드 추가나 문서 수정 같은 첫 PR을 시도(AI 도구 사용 시 PR에 밝히는 정책 준수). 큰 오픈소스 기여 흐름을 경험.
"자바 기초에서 Forge에 카드를 기여하기까지 — 7주 코스 예시."
아래는 "자바를 좀 아는 사람이 Forge 코드를 읽고 작게 기여할 수 있는 수준"까지의 한 가지 길이다. 본인 속도에 맞춰 늘리거나 줄여도 된다.
| 주차 | 주제 | 무엇을 / 왜 |
|---|---|---|
| 1주 | 자바 + 객체지향 복습 | 클래스·상속·인터페이스·enum. Forge는 능력을 클래스 계층(SpellAbility 자식들)으로 표현한다 |
| 2주 | Maven 멀티모듈 | 부모/자식 pom.xml, 의존 방향. Forge를 직접 빌드해 12개 모듈이 어떻게 엮이는지 체감 |
| 3주 | 카드 DSL 읽기·쓰기 | cardsfolder의 카드들을 해석하고 직접 작성. docs/Creating-a-custom-Card.md가 공식 튜토리얼 |
| 4주 | 파서 따라가기 | CardRules.Reader → AbilityFactory → ApiType → Effect 경로를 코드로 추적 |
| 5주 | 게임 엔진 흐름 | Game → PhaseHandler(턴) → MagicStack(스택) → checkStateEffects(SBA)의 맞물림 이해 |
| 6주 | 게임 AI | docs/AI.md 정독 + *Ai 클래스 몇 개 읽기. 휴리스틱 vs 시뮬레이션 경로 비교 |
| 7주 | 기여(PR) | CONTRIBUTING.md 보고 새 카드 추가·버그 수정으로 첫 PR. CI(Xvfb 테스트) 통과 경험 |
Forge 코드베이스는 거대한 보드게임 공방 같다. 처음부터 공방 전체를 이해할 필요는 없다. "카드 만드는 작업대(DSL·파서) → 게임 진행 규칙(엔진) → 자동 대전 로봇(AI)" 식으로 관심 가는 작업대 하나씩 깊이 보는 게, 803개 파일짜리 forge-game을 한입에 삼키려다 체하는 것보다 낫다.
"이 문서와 Forge 코드에서 거듭 나오는 용어들 — 한 곳에 모아 풀었다."
키:값과 |·$ 구분자로 카드 효과를 짧게 적는다.Spell)·기동 능력(Ability)·하위 효과(AbilitySub) 등이 이걸 상속한다. 카드 텍스트의 A:·T: 줄이 결국 이 객체가 된다.forge/game/ability/effects/의 205종). DealDamage(enum) ↔ DealDamageEffect(코드) 식으로 짝지어진다.MagicStack이 양방향 큐(Deque)로 구현하고 resolveStack()으로 해결한다.GameAction.checkStateEffects()가 이 검사 루프를 돈다.TriggerHandler·ReplacementHandler·StaticEffects 핸들러로 처리한다.GameCopier)해 가상의 수를 둬 보고, 결과를 점수(GameStateEvaluator)로 비교해 더 나은 수를 고르는 AI 기법. 바둑·체스 AI의 수읽기와 같은 발상.forge-game 엔진을 공유한다.pom.xml 하나가 12개 모듈을 묶는다.공식 저장소·문서·커뮤니티.
GitHub 저장소 · github.com/Card-Forge/forge — 본체. forge-gui/res/cardsfolder/(카드 텍스트)와 forge-game(엔진)부터 보면 좋다.
카드 제작 튜토리얼 · Wiki — docs/Creating-a-custom-Card.md 및 위키의 Card scripting API 문서가 DSL의 공식 레퍼런스.
AI 설계 문서 · 저장소 docs/AI.md — AI 철학(휴리스틱 기반)과 sim CLI 사용법.
User Guide · Wiki User Guide — 모드(Adventure·Quest·드래프트) 플레이 안내.
Discord 커뮤니티 · discord.gg/HcPJNyD66a — 질문·기여 논의(#help·#rules).
TrendShift · trendshift.io/repositories/908 — 트렌딩 추이.