✍️

【競技プログラミング】Goでテストケースをデバッグしよう!

2020/09/20に公開

Goでもテストケースを入力しながらデバッグしたい!

Goの標準デバッガであるdelveは標準入力をサポートしていません。そのため、AtCoderなどの競技プログラミングに挑む際にデバッガを使うことができず、Printデバッグで何とかしないといけません。

でも特に初心者のうちは、デバッガで一行一行追いながらデバッグしたいですよね。

そこで、ここではVisual Studio Codeを使って、Goでもデバッガを動かしながらテストケースの入力ができる方法を紹介します。

筆者の実行環境

OS : Windows10(非WSL)
Go : go1.14.6 windows/amd64
エディタ : Visual Studio Code
使用ツール : atcoder-cli,online-judge-tools

WindowsとGoで競技プログラミングをする際は、特にWSL環境まで用意しなくても大丈夫です。ただ、WSL環境で環境構築すればWindows環境は無駄に汚れませんので、余裕があればぜひチャレンジしてみてください。

atcoder-cliとonline-judge-toolsはコンテストディレクトリを作成してサンプルケースをダウンロードしてくれたり、テンプレートを用意してくれる非常に便利なツールです。ぜひ導入しておきましょう。

ソースコード

// This source codes are licensed under CC0.
// http://creativecommons.org/publicdomain/zero/1.0/deed.ja

var sc = bufio.NewScanner(os.Stdin)

func init() {
	if len(os.Args) >= 2 {
		if os.Args[1] == "debug" {
			debug()
		}
	}
	const buf = 200100
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, buf), buf)
}

func debug() {
	testFile, err := os.Open("./test/sample-1.in")
	if err != nil {
		fmt.Fprintln(os.Stderr, "There is no testfile.")
		os.Exit(1)
	}
	sc = bufio.NewScanner(testFile)
}

func readS() string {
	sc.Scan()
	return sc.Text()
}

func readR() []rune {
	return []rune(readS())
}

func readI() int {
	i, _ := strconv.Atoi(readS())
	return i
}

func readF() float64 {
	f, _ := strconv.ParseFloat(readS(), 64)
	return f
}

このコードはパブリック・ドメインですので自由にお使いください。

ここでは最低限の入力関数しか用意していません。任意の数の整数を読み込んでスライスにして返す関数など、必要に応じて用意してください。

また、本番環境とユーザ環境ともに64bitであることを前提にしています(Goのintは環境依存です)。
AtCoderは64bit環境ですので特に問題にならないと思いますが、ほかのコンテストサイトでは異なる場合があり、intがオーバーフローするなどあり得ますので、その際はInt64と明示するなどしてください。

使い方

各種入力

string, int, float64を入力する際はそれぞれreadS(), readI(), readF()を使用します。

使用例 ABC175_B

N
L_1\ L_2\ ...\ L_N
入力は全て整数

func main() {
	N := readI()
	L := make([]int, N)
	for i := 0; i < N; i++ {
		L[i] = readI()
	}
	//Do something
}

文字列はruneのスライスで扱ったほうが何かと都合がいいので、その際はreadR()を使用してください。

デバッグの仕方

Visual Studio Codeでデバッグをする際に、引数として"debug"を渡すようにします。
具体的には、launch.jsonを次のようにします。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "env": {},
            "args": ["debug"] // ここで引数を指定できる
        }
    ]
}

引数に"debug"が渡されると、標準入力ではなく、debug()関数内で指定されたファイルを読み込むようになります。

func debug() {
	testFile, err := os.Open("./test/sample-1.in") // ここで読み込むファイルを指定する
	if err != nil {
		fmt.Fprintln(os.Stderr, "There is no testfile.")
		os.Exit(1)
	}
	sc = bufio.NewScanner(testFile)
}

これで、Visual Studio CodeでF5を押すと自動的にデバッガが起動し、指定ファイルからテストケースを読み込んでくれます。
デバッグ環境以外では標準入力から読み込んでくれるので、本番提出でテストファイルがなくてエラーを起こすなんてことはありません。

繰り返しになりますが、atcoder-cliを使用すると、コンテストディレクトリを作成する際に自動的にテストケースをダウンロードしてtestディレクトリを用意してくれるのでとても便利です。

それでは良い競プロライフを!

Discussion