커스텀 기물, 효과, 트리거를 위한 선언적 DSL
레벨 2: Compose (조합)
레벨 2는 커스텀 기물, 보드 효과, 게임 트리거를 만들기 위한 선언적 DSL을 도입합니다. 여기서 ChessLang의 진정한 힘이 발휘됩니다.
개요
레벨 2로 가능한 것들:
- 고유한 이동 패턴을 가진 커스텀 기물 정의
- 게임 동작을 수정하는 보드 효과 생성
- 게임 이벤트에 반응하는 트리거 설정
- 복잡한 상호작용을 선언적으로 조합
커스텀 기물
기본 기물 정의
piece Amazon {
move: slide(orthogonal) | slide(diagonal) | leap(2, 1)
capture: =move
}이렇게 하면 퀸과 나이트의 이동을 결합한 "Amazon"이 생성됩니다.
기물 속성
| 속성 | 필수 | 설명 |
|---|---|---|
move | 예 | 이동 패턴 |
capture | 아니오 | 잡기 패턴 (기본값: move와 동일) |
traits | 아니오 | 특수 능력 |
state | 아니오 | 기물 고유 상태 |
value | 아니오 | 기물 가치 (평가용) |
symbol | 아니오 | 표시 심볼 |
이동 패턴
step
고정된 수의 칸을 이동합니다:
piece King {
move: step(any) # 모든 방향으로 1칸
}
piece Pawn {
move: step(forward) # 앞으로 1칸
move: step(forward, 2) where first_move and clear
}slide
막힐 때까지 여러 칸을 이동합니다:
piece Rook {
move: slide(orthogonal) # 북/남/동/서 방향으로 무제한
}
piece Bishop {
move: slide(diagonal) # 대각선으로 무제한
}
piece Queen {
move: slide(orthogonal) | slide(diagonal)
}leap
특정 오프셋으로 점프합니다 (중간 기물 무시):
piece Knight {
move: leap(2, 1) # 8가지 회전 모두 자동 포함
}
piece Camel {
move: leap(3, 1) # 더 긴 점프
}
piece Zebra {
move: leap(3, 2)
}hop
기물을 뛰어넘어 반대편에 착지합니다:
piece Cannon {
move: slide(orthogonal)
capture: hop(orthogonal) # 정확히 하나의 기물을 뛰어넘어야 함
}패턴 조합자
Or (|)
패턴 중 선택:
piece Queen {
move: slide(orthogonal) | slide(diagonal)
}Then (+)
순차적 이동:
piece Gryphon {
move: step(diagonal) + slide(orthogonal)
}Repeat (*)
패턴 반복:
piece Sprinter {
move: step(forward) * 3 where clear
}조건 (where)
패턴에 조건을 추가합니다:
piece Pawn {
move: step(forward) where empty
move: step(forward, 2) where first_move and clear
capture: step(NE) | step(NW) where enemy # 대각선 앞으로 잡기
}사용 가능한 조건:
| 조건 | 설명 |
|---|---|
empty | 대상 칸이 비어있음 |
enemy | 대상 칸에 적 기물이 있음 |
friend | 대상 칸에 아군 기물이 있음 |
clear | 경로에 기물이 없음 |
first_move | 기물의 첫 이동 |
check | 킹이 체크 상태 |
not check | 킹이 체크 상태가 아님 |
잡기 패턴
piece Pawn {
move: step(forward) where empty
capture: step(NE) | step(NW) where enemy # 다른 잡기 패턴
}
piece Queen {
move: slide(any)
capture: =move # move 패턴과 동일
}특성 (Traits)
특성은 기물에 특수 능력을 부여합니다:
piece Knight {
move: leap(2, 1)
traits: [jump] # 기물을 뛰어넘을 수 있음
}
piece King {
move: step(any)
traits: [royal] # 잡히면/체크메이트되면 게임 종료
}내장 특성:
| 특성 | 설명 |
|---|---|
royal | 잡히면 패배 (체크메이트 대상) |
jump | 다른 기물을 뛰어넘을 수 있음 |
phase | 다른 기물을 통과할 수 있음 (잡기 불가) |
promote | 끝에 도달하면 승진 가능 |
immune | 잡히지 않음 |
explosive | 잡히면 주변 기물을 파괴 |
커스텀 특성도 정의할 수 있습니다:
piece Teleporter {
move: leap(2, 1)
traits: [warp, jump] # 'warp'는 커스텀 특성
state: { cooldown: 0 }
}기물 상태
기물 고유 정보를 추적합니다:
piece Berserker {
move: step(any)
state: { rage: 0 }
}효과 (Effects)
효과는 보드의 칸을 수정하여 이동 차단이나 시각적 표시를 할 수 있습니다:
effect trap {
blocks: enemy # 적 이동을 막음
visual: "red" # 빨간색 표시
}
effect shield {
blocks: enemy # 적 이동을 막음
visual: "blue" # 파란색 표시
}
effect lava {
blocks: all # 모든 이동을 막음
visual: "orange" # 주황색 표시
}효과 속성
| 속성 | 값 | 설명 |
|---|---|---|
blocks | none | 이동 차단 없음 (기본값) |
enemy | 효과 소유자의 적 기물 이동 차단 | |
friend | 효과 소유자의 아군 기물 이동 차단 | |
all | 모든 기물 이동 차단 | |
visual | 문자열 | 시각적 표시 색상 (예: "red", "blue") |
효과 사용하기
효과는 mark 액션으로 칸에 적용됩니다:
# 트리거에서 효과 적용
trigger place_trap {
on: move
when: piece.type == Trapper
do: mark origin with trap
}트리거 (Triggers)
트리거는 게임 이벤트에 반응합니다:
trigger power_up {
on: capture
when: piece.type == Warrior
do: set piece.state.kills = piece.state.kills + 1
}여러 액션이 필요한 경우 중괄호 블록을 사용합니다:
trigger multi_action {
on: capture
do: {
remove piece
set game.state.score = game.state.score + 1
}
}트리거 구조
trigger name {
on: event # 언제 발동할지
when: condition # 추가 조건 (선택)
optional: true # 선택적 트리거 (선택)
description: "메시지" # 선택 다이얼로그 메시지 (선택)
do: action # 무엇을 할지
}선택적 트리거 (Optional Triggers)
optional: true를 사용하면 사용자에게 트리거 실행 여부를 묻습니다:
trigger place_trap {
on: move
when: piece.type == Trapper and piece.state.traps < 3
optional: true
description: "덫을 설치하시겠습니까?"
do: {
mark origin with trap
set piece.state.traps = piece.state.traps + 1
}
}키보드 단축키:
Y/Enter: 트리거 실행N/Escape: 건너뛰기
| 속성 | 필수 | 설명 |
|---|---|---|
optional | 아니오 | true면 사용자에게 선택권 부여 |
description | 아니오 | 선택 다이얼로그에 표시할 메시지 |
이벤트
| 이벤트 | 설명 | 사용 가능한 변수 |
|---|---|---|
move | 모든 이동 | piece, origin, target |
capture | 기물 잡힘 | piece, captured, origin, target |
check | 체크 줌 | piece, king |
turn_start | 턴 시작 | player |
turn_end | 턴 종료 | player |
game_start | 게임 시작 | - |
액션
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 | 무승부 선언 |
완전한 예제
Power Warrior Chess
적을 잡을 때마다 킬 카운트가 증가하는 전사 기물입니다:
game: "Power Warrior Chess"
extends: "Standard Chess"
piece Warrior {
move: step(any)
capture: =move
state: { kills: 0 }
value: 4
}
trigger count_kills {
on: capture
when: piece.type == Warrior
do: set piece.state.kills = piece.state.kills + 1
}
setup:
add:
White Warrior: [d2, e2]
Black Warrior: [d7, e7]Trapper Chess
선택적 트리거를 사용한 덫 설치 게임입니다:
game: "Trapper Chess"
extends: "Standard Chess"
# 덫 효과: 적 이동 차단
effect trap {
blocks: enemy
visual: "red"
}
# 트래퍼 기물: 이동 후 덫 설치 가능
piece Trapper {
move: step(any)
capture: =move
state: { traps: 0 }
value: 3
}
# 선택적 트리거: 사용자가 덫 설치 여부 선택
trigger place_trap {
on: move
when: piece.type == Trapper and piece.state.traps < 3
optional: true
description: "덫을 설치하시겠습니까?"
do: {
mark origin with trap
set piece.state.traps = piece.state.traps + 1
}
}
setup:
add:
White Trapper: [c1]
Black Trapper: [c8]Zombie Chess
폰이 잡히면 좀비로 부활하는 변형입니다:
game: "Zombie Chess"
extends: "Standard Chess"
# 좀비: 모든 방향으로 한 칸씩 이동
piece Zombie {
move: step(any)
capture: =move
traits: [undead]
state: { resurrected: true }
}
# 폰이 잡히면 잡는 기물의 원래 위치에 적 좀비로 부활
# 좀비(Zombie)는 Pawn이 아니므로 이 트리거에 해당하지 않음 → 좀비는 부활하지 않음
trigger pawn_rises {
on: capture
when: captured.type == Pawn
do: create Zombie at origin for captured.owner
}Cannon Chess
⚠️ 참고:
hop패턴은 현재 기본 동작만 구현되어 있습니다.
game: "Cannon Chess"
extends: "Standard Chess"
piece Cannon {
move: slide(orthogonal)
capture: hop(orthogonal) # 정확히 하나의 기물을 뛰어넘어야 함
value: 5
symbol: "C"
}
setup:
add:
White Cannon: [c1, f1]
Black Cannon: [c8, f8]Cooldown Knight Chess
이동 후 쿨다운이 적용되는 나이트입니다:
game: "Cooldown Knight Chess"
extends: "Standard Chess"
piece CooldownKnight {
move: leap(2, 1)
capture: =move
traits: [jump]
state: { cooldown: 0 }
value: 3
}
# 이동 후 쿨다운 설정
trigger knight_cooldown {
on: move
when: piece.type == CooldownKnight
do: set piece.state.cooldown = 2
}
setup:
replace:
Knight: CooldownKnight고급 커스텀 기물
⚠️ 참고: 아래 예제들은 ChessLang의 설계 비전을 보여주는 것으로, 일부 기능(예:
any X where,adjacent to,pieces in radius)은 아직 개발 중입니다. 현재 구현된 기능만 사용하는 예제는 Trapper Chess, Zombie Chess를 참고하세요.
더 복잡한 동작을 가진 기물들의 설계 예제입니다.
Vampire (뱀파이어)
잡은 기물을 아군으로 변환하는 강력한 기물입니다.
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 (변신체)
마지막으로 잡은 기물의 이동 패턴을 복사합니다.
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 (수호자)
인접한 아군 기물을 잡기로부터 보호합니다.
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 (기병)
전방으로 돌격하여 여러 기물을 잡을 수 있습니다.
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 (강령술사)
잡힌 기물에서 영혼을 모아 좀비를 소환합니다.
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 (광대)
잡는 대신 대상 기물과 위치를 교환합니다.
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 (메두사)
대각선 시야의 적 기물을 동결시킵니다.
piece Medusa {
move: step(any)
capture: slide(diagonal) where enemy
state: { gazeActive: true }
value: 5
}
effect frozen {
blocks: all
visual: "cyan"
}
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턴 후 폭발하여 주변 기물을 제거합니다.
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 (텔레포터)
쿨다운이 있지만 빈 칸 어디로든 순간이동할 수 있습니다.
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
}
}
}모범 사례
- 단순하게 시작: 조건을 추가하기 전에 기본 이동 패턴부터 시작
- 점진적 테스트: 한 번에 하나의 기능만 추가하고 테스트
- 명확한 이름 사용: 기물과 효과의 이름을 설명적으로 작성
- 밸런스 고려: 커스텀 기물에 적절한 가치 할당
- 동작 문서화: 복잡한 트리거에 주석 추가