슈퍼루키

NYPC 2026 · 루키 트랙 파이널 라운드


N×MN \times M 크기의 격자 속에서 프레임을 읽어들이며 캐릭터를 최대 10 00010\,000번 조작하여, 맵에 있는 코인들을 최대한 수집하세요.

가이드

맵은 아래 사진과 같이 여섯 종류가 있으며, 각 종류마다 small\textrm{small}, medium\textrm{medium}, large\textrm{large}로 크기가 나뉩니다.

사진은 각 종류의 small\textrm{small} 크기 예시 맵으로, 맵 전체 사진 및 파일이 제공됩니다: 예시 맵 다운로드

전체 샘플 맵은 실제 대회 진행 시에는 제공되지 않았습니다. (다운로드)

HandcraftedChoice
Handcrafted smallChoice small
JumpPits
Jump smallPits small
PuzzleMaze
Puzzle smallMaze small

예시로 제공되는 것 외의 맵 파일이나 사진은 주어지지 않으며, 맵 생성기 또한 제공되지 않습니다. 대신, 제출할 때마다 각 종류의 small\textrm{small}, medium\textrm{medium} 맵에서 해당 코드의 플레이 로그를 받아 볼 수 있습니다. 제출 시 보여지는 맵은 모든 제출 간에 고정이며, 바뀌지 않습니다.

중간평가에서는 large\textrm{large} 맵에 대한 대표 답안의 플레이 로그도 제공됩니다. 중간평가에서는 시드를 다르게 하여 매번 새로운 맵을 생성하며, 시드로 인해 맵의 랜덤 요소가 바뀔 수 있습니다.

모든 맵들은 small\textrm{small}에서 medium\textrm{medium}, large\textrm{large}로 갈 수록 크기가 단계적으로 커지며, Handcrafted 유형을 제외한 모든 맵들은 유형별로 절차적 맵 생성에 의해 자동으로 생성됩니다. Handcrafted 유형은 맵이 고정되어 있으며, medium\textrm{medium} 및 large\textrm{large}로 크기가 커질 때마다 아래로 단계가 하나씩 추가됩니다.

플레이어는 제출 및 중간평가에서 제공되는 로그를 통해 맵을 더 자세히 파악하거나 제출한 코드를 어떻게 개선할지 살펴볼 수 있습니다.

맵

맵은 NN개의 행과 MM개의 열, 총 N×MN \times M개의 칸으로 이루어져 있습니다.

또한 각 칸은 66개의 행과 66개의 열, 총 6×66 \times 6개의 픽셀로 이루어져 있습니다.

맵에서 가장 왼쪽 위의 칸은 (0,0)(0, 0)입니다. 칸의 좌표 (i,j)(i, j)는 (행, 열)이며, 픽셀 좌표 (y,x)(y, x)와 같은 순서입니다. 칸 (i,j)(i, j)는 픽셀 좌표 (6i…6i+5,  6j…6j+5)(6i \ldots 6i{+}5,\; 6j \ldots 6j{+}5) 영역에 대응됩니다.

맵의 각 칸에는 캐릭터, 벽, 상자, 점프 블록, 코인, 가시, 보호막 아이템이 있거나, 아무것도 없는 빈 칸일 수 있습니다.

플레이어는 매 프레임마다 캐릭터를 중심으로 4848개의 열과 4848개의 행, 총 23042304개의 주변 픽셀을 볼 수 있습니다.

조작

플레이어는 매 프레임마다 명령을 출력할 수 있습니다. 한 프레임에 여러 명령을 함께 낼 수 있으며, 형식은 출력 (명령)을 따릅니다. 조건을 만족하지 않는 명령은 무시됩니다. 무시된 명령은 그 명령으로 인한 가속이나 점프를 일으키지 않으며, 같은 프레임의 다른 동작(감속, 중력, 이미 가진 속도로 인한 이동 등)은 그대로 처리됩니다.

  • 이동 방향이 벽이나 밀 수 없는 상자로 막혀 있지 않다면, 왼쪽 또는 오른쪽으로 좌우 이동을 할 수 있습니다.
  • 캐릭터의 하단이 벽/상자와 접해 있거나, 점프 블록에 겹친 상태를 점프 타임이라 합니다. 점프 타임은 매 프레임 상하 이동이 시작되기 전에 한 번 판정됩니다. 이번 프레임이 점프 타임이거나, 직전 프레임이 점프 타임이었는데 그 프레임에 점프 또는 점프 유지를 하지 않았다면, 점프를 할 수 있습니다.
  • 새 점프가 불가능한 상태라면, 직전 프레임에 점프 또는 점프 유지가 이뤄진 경우에 한해 추가로 최대 22프레임 간 점프를 유지할 수 있습니다. 점프 명령이 한 프레임이라도 끊기면 남은 유지 횟수도 사라집니다.
  • 아무 조건 없이 특수 점프를 할 수 있습니다. 단, 특수 점프를 한 프레임 수만큼 추후 비용 계산에 반영되므로 주의하여 사용해야 합니다. 특수 점프는 점프가 아니므로, 특수 점프를 한 직후의 프레임에는 점프를 유지할 수 없습니다.

