自己写的刷题用脚本介绍、分享
自己写的刷题用脚本介绍、分享
Updates: 2024/10/20:改了一处bug
前言
貌似替代方法一大堆?但我就想自己写。
目前主要针对的是 OI 赛制的模拟赛,会有这方面的专门功能,但也有不少日常刷题的好用功能。
脚本在最下面,以 MIT 协议开源,目前只有 powershell(Linux 马上写)。
功能介绍
先说明一下这些脚本的功能:
- 最基础的编译和运行代码
- 在本地编译时去掉 freopen(具体是在文件做全局替换,从 "freopen" 到 "//freopen",编译完再改回来)
- 本地测样例的时候用的临时文件输入输出(不是改代码,而是在运行的时候临时用某个文件输入输出)
- 非常舒服的文件管理(写这个的主要原因)
- 自动测大样例
- 可以看到运行时间、内存和返回值,较为美观(可能吧。。。)
- 即使在控制台输入输出,快读模板也不用改,输入样例的时间也不算在运行时间里
文件管理
文件夹的组织结构是这样:
- 源代码可以随便放
- 样例都放到 test/ 目录下
- 编译完的文件放在 bin/ 目录下
- 把脚本放在 tools/ 目录下
使用方法
脚本包含两个文件:
compile.ps1
用于编译源代码(默认开 -O2 和 -g 选项,栈空间设为 512MB,其他选项和洛谷保持一致),在编译的时候会自动去掉代码中的 freopen,本地测试时无需注释掉 freopen,使用时这样调用:
tools/compile.ps1 [源代码路径(不要.cpp)]
# 例如:
tools/compile.ps1 P1000 # 会编译当前目录的 p1000.cpp 文件
tools/compile.ps1 match/20240230/T1 # 会编译 match/20240230/T1.cpp 文件
run.ps1
用于运行代码,文件输入输出和大样例测试也在里面。
- 注意:如果要用控制台输入输出,输入用空行表示结束,这里脚本实际上会把控制台的输入保存到 test/input.txt ,输出保存到 test/output.txt ,所以不应该使用这两个文件保存任何需要保持的数据
对于普通的运行,可以这样调用,会自动运行上一次编译的代码,如果 RE 给出返回值,否则给出运行输出、时间和内存占用:
tools/run.ps1
如果要加文件输入输出,可以这样调用:
tools/run.ps1 in [inputfile] out [outputfile]
# 不加读入或不加输出也是可以的,会自动加上test/的目录名和.in/.out的扩展名,例如:
tools/run.ps1 in bargain out bargain
# 读入 test/bargain.in 输出 test/bargain.out
tools/run.ps1 in bargain
# 读入 test/bargain.in 输出到控制台
tools/run.ps1 out bargain
# 读入控制台 输出到 test/bargain.out
tools/run.ps1 in bargain out
# 特殊用法:out后不接任何东西会输出到 test/output.txt,注意此时不可以写成 out in bargain
如果要测大样例,可以这样调用:
tools/run.ps1 test [样例名的匹配模式]
# 例如:
tools/run.ps1 test bargain*
# 会在 test/ 目录下匹配 bargain*.in/.ans/.out 这个模式的所有文件。
# 如 bargain1.in bargain1.ans bargain2.in bargain2.ans 等。
# 自动执行文件输入输出,代码中无需 freopen(即使加了 freopen 也会在编译的时候自动去掉)
# 可以识别到AC和WA和RE,并给出相应的颜色
# WA的时候会给出差异,RE的时候会给出返回值
# 虽然测不出TLE和MLE,但可以看到时间和内存消耗。
# 执行完后给出分数(100 * AC测试点 / 所有测试点)
脚本代码
tools/compile.ps1
# The MIT License (MIT)
# Copyright © 2024 marscheng
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
$bin_dir = Split-Path -Parent "./bin/$args"
if (-not (Test-Path $bin_dir)) {
New-Item -ItemType Directory -Force -Path $bin_dir | Out-Null
}
$source_file = "$args.cpp"
(Get-Content -Path $source_file) |`
ForEach-Object { $_ -Replace 'freopen', '//freopen' } |`
Set-Content -Path $source_file
g++ -x c++ -std=c++14 "-Wl,--stack=536870912" -g -O2 -DONLINE_JUDGE -Wall -fno-asm `
-lm -march=native -o "./bin/$args" "$args.cpp"
(Get-Content -Path $source_file) |`
ForEach-Object { $_ -Replace '//freopen', 'freopen' } |`
Set-Content -Path $source_file
$LAST_COMPILE = $args
tools/run.ps1
# The MIT License (MIT)
# Copyright © 2024 marscheng
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
$comand = (".\bin\" + $LAST_COMPILE + ".exe")
if ("test" -in $args) {
$input_file = [string]$args[($args.IndexOf("test") + 1)]
$test_input = [System.IO.Directory]::GetFiles(".\test\", $input_file + ".in")
$test_answer = [System.IO.Directory]::GetFiles(".\test\", $input_file + ".ans") + `
[System.IO.Directory]::GetFiles(".\test\", $input_file + ".out")
$ac_num = 0
for ($i = 0; $i -lt $test_input.Length; $i++) {
Write-Host "Test case $([string]($i + 1))"
Write-Host "Input file: $(Split-Path -Leaf $test_input[$i])"
Write-Host "Answer file: $(Split-Path -Leaf $test_answer[$i])"
$processOptions = @{
FilePath = $comand
RedirectStandardInput = $test_input[$i]
RedirectStandardOutput = ".\test\output.txt"
NoNewWindow = $true
PassThru = $true
}
$process = Start-Process @processOptions
$handle = $process.Handle
$memory = ($process.PrivateMemorySize64 / 1MB)
$process.WaitForExit()
if ($process.ExitCode -ne 0) {
Write-Host -ForegroundColor Magenta `
"Runtime Error: return value: $($process.ExitCode)"
continue
}
$total_time = $process.ExitTime - $process.StartTime
fc.exe /A /W ".\test\output.txt" $test_answer[$i] | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host -ForegroundColor Green `
"Test case $([string]($i + 1)) Accepted"
Write-Host -ForegroundColor Green `
"Time used: $($total_time.TotalSeconds) seconds"
Write-Host -ForegroundColor Green `
"Memory used: $memory MB`n"
$ac_num += 1
}
else {
Write-Host -ForegroundColor Red "Test case $([string]($i + 1)) Wrong Answer"
fc.exe /A /W /N ".\test\output.txt" $test_answer[$i]
}
}
Write-Host "Total Socre: $(100.0 * [float]$ac_num / [float]$test_input.Length)"
}
else {
if ("in" -in $args) {
$input_file = [System.IO.Directory]::GetFiles(".\test\", `
[string]$args[($args.IndexOf("in") + 1)] + ".in")[0]
}
else {
$input_file = "test/input.txt"
New-Item $input_file -ItemType File -Force | Out-Null
while ($true) {
$input_line = Read-Host
if ($input_line -eq "") {
break;
}
Add-Content $input_file $input_line
}
}
if ("out" -in $args -and ($args.IndexOf("out") + 1) -le $args.Length - 1) {
$output_file = ".\test\" + [string]$args[($args.IndexOf("out") + 1)] + ".out"
}
else {
$output_file = ".\test\output.txt"
}
$processOptions = @{
FilePath = $comand
RedirectStandardInput = $input_file
RedirectStandardOutput = $output_file
NoNewWindow = $true
PassThru = $true
}
$start_time = Get-Date
$process = Start-Process @processOptions
$handle = $process.Handle
$memory = ($process.PrivateMemorySize64 / 1MB)
$process.WaitForExit()
$total_time = $process.ExitTime - $process.StartTime
if (-not ("out" -in $args)) {
Get-Content $output_file | Out-Host
}
if ($process.ExitCode -eq 0) {
Write-Host "`nTotal time: $($total_time.TotalSeconds) seconds"
Write-Host "Memory used: $memory MB"
}
else {
Write-Host -ForegroundColor Magenta `
"`nRuntime Error: return value: $($process.ExitCode)"
}
}
写在最后
第一次写文章,写得不好,还请各位大佬指教。
如果有什么问题,或者有什么建议,欢迎在评论区提出,比较有用的新功能我会尽快加上。
目前这个只有 powershell 的版本(在学校用windows),家里用的 linux 版本下周可能会更新。