😎

VSCodeでNimのAtCoder環境を構築

に公開

Pythonライクで処理速度の速いAtCoderに最適な言語の1つNimの環境構築について、ご参考までに書いておきます。

環境の前提

  • Windows
  • WSL2
  • VSCode

皆さん、基本はC++やPythonなどを使っていて、完全にNimにスイッチするわけではないでしょう。
ぜひ、この機会にDockerの導入を検討ください。
コンテナごとに環境を持てて、非常に快適です。
VSCodeのdevcontainerでAtCoder環境を構築という記事も、あわせてご覧ください。

インストール(Dockerfile)

ここではDockerfileとして挙げておきますが、そうでなくても、(見ればわかると思いますが)WORKDIR → cdと読み替えて、RUN以下のコマンドを打っていけばいいだけです。
Dockerfileとしては、基本はubuntunに、2023年の言語アップデート時の提案シート通りにinstall commandを書いただけ。
みんな大好きonline-judge-tools(まだ、コンテスト中は使えますから…)も入れてあります。
(online-judge-toolsについては、このDockerfileを使ったVSCodeのdevcontainer内でsubmitしても、結果表示のブラウザが立ち上がらなかったので、submit.pyのshow resultのところのutils.webbrowser_register_explorer_exe()の行をコメントアウトして使っています。)
Nim Language Serverが開発され、LLVMで高度なデバッグができるよ、ということのようですが、わたくしにはうまく使いこなせませんでしたので、コメントアウトしてあります…

Dockerfile_AtCoder-Nim
FROM ubuntu:22.04

# Nim
RUN apt update && apt install -y curl xz-utils g++ git build-essential time
RUN curl https://nim-lang.org/choosenim/init.sh -sSf | bash -s -- -y
ENV PATH=/root/.nimble/bin:$PATH

# neo
RUN nimble install neo -y

# OpenBLAS
RUN apt install libopenblas-base -y

# Nim-ACL
RUN nimble install https://github.com/zer0-star/Nim-ACL

# bignum
RUN nimble install bignum -y

# Nim Language Server 
RUN nimble install nimlangserver -y

# LLVM
#RUN apt install clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python3-clang -y

# gbd
RUN apt install -y gdb

# online-judge-tools
RUN apt install -y python3-pip &&\
    #pip3 install online-judge-tools
    pip3 install git+https://github.com/sukenori/oj.git

# Docker
RUN apt install -y docker.io

参考①(devcontainer.json)

あくまで、VSCodeのdevcontainerでAtCoder環境を構築の通りのディレクトリ構造にしたら、こうなりますよ、という参考として挙げておきます。

devcontainer.json
{
  "name": "AtCoder-Nim",
  "build": {
    "dockerfile": "Dockerfile_AtCoder-Nim"
  },
  "workspceMount": "source=C:/Users/ユーザー名/OneDrive/Development/Competitive_Programming/Workspaces/AtCoder/AtCoder-Nim,target=/workspaces/AtCoder-Nim,type=bind",
  "workspaceFolder": "/workspaces/AtCoder-Nim",
  "mounts": [
    "source=C:/Users/ユーザー名/OneDrive/Development/Competitive_Programming/Solved_Code,target=/workspaces/Solved_Code,type=bind",
    "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
  ],
  "customizations": {
    "vscode": {
      "extensions": [
        "NimLang.nimlang",
        //"vadimcn.vscode-lldb",
        "GitHub.copilot",
        "GitHub.copilot-chat",
        "ms-azuretools.vscode-docker"
      ]
    }
  },
  "postCreateCommand": "./.devcontainer/postCreateCommand.sh"
}

参考②(postCreateCommand.sh)

文字通り、コンテナクリエイト後に走るスクリプトですので、ojのログインなんかをします。
2023年の言語アップデート時点では、Nimは1.6.14ですので、choosenim 1.6.14としてダウングレードしておいてもいいと思います。

postCreateCommand.sh
#!/bin/bash
RUN choosenim 1.6.14
oj login -u ログイン名 -p パスワード https://atcoder.jp/

参考③(.code-workspace)

