たこすの競プロライブラリメモ

C++の個人的競プロライブラリです。99%拝借。

atcoder-cliでコンテスト期間中に問題の追加があった場合の対応

要約

・コンテスト期間中に問題追加された場合は、contest.acc.jsonを直接編集し、$ acc add --force コマンドを実施する。

背景

E869120氏主催の「競プロ典型90問」を、AtCoderのジャッジを利用して挑戦中。

qiita.com

atcoder.jp

普段自分はatcoder-clionline-judge-toolsの併用で、テストケースのチェックなど一括で実施中。
しかし、「競プロ典型90問」は毎日一題ずつ追加される仕様のため、atcoder-cliの新規コンテスト追加では追加された問題に対応不可能であった。

今回はcontest.acc.jsonの編集により、コンテスト中の問題追加への対応を行った。

問題追加の方法

既存の問題追加は$ acc add コマンドで行えるが、このコマンドでは今回のケースに対応できない。
なぜならacc addはコンテストの仕様をダウンロードした際の問題数しか登録されておらず、途中で問題が増えても新規の問題には対応できない(ようだ)。
helpを読むと、$ acc add --force で上書きはできるようだが、追加問題の上書きは達成できず。

そこでcontest.acc.jsonを直接編集し、$ acc add --forceを行うことで、問題を無理やり追加することに成功した。

contest.acc.jsonの編集

contest.acc.jsonは以下のような構成である。

{
  "contest": {
    "id": "typical90",
    "title": "競プロ典型 90 問",
    "url": "https://atcoder.jp/contests/typical90"
  },
  "tasks": [
    {
      "id": "typical90_a",
      "label": "001",
      "title": "Yokan Party(★4)",
      "url": "https://atcoder.jp/contests/typical90/tasks/typical90_a",
      "directory": {
        "path": "001",
        "testdir": "tests",
        "submit": "main.cpp"
      }
    },
    {
      "id": "typical90_b",
      "label": "002",
      "title": "Encyclopedia of Parentheses(★3)",
      "url": "https://atcoder.jp/contests/typical90/tasks/typical90_b",
      "directory": {
        "path": "002",
        "testdir": "tests",
        "submit": "main.cpp"
      }
    }, /*以下略*/
 ] 
}

連番がaからzまであり、次はaaからazまで、その次はbaからbzに変化する構成である。
最初は、手作業でコピペしていたが、30問あたりから面倒に感じたため、半自動で生成するコードを作製した。(C++で作成)
※21/5/7追記:さすがに冗長だったため、まとめられるところをまとめた。

#include <bits/stdc++.h>
using namespace std;

typedef long long int ll;

#define REPS(i, x) for (ll i = 1; i <= (ll)(x); i++)

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    REPS(i, 90)
    {
        if (i <= 26)
        {
            char ch = i + 'Z'+6;
            printf("    {\n");
            printf("      \"id\": \"typical90_%c\",\n", ch);
            printf("      \"label\": \"%03lld\",\n", i);
            printf("      \"title\": \"xxx\",\n");
            printf("      \"url\": \"https://atcoder.jp/contests/typical90/tasks/typical90_%c \",\n", ch);
        }
        else if(i<=52){
            char ch = i + 'Z' + 6-26;
            printf("    {\n");
            printf("      \"id\": \"typical90_a%c\",\n", ch);
            printf("      \"label\": \"%03lld\",\n", i);
            printf("      \"title\": \"xxx\",\n");
            printf("      \"url\": \"https://atcoder.jp/contests/typical90/tasks/typical90_a%c\",\n", ch);
        }
        else if(i<=78){
            char ch = i + 'Z' + 6 - 52;
            printf("    {\n");
            printf("      \"id\": \"typical90_b%c\",\n", ch);
            printf("      \"label\": \"%03lld\",\n", i);
            printf("      \"title\": \"xxx\",\n");
            printf("      \"url \": \"https://atcoder.jp/contests/typical90/tasks/typical90_b%c\",\n", ch);
        }
        else{
            char ch = i + 'Z' + 6 - 78;
            printf("    {\n");
            printf("      \"id\": \"typical90_c%c\",\n", ch);
            printf("      \"label\": \"%03lld\",\n", i);
            printf("      \"title\": \"xxx\",\n");
            printf("      \"url\": \"https://atcoder.jp/contests/typical90/tasks/typical90_c%c\",\n", ch);
        }
        printf("      \"directory\": {\n");
        printf("        \"path\": \"%03lld\",\n", i);
        printf("        \"testdir\": \"tests\",\n");
        printf("        \"submit\": \"main.cpp\"\n");
        printf("      }\n");
        printf("    },\n");
    }
}

もっとキレイに書きたかったが、仕方なく原始的な場合分けを行った。
問題タイトルのスクレイピング能力はないため、問題が追加され次第自分でコピペしてaccコマンドを実施する。