캐릭터가 이동하는 과정에서 가시와 픽셀이 겹치는 순간, 보호막 개수가 양수라면 11 소모되고, 00개라면 추후 비용 계산에 반영됩니다. 또한 맵에서 해당 가시 오브젝트는 영구적으로 사라집니다.

캐릭터가 이동하는 과정에서 코인이나 보호막 아이템과 픽셀이 겹치는 순간, 해당 아이템의 개수가 11 증가합니다. 또한 맵에서 그 오브젝트는 영구적으로 사라집니다.

점프 블록은 아이템이 아니며, 캐릭터와 겹쳐도 사라지지 않습니다.

코인 개수, 보호막 개수는 처음에 00으로 시작합니다.

동작

아래에서 번호의 나열로 서술된 동작들은 번호 순서대로 처리되며, 서로 다른 두 번호의 동작이 동시에 처리되지 않음에 주의하세요.

아래에서 "부딪힌다"는 표현은 캐릭터의 이동이 멈추지 않을 시 해당 오브젝트와 겹칠 수 있는 상태를 의미합니다.

상하 이동 (점프/낙하)

이 문단에서 다루는 속도는 상하 속도입니다. 상하 이동에서 다루는 속도는 좌우 이동에서 다루는 속도와 독립적입니다. 또한, 상하 이동은 좌우 이동보다 먼저 이뤄집니다.

  1. 이번 프레임에 점프가 이뤄졌다면, (점프/점프 유지/특수 점프에 관계 없이) 캐릭터의 속도가 −3-3으로 설정됩니다.
  2. 속도가 음수라면 위로 1픽셀씩, 속도의 절대값만큼 이동을 시도합니다. 벽/상자에 부딪힐 시 이동이 멈추고, 속도가 00으로 초기화됩니다.
  3. 속도가 양수라면 아래로 1픽셀씩, 속도의 값만큼 이동을 시도합니다. 벽/상자에 부딪힐 시 이동이 멈추고, 속도가 00으로 초기화됩니다.
  4. 하단이 벽/상자와 접해 있지 않고, 이번 프레임에 점프가 이뤄지지 않았을 경우, 속도가 11 증가합니다. 단, 속도는 66을 넘지 않습니다. 조건을 만족하지 못해 무시된 점프 명령은 점프가 이뤄진 것으로 보지 않습니다.

이때, 상자 또한 낙하할 수 있습니다. 상자는 아래로 1픽셀씩 속도만큼 이동을 시도하며, 벽/상자/캐릭터에 부딪힐 시 이동이 멈추고 속도가 00으로 초기화됩니다. 하단이 벽/상자/캐릭터와 접해 있지 않으면 속도가 11 증가하며, 속도는 66을 넘지 않습니다. 공중에 뜬 직후 첫 프레임의 속도는 00이므로, 그 프레임에는 상자가 낙하하지 않습니다.

낙하는 아래쪽에 있는 개체부터 수행되며, 같은 높이에서는 캐릭터가 상자보다 먼저 처리됩니다. 따라서 여럿이 포개진 상자들이 같은 프레임에 함께 낙하할 수 있습니다.

좌우 이동

