문제 안내

자원을 모으고 숨은 계약을 완성하는 Duel 봇을 작성하세요. 기본 명성과 계약 보너스를 합쳐 총점 20에 도달하는 것이 목표입니다.

승리 목표와 판정

자원 토큰으로 목적지 카드를 구매하면 카드 색의 영구 할인을 얻습니다. 조건을 만족하면 후원자를 방문합니다. 총점 20 이상에 도달하면 같은 라운드의 양쪽 행동 횟수를 맞춘 뒤 종료합니다.

모든 정상 종료는 높은 총점, 높은 기본 명성, 구매한 목적지 카드가 더 적은 순서로 판정합니다. 세 기준이 정확히 같으면 무승부입니다. 120턴 제한과 교착에도 같은 기준을 적용하며 최종 동률이면 무승부입니다. 예약 카드 수와 좌석은 동률 판정에 사용하지 않습니다. 할인 합과 보유 토큰 수도 사용하지 않습니다.

활성 좌석의 합법 행동이 0개이면 서버가 봇을 호출하지 않고 그 턴을 자동 패스해 리플레이에 기록합니다. 실제 행동이 나오면 연속 패스 수를 초기화하고, 양쪽 좌석이 연속 자동 패스하면 deadlock으로 종료합니다. pass는 서버 전용이므로 봇이 직접 반환하면 잘못된 행동입니다.

숨은 계약 6종

매 경기 돌진·엔진·계획 계열에서 하나씩 제시된 세 후보 중 하나를 선택합니다. 보너스는 최대 6점이며 기본 명성과 더해 총점이 됩니다.

자기 계약은 시작 단계에서 기억하세요. 경기 중 관측에는 양쪽 계약·보너스·진행도·총점을 넣지 않습니다. 완료 리플레이에서만 양쪽 후보·선택·진행도·최종 점수를 공개합니다. 공식 리플레이는 전체 tick 완료 후 볼 수 있습니다. 선후공 두 경기는 같은 초기 배치와 좌석별 후보를 사용하고 두 팀이 자리를 바꿉니다.

시장과 예약

시장은 3단계마다 공개 카드 각 4장을 유지하고 후원자 3개를 공개합니다. 예약 공간은 3장이며 예약 행동은 한 경기 3회로 제한됩니다. 공개 덱의 보이는 카드를 예약하거나 비공개 덱 맨 위를 예약할 수 있습니다. 가능한 경우 골드 토큰을 받고, 보유 한도를 넘으면 토큰을 반납해야 합니다.

봇 제출 규격

제출물은 Python으로 작성한 단일 UTF-8 bot.py이며 최대 65,536바이트입니다. 프로세스는 JSON Lines로 통신합니다. start에 {"type":"ready","protocol_version":"grand-tour-jsonl-v2"}로 응답한 뒤 choose_contract에 {"type":"contract_choice","contract_id":"후보 ID"}를 반환합니다. contract_assignment의 자기 계약을 기억하고 {"type":"contract_ready"}로 확인합니다. 재시작에서는 선택 없이 할당부터 받을 수 있습니다. 이후 매 턴 legal_actions 중 정확히 하나를 반환합니다. 표준 출력(stdout)은 프로토콜 메시지에만 사용하고 진단은 표준 오류(stderr)에 기록하세요. 같은 준비 단계에서 두 봇이 모두 실패하면 양쪽 0점이며 일반 무승부는 양쪽 0.5점입니다.

기본 코드에서 수정할 함수

봇 제출 편집기의 완전한 기본 코드를 사용하세요. 아래 함수만 바꾸어 계약과 행동을 선택할 수 있습니다. 통신과 토큰 반환 처리는 기본 코드에 있습니다.

def choose_contract(choices):
    return choices[0]["id"]

def choose_action(observation):
    return observation["legal_actions"][0]

제출에서 공식 경기까지

  1. 제출 — 서버가 파일과 SHA-256을 기록합니다.
  2. 검증 — 규격과 실행 가능성을 검사합니다.
  3. 연습 완료 — 기준 상대 6종을 선공과 후공으로 만나 12경기를 완료합니다. 통과 조건은 12승이 아닙니다.
  4. 대표 승격 — 검증된 제출을 팀 대표로 활성화합니다.
  5. 적용 — 승격 뒤 시작하는 다음 15분 구간부터 공식 대회에 참가합니다.