SC2L
A commitment language for StarCraft II — authors declare what game states must hold by certain times, how to react to events, and how to orchestrate concurrent behaviors.
Compiles to playbook that runs on a fixed runtime across desktop, mobile, and web.
Grammar
// Program structure
program ::= block*
block ::= world | belief | economy | plan | tactics
// World — map topology
world ::= 'world' '{' world_decl* '}'
world_decl ::= 'base' IDENT '=' 'base' '(' STRING ')'
| 'ramp' IDENT '=' 'ramp' '(' IDENT '->' IDENT ')'
| 'region' IDENT '=' ('choke' | 'open') '(' region_params ')'
// Belief — partial information
belief ::= 'belief' IDENT '{' belief_decl* '}'
belief_decl ::= 'track' IDENT '=' expr
| 'hypothesis' IDENT 'when' expr
| 'infer' IDENT 'from' '{' infer_fields '}'
infer_fields ::= ('rule' ':' expr)? ('quality' ':' IDENT)? ('decay' ':' expr)?
// Economy — continuous invariants
economy ::= 'economy' '{' invariant* '}'
invariant ::= 'invariant' 'never' expr
| 'invariant' 'keep' expr ('when' expr)?
// Plan — milestones and commitments
plan ::= 'plan' '{' plan_stmt* '}'
plan_stmt ::= 'commit' STRING ('confidence' expr)?
| 'milestone' STRING time_spec 'require' requirements
| 'on_miss' STRING '{' tactics_stmt* '}'
| 'pivot_to' STRING 'when' expr '{' plan_stmt* '}'
| 'cancel_milestone' STRING
time_spec ::= 'around' expr ('±' expr)? | 'asap'
requirements ::= '{' requirement* '}'
requirement ::= 'units' '{' type_counts '}' | 'building' '{' type_counts '}' | expr
type_counts ::= (IDENT ':' expr (',' IDENT ':' expr)*)?
// Tactics — groups, actions, events
tactics ::= 'tactics' '{' tactics_decl* '}'
tactics_decl ::= 'group' IDENT '=' expr
| 'on' 'event' IDENT args? '{' tactics_stmt* '}'
| 'every' expr ('while' expr)? '{' tactics_stmt* '}'
tactics_stmt ::= 'until' expr 'timeout' expr '{' tactics_stmt* '}'
| 'await' 'act' IDENT expr ('->' expr)?
| 'await' 'sleep' expr
| IDENT '=' 'try' 'act' IDENT expr ('->' expr)?
| 'match' expr '{' match_arm* '}'
| 'if' expr '{' tactics_stmt* '}' ('else' '{' tactics_stmt* '}')?
| 'race' '{' ('{' tactics_stmt* '}')+ '}'
| 'select' '{' (expr '->' '{' tactics_stmt* '}')+ '}'
| 'deviation' 'severity' IDENT expr
| expr
match_arm ::= ('ok' | 'failed' IDENT? | 'timeout') '->' '{' tactics_stmt* '}'
// Expressions
expr ::= or_expr
or_expr ::= and_expr ('or' and_expr)*
and_expr ::= cmp_expr ('and' cmp_expr)*
cmp_expr ::= add_expr (('==' | '!=' | '<' | '<=' | '>' | '>=') add_expr)?
add_expr ::= mul_expr (('+' | '-' | '±') mul_expr)*
mul_expr ::= unary_expr (('*' | '/' | '%') unary_expr)*
unary_expr ::= ('-' | 'not') unary_expr | postfix_expr
postfix_expr ::= primary ('.' IDENT args? | 'where' expr | 'within' expr 'of' expr)*
primary ::= INT | FLOAT | TIME | STRING | 'true' | 'false' | IDENT args? | '(' expr ')'
args ::= '(' (expr (',' expr)*)? ')'
// Tokens
INT ::= [0-9]+
FLOAT ::= [0-9]+ '.' [0-9]+
TIME ::= [0-9]+ ':' [0-9][0-9] // e.g., 2:30, 0:15
STRING ::= '"' [^"]* '"'
IDENT ::= [a-zA-Z_][a-zA-Z0-9_]* Example
example.sc2l
world {
base main = base("main")
base natural = base("natural")
ramp main_ramp = ramp(main -> natural)
}
economy {
invariant never supply_blocked
invariant keep workers_building when minerals >= 50
}
plan {
milestone "expand" around 2:30 ± 0:15 require {
base_count >= 2
}
on_miss "expand" {
deviation severity high "Missed expansion timing"
}
}
tactics {
group defenders = owned.units where type == Stalker
on event EnemyNear(natural) {
until threat == 0 timeout 1:00 {
await act attack_move defenders -> natural
await sleep 0:02
}
}
}