이 문단에서 다루는 속도는 좌우 속도입니다. 좌우 이동에서 다루는 속도는 상하 이동에서 다루는 속도와 독립적입니다. 또한, 좌우 이동은 상하 이동보다 나중에 이뤄집니다.

  1. 캐릭터의 속도가 00이 아닌 상황에서, 좌우 이동 명령을 내리지 않았거나, 속도와 반대 방향으로 이동 명령을 내렸다면, 속도의 절대값이 11 줄어듭니다.
  2. 플레이어가 이번 프레임에 좌우 이동 명령을 내렸다면,
    • 해당 방향으로 벽이 접해 있거나, 밀 수 없는 상자가 접해 있다면, 속도는 변하지 않으며 밀기도 일어나지 않습니다.
    • 해당 방향으로 접해 있는 상자가 없다면, 왼쪽 이동의 경우 속도가 11 감소하고, 오른쪽 이동의 경우 속도가 11 증가합니다. 단, 속도의 절대값은 44를 넘지 않습니다.
    • 해당 방향으로 밀리는 상자가 접해 있다면, 속도는 변하지 않은 채 그 상자를 같은 방향으로 1픽셀 민 뒤에 캐릭터가 1픽셀 이동합니다. 밀리는 상자들이 연속하여 붙어 있을 수 있으며, 이 경우 모든 상자가 한꺼번에 밀립니다.
  3. 속도가 음수라면 왼쪽으로 1픽셀씩, 속도의 절대값만큼 이동을 시도합니다. 벽/상자에 부딪힐 시 이동이 멈추고 속도가 00으로 초기화됩니다.
  4. 속도가 양수라면 오른쪽으로 1픽셀씩, 속도의 값만큼 이동을 시도합니다. 벽/상자에 부딪힐 시 이동이 멈추고 속도가 00으로 초기화됩니다.

상자

벽에 의해 해당 방향으로의 이동이 막히는 상자는 밀 수 없습니다. 또한, 다른 밀리지 않는 상자에 의해 막히는 상자 또한 밀 수 없습니다. 상자는 가시나 아이템에 의해 막히지 않으며, 겹칠 수 있습니다.

캐릭터와 접해 있는 밀리는 상자가 둘 이상일 시, 해당하는 모든 상자를 밉니다. 반대로, 하나라도 밀리지 않는 상자일 시, 이동/밀기는 중단됩니다.

하단이 벽/상자와 접해 있는 밀리는 상자를 밀 시, 해당 상자의 상단과 접해 있는 밀리는 상자들까지 한꺼번에 밀립니다. 이 작동은 한꺼번에 밀리는 상자들 모두에 연쇄적으로 적용됩니다. 캐릭터는 이 받침으로 보지 않습니다. 위에 얹힌 상자의 이동이 벽에 막히면 그 상자만 남고, 나머지 밀기는 그대로 이뤄집니다.

상자는 한 프레임에 1픽셀 넘게 밀리지 않습니다.

명령을 내린 시점에 상자가 접해 있지 않았을 시, 캐릭터가 상자에 부딪혀도 상자는 밀리지 않습니다.

입력

첫 번째 줄에 맵의 세로 크기 NN, 가로 크기 MM, 서브태스크 유형 SS가 공백으로 구분되어 차례대로 주어집니다. (10≤N≤50010 \le N \le 500, 10≤M≤50010 \le M \le 500, N×M≤10 000N \times M \le 10\,000, SS는 Handcrafted, Choice, Jump, Pits, Puzzle, Maze 중 하나)

이후 프레임의 정보가 두 줄씩 주어집니다. 조작 전의 시작 프레임이 먼저 주어지고, 이후 조작할 때마다 조작이 처리된 직후의 프레임이 주어집니다. FINISH를 출력하면 더 이상 프레임이 주어지지 않습니다. 각 프레임의 정보는 다음 형식을 따릅니다.

첫 번째 줄에는 현재 프레임에 보유 중인 코인 개수, 보호막 개수, 캐릭터의 좌상단 픽셀 좌표 yy, xx로 네 개의 수가 공백으로 구분되어 차례대로 주어집니다. (0≤y≤6N−60 \le y \le 6N - 6, 0≤x≤6M−60 \le x \le 6M - 6)

두 번째 줄에는 현재 프레임의 48×4848 \times 48 크기의 픽셀 출력이 인코딩되어 한 줄로 주어집니다.

픽셀 출력

문자오브젝트
@캐릭터
#벽
O상자
$코인
+점프 블록
*보호막 아이템
^가시
.빈 칸

한 픽셀에 여러 오브젝트가 겹칠 경우, 목록의 상단에 있는 것일 수록 더 위에 표시됩니다.

캐릭터, 벽, 가시, 상자, 점프 블록은 칸 전체(6×66 \times 6)를 차지합니다.

코인과 보호막 아이템은 아래와 같이 가운데 영역만 차지합니다.

......
..$$..
.$$$$.
.$$$$.
..$$..
......

......
..**..
.****.
.****.
..**..
......

인코딩

픽셀 출력은 개행을 모두 제거한 뒤, 같은 문자가 연속한 구간을 (문자)(개수) 형태로 이어서 쓴 압축입니다. 개수가 11이어도 생략하지 않으며, 개수는 한 자리보다 클 수 있습니다.

예를 들어 다음과 같은 6×66 \times 6 픽셀이 있을 때,

......
..$$..
.$$$$.
.$$$$.
..$$..
......

