読者です 読者をやめる 読者になる 読者になる

algoNote

プログラミング関連

競プロのプレイスタイル(ソースコード的な意味で)

みなさんはプログラミングコンテストに参加するとき、ソースコードを問題ごとに分けますか?それとも1つのファイルに収めますか?

僕は1つのファイルに収める派です。(深い理由はないのですが、問題毎にファイルを切り替えるのが大変そうだからです)

この記事は1ファイラー(勝手に命名)の僕が快適にプロコンに参加するためにとってきた方法と試行錯誤についてです。

環境

方法1:main関数リネーム

#include <bits/stdc++.h>
using namespace std;
//====マクロ定義====
//-------------------------------------

signed main_C() {
    // C問題のコード
    return 0;
}

signed main_B() {
    // B問題のコード
    return 0;
}

signed main() {
    // A問題のコード
    return 0;
}

この方法は、問題を解き終えたらmain関数をリネームし、新しく作ったmain関数に次の問題を解くという感じです。実はこの方法にはいくつかの問題点があります。

  1. 前の問題に戻りたい時に、再びmain関数をリネームしなければならない (面倒くさい)
  2. グローバル変数or関数を使うと、他の問題に影響する恐れがある
  3. 提出するときに関係ない問題のコードが含まれてしまう(それを避けるために必要な部分だけをコピーするのは面倒くさい)

方法2:マクロで解く問題を指定

#include <bits/stdc++.h>
using namespace std;
//====マクロ定義====
//-------------------------------------
#define PROBLEM_A  // <--- ここではA問題を指定

#ifdef PROBLEM_C
signed main() {
    // C問題のコード
    return 0;
}
#endif

#ifdef PROBLEM_B
signed main() {
    // B問題のコード
    return 0;
}
#endif

#ifdef PROBLEM_A
signed main() {
    // A問題のコード
    return 0;
}
#endif

#defineコンパイルする問題を指定しています。
この方法は一見すると#ifdef#endifを書くのが面倒そうに見えますが、この点はAtomスニペット機能を使えば解決できます。

指定した問題のブロックだけがコンパイルされるので方法1の問題点1,2は解決出来ています。

しかし方法1の問題3は解決出来ていません。

方法2+自作パッケージ

そこで「kyopro-copy」というAtom用のパッケージを作りました。(名前は適当)
C++用です

atom.io

GitHub - algon-320/kyopro-copy: atom package.

このパッケージは、方法2において#defineで指定している問題の部分(#ifdef#endifの間)をクリップボードにコピーするというものです。

例えば、

#include <iostream>
using namespace std;
//====マクロ定義====
//-------------------------------------
#define KYOPRO_COPY_PROBLEM_A

#ifdef KYOPRO_COPY_PROBLEM_C
int main() {
    cout<<"Problem C"<<endl;
    return 0;
}
#endif

#ifdef KYOPRO_COPY_PROBLEM_B
int main() {
    cout<<"Problem B"<<endl;
    return 0;
}
#endif

#ifdef KYOPRO_COPY_PROBLEM_A
int main() {
    cout<<"Problem A"<<endl;
    return 0;
}
#endif

こんなコードを書いている状態で、いざSubmitしようという時にこのパッケージを使うと、

#include <iostream>
using namespace std;
//====マクロ定義====
//-------------------------------------

int main() {
    cout<<"Problem A"<<endl;
    return 0;
}

このように整形されたソースコードクリップボードにコピーされます。

これで上に挙げた問題は解決されました。

おまけ

おまけ機能として//SKIPBEGIN//SKIPENDで挟まれた行をコピーせずに飛ばす、という機能をつけてみました。

この機能を使うと、

#include <iostream>
using namespace std;
//====マクロ定義====
//-------------------------------------
#define KYOPRO_COPY_PROBLEM_A

#ifdef KYOPRO_COPY_PROBLEM_A
int main() {
    //SKIPBEGIN
    cout<<"local only"<<endl;
    //SKIPEND
    cout<<"Problem A"<<endl;
    return 0;
}
#endif

というコードが

#include <iostream>
using namespace std;
//====マクロ定義====
//-------------------------------------

int main() {
    cout<<"Problem A"<<endl;
    return 0;
}

の様になります。

提出時に削りたいコードを挟むことで自動的に削ってくれます。(使い道はよくわかりません)

スニペット

登録しているAtomスニペットです(signed main!)

'.source.cpp':
    'main function':
        'prefix': 'main'
        'body':'''
#ifdef KYOPRO_COPY_PROBLEM_$1
signed main() {$2
    return 0;
}
#endif
'''

    'skip':
      'prefix': 'skip'
      'body': '''
//SKIPBEGIN
$1
//SKIPEND
'''

まとめ

方法2と自作パッケージを組み合わせることで、1つのファイルで快適にプロコンに参加出来るようになりました!