커스텀 기물, 효과, 트리거를 위한 선언적 DSL
레벨 2: Compose (조합)
레벨 2는 커스텀 기물, 보드 효과, 게임 트리거를 만들기 위한 선언적 DSL을 도입합니다. 여기서 ChessLang의 진정한 힘이 발휘됩니다.
개요
레벨 2로 가능한 것들:
- 고유한 이동 패턴을 가진 커스텀 기물 정의
- 게임 동작을 수정하는 보드 효과 생성
- 게임 이벤트에 반응하는 트리거 설정
- 복잡한 상호작용을 선언적으로 조합
커스텀 기물
기본 기물 정의
chesslang
piece Amazon {
move: slide(orthogonal) | slide(diagonal) | leap(2, 1)
capture: =move
}이렇게 하면 퀸과 나이트의 이동을 결합한 "Amazon"이 생성됩니다.
기물 속성
| 속성 | 필수 | 설명 |
|---|---|---|
move | 예 | 이동 패턴 |
capture | 아니오 | 잡기 패턴 (기본값: move와 동일) |
traits | 아니오 | 특수 능력 |
state | 아니오 | 기물 고유 상태 |
value | 아니오 | 기물 가치 (평가용) |
symbol | 아니오 | 표시 심볼 |
이동 패턴
step
고정된 수의 칸을 이동합니다:
chesslang
piece King {
move: step(any) # 모든 방향으로 1칸
}
piece Pawn {
move: step(forward) # 앞으로 1칸
move: step(forward, 2) where first_move and clear
}slide
막힐 때까지 여러 칸을 이동합니다:
chesslang
piece Rook {
move: slide(orthogonal) # 북/남/동/서 방향으로 무제한
}
piece Bishop {
move: slide(diagonal) # 대각선으로 무제한
}
piece Queen {
move: slide(orthogonal) | slide(diagonal)
}leap
특정 오프셋으로 점프합니다 (중간 기물 무시):
chesslang
piece Knight {
move: leap(2, 1) # 8가지 회전 모두 자동 포함
}
piece Camel {
move: leap(3, 1) # 더 긴 점프
}
piece Zebra {
move: leap(3, 2)
}hop
기물을 뛰어넘어 반대편에 착지합니다:
chesslang
piece Cannon {
move: slide(orthogonal)
capture: hop(orthogonal) # 정확히 하나의 기물을 뛰어넘어야 함
}패턴 조합자
Or (|)
패턴 중 선택:
chesslang
piece Queen {
move: slide(orthogonal) | slide(diagonal)
}Then (+)
순차적 이동:
chesslang
piece Gryphon {
move: step(diagonal) + slide(orthogonal)
}Repeat (*)
패턴 반복:
chesslang
piece Sprinter {
move: step(forward) * 3 where clear
}조건 (where)
패턴에 조건을 추가합니다:
chesslang
piece Pawn {
move: step(forward) where empty
move: step(forward, 2) where first_move and clear
capture: step(forward-diagonal) where enemy
}사용 가능한 조건:
| 조건 | 설명 |
|---|---|
empty | 대상 칸이 비어있음 |
enemy | 대상 칸에 적 기물이 있음 |
friend | 대상 칸에 아군 기물이 있음 |
clear | 경로에 기물이 없음 |
first_move | 기물의 첫 이동 |
check | 킹이 체크 상태 |
not check | 킹이 체크 상태가 아님 |
잡기 패턴
chesslang
piece Pawn {
move: step(forward)
capture: step(forward-diagonal) # 다른 잡기 패턴
}
piece Queen {
move: slide(any)
capture: =move # move 패턴과 동일
}특성 (Traits)
특성은 기물에 특수 능력을 부여합니다:
chesslang
piece Knight {
move: leap(2, 1)
traits: [jump] # 기물을 뛰어넘을 수 있음
}
piece King {
move: step(any)
traits: [royal] # 잡히면/체크메이트되면 게임 종료
}내장 특성:
| 특성 | 설명 |
|---|---|
royal | 잡히면 패배 (체크메이트 대상) |
jump | 다른 기물을 뛰어넘을 수 있음 |
phase | 다른 기물을 통과할 수 있음 (잡기 불가) |
promote | 끝에 도달하면 승진 가능 |
immune | 잡히지 않음 |
explosive | 잡히면 주변 기물을 파괴 |
커스텀 특성도 정의할 수 있습니다:
chesslang
piece Teleporter {
move: leap(2, 1)
traits: [warp, jump] # 'warp'는 커스텀 특성
state: { cooldown: 0 }
}기물 상태
기물 고유 정보를 추적합니다:
chesslang
piece Berserker {
move: step(any)
state: { rage: 0 }
}효과 (Effects)
효과는 보드의 칸을 수정합니다:
chesslang
effect fire {
damages: [any] # 모든 기물에게 피해
visual: highlight(red)
}
effect ice {
blocks: [enemy] # 적 이동을 막음
visual: highlight(blue)
}
effect trap {
on_enter: capture(entering) # 들어오는 기물을 잡음
visual: highlight(orange)
}효과 속성
| 속성 | 설명 |
|---|---|
damages | 피해를 받는 기물 |
blocks | 진입할 수 없는 기물 |
on_enter | 기물이 들어올 때 액션 |
on_exit | 기물이 나갈 때 액션 |
duration | 효과 지속 시간 (턴) |
visual | 시각적 표현 |
시각 효과
chesslang
effect glow {
visual: highlight(yellow)
visual: border(gold)
visual: icon("star")
}트리거 (Triggers)
트리거는 게임 이벤트에 반응합니다:
chesslang
trigger explosion {
on: capture
when: piece.type == Bomb
do: remove pieces in radius(1) from target
}여러 액션이 필요한 경우 중괄호 블록을 사용합니다:
chesslang
trigger multi_action {
on: capture
do: {
remove piece
set game.state.score = game.state.score + 1
}
}트리거 구조
chesslang
trigger name {
on: event # 언제 발동할지
when: condition # 추가 조건
do: action # 무엇을 할지
}이벤트
| 이벤트 | 설명 | 사용 가능한 변수 |
|---|---|---|
move | 모든 이동 | piece, origin, target |
capture | 기물 잡힘 | piece, captured, origin, target |
check | 체크 줌 | piece, king |
turn_start | 턴 시작 | player |
turn_end | 턴 종료 | player |
game_start | 게임 시작 | - |
액션
chesslang
trigger promote_on_hill {
on: move
when: piece.type == Pawn and target in zone.hill
do: transform piece to Queen
}
trigger place_trap {
on: move
when: piece.type == Trapper
do: mark origin with trap
}
trigger rage_increase {
on: capture
when: piece.type == Berserker
do: set piece.state.rage = piece.state.rage + 1
}사용 가능한 액션:
| 액션 | 설명 |
|---|---|
set X = Y | 값 설정 |
create Piece at pos | 새 기물 생성 |
remove piece | 기물 제거 |
transform piece to Type | 기물 타입 변경 |
mark pos with effect | 칸에 효과 적용 |
win Player | 승자 선언 |
draw | 무승부 선언 |
완전한 예제
Atomic Chess
chesslang
game: "Atomic Chess"
extends: "Standard Chess"
trigger atomic_explosion {
on: capture
do: {
remove piece
remove captured
remove pieces in radius(1) from target where not Pawn
}
}
victory:
add:
king_exploded: opponent.King == nullTrapper Chess
chesslang
game: "Trapper Chess"
extends: "Standard Chess"
piece Trapper {
move: step(any)
capture: =move
state: { traps_placed: 0 }
value: 3
}
effect trap {
on_enter: capture(entering) where enemy
duration: 5
visual: highlight(red, 0.3)
}
trigger place_trap {
on: move
when: piece.type == Trapper and piece.state.traps_placed < 3
do: {
mark origin with trap
set piece.state.traps_placed = piece.state.traps_placed + 1
}
}
setup:
add:
White:
Trapper: [d1]
Black:
Trapper: [d8]Cannon Chess
chesslang
game: "Cannon Chess"
extends: "Standard Chess"
piece Cannon {
move: slide(orthogonal)
capture: hop(orthogonal) # 정확히 하나의 기물을 뛰어넘어야 함
value: 5
symbol: "C"
}
setup:
modify:
White:
Rook: [a1]
Cannon: [h1]
Black:
Rook: [a8]
Cannon: [h8]Berserk Chess
chesslang
game: "Berserk Chess"
extends: "Standard Chess"
piece Berserker {
move: step(any) * (1 + state.rage)
capture: =move
state: { rage: 0 }
value: 4
}
trigger gain_rage {
on: capture
when: piece.type == Berserker
do: set piece.state.rage = min(piece.state.rage + 1, 3)
}
trigger lose_rage {
on: turn_end
when: any Berserker where state.rage > 0
do: set piece.state.rage = piece.state.rage - 1
}
setup:
modify:
White:
Knight: [b1]
Berserker: [g1]
Black:
Knight: [b8]
Berserker: [g8]고급 커스텀 기물
더 복잡한 동작을 가진 기물들의 예제입니다.
Vampire (뱀파이어)
잡은 기물을 아군으로 변환하는 강력한 기물입니다.
chesslang
piece Vampire {
move: step(any) | leap(2, 0)
capture: =move
traits: [jump]
state: { thralls: 0 }
value: 6
}
trigger vampiric_conversion {
on: capture
when: piece.type == Vampire and captured.type != King
do: {
transform captured to captured.type
set captured.owner = piece.owner
set piece.state.thralls = piece.state.thralls + 1
}
}Shapeshifter (변신체)
마지막으로 잡은 기물의 이동 패턴을 복사합니다.
chesslang
piece Shapeshifter {
move: leap(2, 1) # 기본: 나이트 이동
capture: =move
traits: [jump]
state: {
copiedType: "Knight",
captureCount: 0
}
value: 5
}
trigger shapeshifter_copy {
on: capture
when: piece.type == Shapeshifter
do: {
set piece.state.copiedType = captured.type
set piece.state.captureCount = piece.state.captureCount + 1
}
}Guardian (수호자)
인접한 아군 기물을 잡기로부터 보호합니다.
chesslang
piece Guardian {
move: step(any)
capture: =move
state: { protected: 0 }
value: 4
}
trigger guardian_protection {
on: capture
when: any Guardian adjacent to captured where Guardian.owner == captured.owner
do: {
cancel # 잡기 취소 - 기물이 보호됨
set Guardian.state.protected = Guardian.state.protected + 1
}
}Lancer (기병)
전방으로 돌격하여 여러 기물을 잡을 수 있습니다.
chesslang
piece Lancer {
move: step(orthogonal) # 일반 이동
capture: slide(forward) where enemy # 돌격 공격
traits: [charge]
state: { chargeReady: true }
value: 5
}
trigger lancer_cooldown {
on: capture
when: piece.type == Lancer
do: set piece.state.chargeReady = false
}
trigger lancer_recover {
on: turn_start
when: any Lancer where not state.chargeReady
do: set piece.state.chargeReady = true
}Necromancer (강령술사)
잡힌 기물에서 영혼을 모아 좀비를 소환합니다.
chesslang
piece Necromancer {
move: step(diagonal)
capture: =move
state: { souls: 0 }
value: 6
}
piece Zombie {
move: step(forward) | step(orthogonal)
capture: step(any) where enemy
value: 1
}
trigger collect_soul {
on: capture
when: any Necromancer where owner == piece.owner
do: set Necromancer.state.souls = Necromancer.state.souls + 1
}
trigger raise_zombie {
on: turn_start
when: any Necromancer where state.souls >= 3
do: {
create Zombie at random_empty_square adjacent to Necromancer
set Necromancer.state.souls = Necromancer.state.souls - 3
}
}Jester (광대)
잡는 대신 대상 기물과 위치를 교환합니다.
chesslang
piece Jester {
move: step(any)
capture: none # 잡기 불가, 교환만 가능
state: { swapsUsed: 0 }
value: 4
}
trigger jester_swap {
on: move
when: piece.type == Jester and target has piece
do: {
let targetPiece = piece_at(target)
move targetPiece to origin
set piece.state.swapsUsed = piece.state.swapsUsed + 1
}
}Medusa (메두사)
대각선 시야의 적 기물을 동결시킵니다.
chesslang
piece Medusa {
move: step(any)
capture: slide(diagonal) where enemy
state: { gazeActive: true }
value: 5
}
effect frozen {
blocks: [all]
duration: 2
visual: highlight(cyan, 0.5)
}
trigger medusa_gaze {
on: turn_start
when: any Medusa where state.gazeActive
do: mark pieces in line(diagonal) from Medusa where enemy with frozen
}Time Bomb (시한폭탄)
3턴 후 폭발하여 주변 기물을 제거합니다.
chesslang
piece TimeBomb {
move: step(orthogonal)
capture: none
state: { timer: 3, armed: true }
value: 1
}
trigger bomb_countdown {
on: turn_end
when: any TimeBomb where state.armed
do: set piece.state.timer = piece.state.timer - 1
}
trigger bomb_explode {
on: turn_start
when: any TimeBomb where state.timer <= 0
do: {
remove pieces in radius(2) from TimeBomb where not King
remove TimeBomb
}
}Teleporter (텔레포터)
쿨다운이 있지만 빈 칸 어디로든 순간이동할 수 있습니다.
chesslang
piece Teleporter {
move: step(orthogonal) # 일반 이동
capture: step(orthogonal)
state: { warpReady: true, warpCooldown: 0 }
value: 5
}
trigger teleporter_warp {
on: move
when: piece.type == Teleporter and piece.state.warpReady and distance > 1
do: {
set piece.state.warpReady = false
set piece.state.warpCooldown = 3
}
}
trigger warp_cooldown {
on: turn_end
when: any Teleporter where state.warpCooldown > 0
do: {
set piece.state.warpCooldown = piece.state.warpCooldown - 1
if piece.state.warpCooldown == 0 {
set piece.state.warpReady = true
}
}
}모범 사례
- 단순하게 시작: 조건을 추가하기 전에 기본 이동 패턴부터 시작
- 점진적 테스트: 한 번에 하나의 기능만 추가하고 테스트
- 명확한 이름 사용: 기물과 효과의 이름을 설명적으로 작성
- 밸런스 고려: 커스텀 기물에 적절한 가치 할당
- 동작 문서화: 복잡한 트리거에 주석 추가