다음처럼 인코딩됩니다.

.8$2.3$4.2$4.3$2.8

조건

초기에 한 칸에 두 오브젝트가 동시에 또는 겹쳐서 존재하는 경우는 주어지지 않습니다.

출력 중앙 (21..26,21..26)(21..26, 21..26)에는 항상 캐릭터가 위치해 있습니다.

맵 테두리(i=0i = 0, i=N−1i = N{-}1, j=0j = 0, j=M−1j = M{-}1에 해당하는 칸)는 모두 벽입니다. 맵 바깥은 빈 칸(.)으로 표시됩니다.

맵에는 적어도 하나의 코인이 존재합니다.

서브태스크에서 Handcrafted를 제외한 모든 맵은 각 유형에 따라 절차적으로 랜덤하게 생성됩니다. Handcrafted는 맵이 바뀌지 않습니다. 생성 알고리즘은 각 유형마다 모든 중간평가에서 동일하며, 시드만 바뀝니다.

입력으로 주어지는 모든 맵은 보호막 없이 가시에 부딪히지 않으며 특수 점프를 사용하지 않고 모든 코인을 수집할 수 있음이 보장됩니다.

출력 (명령)

매 프레임마다 다음 명령 중 원하는 명령들을 골라 출력해야 합니다. 조건을 만족하지 않는 명령은 무시되며, 그 명령으로 인한 가속이나 점프는 일어나지 않습니다. 이는 올바른 출력이며, 해당 프레임은 정상적으로 진행됩니다.

명령조작
<왼쪽으로 이동
>오른쪽으로 이동
J점프/점프 유지
S특수 점프

각 프레임의 출력에 대해, 첫 줄에 FINISH 또는 선택한 명령의 개수를 44 이하의 음이 아닌 정수로 출력해야 합니다. 00을 출력하면 명령을 내지 않고 그 프레임만 진행합니다. 이후 해당 개수만큼 줄마다 명령을 출력합니다.

매 프레임의 출력을 마친 뒤에는 반드시 출력 버퍼를 비워야 합니다. 출력 버퍼를 비우는 방법에 대해서는 각 언어의 예제 코드, 또는 공식 레퍼런스 페이지를 참고하세요.

왼쪽으로 이동과 오른쪽으로 이동을 동시에 할 경우, 오른쪽으로 이동만 시도됩니다. 점프와 특수 점프를 동시에 할 경우, 특수 점프만 시도됩니다. 또한, 한 프레임에 한 종류의 명령을 여러 번 사용할 수 없습니다.

첫 줄이 FINISH도 44 이하의 음이 아닌 정수도 아닌 경우, 표에 없는 명령을 출력한 경우, 명령에 여분의 토큰이 붙은 경우, 한 프레임에 같은 종류의 명령을 두 번 이상 출력한 경우는 모두 올바르지 않은 출력이며, 채점 규칙에 따라 00점입니다.

프로그램 종료 전, 반드시 FINISH를 출력해야 함에 주의하세요. FINISH를 출력하면 그 이후 프레임은 주어지지 않으며, 프로그램은 반드시 정상적으로 실행을 종료해야 합니다. 프로그램의 제한 시간은 2초이며, 프로그램이 2초를 전부 소모하고도 FINISH를 출력하지 않으면 시간 초과로 강제 종료됩니다.

10 00010\,000번째 조작을 수행한 뒤에는 FINISH 외의 응답을 출력할 수 없습니다.

채점

올바르지 않은 출력을 한 경우, 즉 출력 형식을 맞추지 않은 경우 00점입니다.

아닌 경우, TT를 종료 시점까지 플레이어가 수행한 조작 개수, tt를 조작이 수행된 횟수, cmax⁡c_{\max}를 맵의 전체 코인 개수, ctc_t를 플레이어가 tt 시점에 수집한 코인 개수, sts_t를 tt 시점까지 특수 점프 명령을 낸 프레임 수, hth_t를 tt 시점까지 보호막 없이 가시에 부딪힌 횟수라고 할 때 비용이 다음과 같은 방법으로 정해집니다.

  • Cost(t)=⌊(1−ctcmax⁡+st+ht)×106⌋\textrm{Cost(t)} = \left\lfloor\left(1 - \dfrac{c_t}{c_{\max}+s_t+h_t}\right) \times 10^6\right\rfloor
  • Cost=min⁡t=0TCost(t)\textrm{Cost} = \displaystyle\min_{t=0}^{T}{\textrm{Cost(t)}}
  • 비용이 낮을수록 더 좋은 결과입니다.