さっきマウントしておいたディレクトリで、ワークスペースを構成します。
(提出コード集部分は一例です。)
コンテストが終わったら、.Contesutから中身を移していったりします。

AtCoder-Nim.code-workspace
{
	"folders": [
		{
			"name": "AtCoder-Nim",
			"path": "/workspaces/AtCoder-Nim"
		},
		{
			"name": "AtCoder_Beginner_Contest",
			"path": "/workspaces/Solved_Code/AtCoder/AtCoder_Beginner_Contest"
		},
		{
			"name": "AtCoder_Regular_Contest",
			"path": "/workspaces/Solved_Code/AtCoder/AtCoder_Regular_Contest"
		},
		{
			"name": "AtCoder_Grand_Contest",
			"path": "/workspaces/Solved_Code/AtCoder/AtCoder_Grand_Contest"
		},
		{
			"name": "ABC_Like_Contest",
			"path": "/workspaces/Solved_Code/AtCoder/ABC_Like_Contest"
		},
		{
			"name": "ARC_Like_Contest",
			"path": "/workspaces/Solved_Code/AtCoder/ARC_Like_Contest"
		}
	],
	"settings": {
		"terminal.integrated.env.linux": {
			"PATH": "${env:PATH}:/workspaces/AtCoder/.workspaces/Nim"
		}
	}
}

tasks.json

ojの自動化を導入するので、コンパイル、テストのダウンロード、テスト、提出の各taskを用意します。
コンパイルオプションは、これもしつこく言語アップデート時の提案シートに揃えてみたりしています。
(汚らしいですが、デバッグを試みた跡がコメントアウトしてあります。)
コンパイルをデフォルトのタスクにして、提出のタスクにショーカットをつければ、その2つのショートカットでほぼほぼCLI要らずになります。というのも、提出のタスクは、testディレクトリの削除→サンプルケースのダウンロード→テスト→提出のコンボにしてあるからです。URL渡しは、サンプルケースのダウンロード時に、出てくるウィンドウに問題文URLをコピペするだけです(Chrome拡張機能を使うとさらにいい感じです)。

tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "nim build",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "type": "shell",
            "command": "${userHome}/.nimble/bin/nim",
            "args": [
                "cpp",
                //"c",
                "-d:release",
                "--opt:speed",
                "--multimethods:on",
                //"--warning[SmallLshouldNotBeUsed]:off",
                "--hints:off",
                "-o:a.out",
                "${file}",
                //"-g",
                //"--cc:clang",
                //"--debuginfo:on"
                //"--cc:gcc",
                //"--debugger:native"
            ],
            "presentation": {
                "panel": "shared"
            }
        },
        {
            "label": "remove test",
            "type": "shell",
            "command": "rm",
            "args": [
                "-rf",
                "${workspaceFolder}/test"
            ],
            "presentation": {
                "panel": "shared"
            }
        },
        {
            "label": "download test",
            "type": "shell",
            "command": "oj",
            "args": [
                "d",
                "${input:url}",
                "-d",
                "${workspaceFolder}/test",
                "-s"
            ],
            "presentation": {
                "panel": "shared",
                "showReuseMessage": false
            },
            "dependsOn": ["remove test"],
            "dependsOrder": "sequence"
        },
        {
            "label": "test",
            "type": "shell",
            "command": "oj",
            "args": [
                "t",
                "-c",
                "${workspaceFolder}/a.out",
                "-d",
                "${workspaceFolder}/test/"
            ],
            "presentation": {
                "panel": "shared"
            }
        },
        {
            "label": "nim submit",
            "type": "shell",
            "command": "oj",
            "args": [
                "s",
                "${input:url}",
                "${file}",
                "-w",
                "0",
                "-y"
            ],
            "presentation": {
                "panel": "shared"
            },
            "dependsOn": ["nim build","download test","test"],
            "dependsOrder": "sequence"
        },
    ],
    "inputs": [
        {
            "type":"promptString",
            "id":"url",
            "description": "URL of the task"
        }
    ]
}

尊敬する優秀なNim使いの皆さんによって、Nim-ACLも整備され、非常に快適な環境が整えられています。
それだけに、後は、実力だけなんですよね…

Discussion