0%

以最优雅的方式做算法竞赛

自从在大学入坑了ICPC这类算法比赛,就沉迷其中,在集训队的时候花上一整天做各种各样的比赛,写各种各样的题目,日常的话,也会在深夜打开codeforces,参加一场场的掉分赛/(ㄒoㄒ)/~~

LifeGoals

刚开始写比赛的时候,用的IDE是Dev C++,这款IDE上手简单,对新手比较友好,但是调试能力较弱;之后改用CodeBlocks,相对而言功能更加丰富,可自定义的地方也比较多,但麻烦之处在于需要建工程,以及对我来说,调试相当不友好,UI也比较丑;也见过有人使用Visual Studio,不过庞大的体量让我瞬间失去了用它做题的想法。

除了IDE本身的缺陷,还有一个比较难以忍受的共性问题是,竞赛的输入输出是分开的,区分十分清晰,但选手在编写程序的时候,需要在终端里同时完成输入输出,难免会产生混乱,如果在代码中使用了重定向,又需要分心去管理重定向的事情,就有点舍本逐末了。

综上,理想中算法竞赛刷题工具应有以下几个便利点:

  1. 允许单文件编译运行,使得做一道题目不需要大费周章的建立工程,只需要一个单文件。
  2. 界面美观,友好,调试方便。
  3. 直接重定向到文件。

一番摸索之后,我选择的工具是vscode,主要是基于一下几点考虑:

  1. 界面美观。
  2. 编辑器可自由拖拽,观看方便。
  3. 拥有大量插件,功能高度自定义。

于是,踏上了配置之旅。

想看简易配置过程直接拉到最后。

效果展示

效果图

主要功能:

  • 源代码放在 src 文件夹中,编译生成的可执行程序在 bin 文件夹中,用于重定向的输入输出文件放在 data 中,vscode的配置文件放在 .vscode 中。
  • 在一个源文件中编写完程序之后按下F5一键编译运行,程序重定向输入自data.in,重定向输出至data.out中。
  • 可自由选择需要编译的源文件,各个文件之间不冲突。

配置思路

本配置是从官方的配置魔改而来,先贴一下官方的 task.jsonlaunch.json 两个配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// task.json
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": [
"-g",
"-o",
"helloworld",
"helloworld.cpp"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/helloworld.exe",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

不难看出,task.json中的build hello world任务是调用了g++命令,而它的参数是 -g -o helloworld helloworld.cpp,即编译helloworld.cpplaunch.json则是在编译完后调试 ${workspaceFolder} 目录下的helloworld.exe

而我们希望的功能是编译任意一个单源文件,并重定向输入输出。在task中需要指定编译文件的路径,vscode提供了几个预定义的宏变量用来表示路径。

宏

那么,可以通过 ${file} 来表示正在编辑的文件路径,使用 ${workspaceFolder} 加上相对路径以及 ${fileBasenameNoExtension} 来指定生成可执行文件的路径与名称。那么,假如源文件都在src文件夹中,希望生成的可执行文件都在bin中,则task.json中的args参数修改为

1
2
3
4
"args": [
"-g", "${file}",
"-o", "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe"
]

而重定向则可以由 >< 来进行,假如希望重定向的文件都在data文件夹中,输入文件为data.in,输出文件为data.out,则launch.json中的programargs参数修改为

1
2
3
4
5
6
7
"program": "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe",
"args": [
"<",
"${workspaceFolder}/data/data.in",
">",
"${workspaceFolder}/data/data.out"
]

大功告成。

简易配置过程

  1. 按照官方教程或者我之前的文章配置好一个C/C++编程环境。

  2. 在工作目录下新建bindatasrc三个文件夹,将源文件放入src文件夹中,可执行文件放入bin中。

  3. data文件夹中新建两个文本文件,分别为data.indata.out。此时工作区的文件结构为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    |--.vscode
    | --c_cpp_properties.json
    | --launch.json
    | --settings.json
    | --tasks.json
    |--bin
    | --helloworld.exe
    |--data
    | --data.in
    | --data.out
    |-src
    | --helloworld.cpp
  4. 修改task.json中的参数args

    1
    2
    3
    4
    "args": [
    "-g", "${file}",
    "-o", "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe"
    ]

    此时task.json应该类似于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    {
    "version": "2.0.0",
    "tasks": [
    {
    "label": "build hello world",
    "type": "shell",
    "command": "g++",
    "args": [
    "-g",
    "${file}",
    "-o",
    "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe"
    ],
    "group": {
    "kind": "build",
    "isDefault": true
    }
    }
    ]
    }
  5. 修改launch.json中的参数programargs

    1
    2
    3
    4
    5
    6
    7
    "program": "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe",
    "args": [
    "<",
    "${workspaceFolder}/data/data.in",
    ">",
    "${workspaceFolder}/data/data.out"
    ]

    此时launch.json应该类似于:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    {
    "version": "0.2.0",
    "configurations": [{
    "name": "(gdb) Launch",
    "type": "cppdbg",
    "request": "launch",
    "program": "${workspaceFolder}/bin/${fileBasenameNoExtension}.exe",
    "args": [
    "<",
    "${workspaceFolder}/data/data.in",
    ">",
    "${workspaceFolder}/data/data.out"
    ],
    "stopAtEntry": true,
    "cwd": "${workspaceFolder}",
    "environment": [],
    "externalConsole": false,
    "MIMode": "gdb",
    "miDebuggerPath": "C:/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/gdb.exe",
    "setupCommands": [
    {
    "description": "Enable pretty-printing for gdb",
    "text": "-enable-pretty-printing",
    "ignoreFailures": true
    }
    ]
    }
    ]}
  6. 配置完成,拖拽编辑器到合适的位置

  7. 编辑完代码后,按下F5一键编译运行,程序将重定向输入自data/data.in,重定向输出至data.out

  8. 保存一份配置好的文件夹作为模板,后续需要做比赛的时候复制一份。

后续

本次配置难度不是很大,灵活使用vscode的宏变量进行配置,也比较好理解。最终的结果满足了我打比赛的需求,不过还是存在一下几点问题:

  1. 每次使用都需要重新设置一下布局,虽然不是很麻烦但是很繁琐。
  2. 无法识别编辑文件的文件类型,如果在修改了data.in后直接编译,会报错。

好了,开开心心掉分去QAQ。

如果帮到了你的话,可以考虑请我喝咖啡