이때의 각 테스트케이스의 점수는 다음과 같은 방법으로 정해집니다.

  • 전체 참가자의 수: ntotn_\textrm{tot}
  • 자신보다 비용이 낮은 참가자의 수: nlosen_\textrm{lose}
  • 자신과 비용이 같은 다른 참가자의 수: ndrawn_\textrm{draw}
  • Score=⌊106(1−0.5nlose+0.5ndrawntot)⌋\textrm{Score} = \left\lfloor 10^6 \left(1 - 0.5\sqrt{\dfrac{n_\textrm{lose} + 0.5 n_\textrm{draw}}{n_\textrm{tot}}}\right) \right\rfloor

챌린지 문제의 최종 점수는 최종 평가에 사용된 각 테스트 케이스 점수의 평균이 됩니다. 비슷하게, 중간 평가의 점수는 중간 평가에 사용된 각 테스트 케이스 점수의 평균이 되며, 이 점수는 참고용으로 최종 점수에 반영되지 않습니다. 평가에는 예제 코드보다 낮은 비용을 받은 제출만 채점됩니다.

문제의 점수는 각 테스트 케이스 별로 매겨지며, 최종 점수는 테스트 케이스별 점수의 평균으로 계산됩니다.

중간 평가 데이터

각 중간 평가마다 66개 유형(Handcrafted, Choice, Jump, Pits, Puzzle, Maze)과 33개 크기(small\textrm{small}, medium\textrm{medium}, large\textrm{large})의 모든 조합에 대해 맵이 11개씩, 총 1818개의 테스트 케이스가 사용됩니다. 이 1818개 테스트 케이스에 대한 플레이 로그가 제공됩니다.

최종 평가 데이터

최종 평가 역시 같은 1818개 조합에 대해 채점하며, 모든 유형·크기에 대해 2020개의 데이터로 채점합니다.

CLI 툴

CLI 툴 다운로드

위 CLI 툴을 활용하여 로컬에서 AI를 실행시켜볼 수 있습니다.

시뮬레이터

시뮬레이터에서는 맵 파일을 업로드하여 직접 플레이해보거나, 로그 파일을 업로드하여 재생해볼 수 있습니다. 제공된 맵 파일이나 제출 및 중간평가에서 제공되는 로그 파일만 쓸 필요는 없으며, 직접 만든 맵 파일이나, 자신의 컴퓨터에서 실행한 로그도 사용 가능합니다.

예제 코드

대회에서 지원하는 각 언어로 작성된 예제 코드를 아래에서 확인할 수 있습니다.

파일 형식

로그

플레이어는 CLI 툴 또는 채점을 통해 게임이 진행된 로그를 받을 수 있습니다. 해당 파일은 시뮬레이터에서도 재생 가능합니다.

로그의 첫 번째 줄에는 맵의 세로 크기 NN, 가로 크기 MM, 서브태스크 유형 SS, 플레이어가 수행한 조작 개수 TT가 공백으로 구분되어 차례대로 주어집니다.

두 번째 줄부터 플레이어가 각 프레임 사이에 출력한 명령이 출력 (명령) 형식과 동일한 형식으로 주어집니다. 실행을 끝내는 FINISH는 조작이 아니므로 기록되지 않습니다.

이후 플레이어에게 전송된 프레임 T+1T+1개의 정보가 차례대로 주어집니다. 각 프레임의 형식은 다음과 같습니다.

첫 번째 줄에는 해당 프레임에 보유 중인 코인 개수, 보호막 개수, 캐릭터의 좌상단 픽셀 좌표 yy, xx로 네 개의 수가 공백으로 구분되어 차례대로 주어집니다.

두 번째 줄에는 해당 프레임의 48×4848 \times 48 크기의 픽셀 출력이 인코딩되어 한 줄로 주어집니다.

맵

첫 번째 줄에 맵의 세로 크기 NN, 가로 크기 MM, 서브태스크 유형 SS가 공백으로 구분되어 차례대로 주어집니다. (10≤N≤50010 \le N \le 500, 10≤M≤50010 \le M \le 500, N×M≤10 000N \times M \le 10\,000, SS는 Handcrafted, Choice, Jump, Pits, Puzzle, Maze 중 하나)

두 번째 줄부터 NN개의 줄에 걸쳐 줄마다 픽셀 문자로 이뤄진 길이 MM의 문자열이 주어집니다. 각 문자는 해당 위치의 셀에 있는 오브젝트를 의미합니다. 초기에 한 셀에 두 오브젝트가 동시에 또는 겹쳐서 존재하는 경우는 없습니다.