Compare commits
No commits in common. "main" and "v1.0" have entirely different histories.
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,12 +1,6 @@
|
|||||||
# Editor
|
# Editor
|
||||||
.vscode/
|
.vscode/
|
||||||
*.swp
|
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
test*
|
test*
|
||||||
test/
|
test/
|
||||||
|
|
||||||
# Executables & Builds
|
|
||||||
*.exe
|
|
||||||
*.pch
|
|
||||||
*.o
|
|
||||||
|
|||||||
34
NOTICE
34
NOTICE
@ -1,34 +0,0 @@
|
|||||||
Licenses for third party components used by this project can be found below.
|
|
||||||
|
|
||||||
================================================================================
|
|
||||||
The BSL-1.0 License applies to:
|
|
||||||
|
|
||||||
* optional lite in `libvmake/optional.hpp`
|
|
||||||
Copyright (c) 2014-2021 Martin Moene
|
|
||||||
in GitHub repository martinmoene/optional-lite (https://github.com/martinmoene/optional-lite)
|
|
||||||
|
|
||||||
Boost Software License - Version 1.0 - August 17th, 2003 (BSL-1.0)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person or organization
|
|
||||||
obtaining a copy of the software and accompanying documentation covered by
|
|
||||||
this license (the "Software") to use, reproduce, display, distribute,
|
|
||||||
execute, and transmit the Software, and to prepare derivative works of the
|
|
||||||
Software, and to permit third-parties to whom the Software is furnished to
|
|
||||||
do so, all subject to the following:
|
|
||||||
|
|
||||||
The copyright notices in the Software and this entire statement, including
|
|
||||||
the above license grant, this restriction and the following disclaimer,
|
|
||||||
must be included in all copies of the Software, in whole or in part, and
|
|
||||||
all derivative works of the Software, unless such copies or derivative
|
|
||||||
works are solely in the form of machine-executable object code generated by
|
|
||||||
a source language processor.
|
|
||||||
|
|
||||||
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
||||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
================================================================================
|
|
||||||
|
|
||||||
165
README.md
165
README.md
@ -1,14 +1,14 @@
|
|||||||
# py-Vtest
|
# py-Vtest
|
||||||
|
|
||||||
](https://img.shields.io/github/license/ZTL-UwU/py-vtest?style=flat-square)
|
](https://img.shields.io/github/license/zhangtianli2006/py-vtest?style=flat-square)
|
||||||

|

|
||||||
|
|
||||||
An OI test-data maker & std test tool.
|
An OI test-data maker & std test tool.
|
||||||
|
|
||||||
## Mode
|
## Mode
|
||||||
|
|
||||||
1. **vmake**: Automatically generate test-data with user-provided standard solution and Maker (described below).
|
1. **vmake**: Automatically generate test-data with user-provided std and Maker (described below).
|
||||||
2. **vcheck**: Execute a solution on set of test-data like an OnlineJudge does.
|
2. **vcheck**: Judge a solution like a OnlineJudge does.
|
||||||
**WARNING: No sandbox protection, don't run any untrusted code!**
|
**WARNING: No sandbox protection, don't run any untrusted code!**
|
||||||
|
|
||||||
## Maker
|
## Maker
|
||||||
@ -51,25 +51,25 @@ A Maker is an executable that generates the input of a single test case.
|
|||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
.
|
.
|
||||||
├─ <data path> // Auto Generated
|
|- <data path> // Auto Generated
|
||||||
│ ├─ <name>.1.1.in
|
| |- <name>.1.1.in
|
||||||
│ ├─ <name>.1.1.out
|
| |- <name>.1.1.out
|
||||||
│ ├─ ...
|
| |- ...
|
||||||
│ ├─ <name>.<subtask count>.<n>.in
|
| |- <name>.<subtask count>.<n>.in
|
||||||
│ └─ <name>.<subtask count>.<n>.out
|
| |- <name>.<subtask count>.<n>.out
|
||||||
│
|
|
|
||||||
├─ mk_<name> // Compile yourself
|
|- mk_<name> // Compile yourself
|
||||||
├─ std_<name> // Compile yourself
|
|- std_<name> // Compile yourself
|
||||||
├─ run_<name> // Compile yourself
|
|- run_<name> // Compile yourself
|
||||||
├─ vmake.py // Downloaded
|
|- vmake.py // Downloaded
|
||||||
└─ vcheck.py // Downloaded
|
|- vcheck.py // Downloaded
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Here is a example of generating test-data of the _A + B problem_ and testing a solution of it.
|
Here is a example of generating test-data of the _A + B problem_ and testing a solution of it.
|
||||||
|
|
||||||
1. Create an empty folder.
|
1. Make an empty folder.
|
||||||
2. Create `vtest.conf` with the following content:
|
2. Create `vtest.conf` with the following content:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
@ -81,22 +81,22 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
|
|||||||
|
|
||||||
3. Download `vmake.py` and `vcheck.py`.
|
3. Download `vmake.py` and `vcheck.py`.
|
||||||
|
|
||||||
You can use the following commands if you prefer CLI or simply click `Download Zip` in the project repository page and extract `vmake.py` and `vcheck.py`:
|
You can use these commands if you are a command-line user:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/ZTL-UwU/py-vtest/raw/main/vmake.py
|
wget https://github.com/zhangtianli2006/py-vtest/raw/main/vmake.py
|
||||||
wget https://github.com/ZTL-UwU/py-vtest/raw/main/vcheck.py
|
wget https://github.com/zhangtianli2006/py-vtest/raw/main/vcheck.py
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Create a standard solutoion as an executable named `std_AplusB`.
|
4. Create an executable named `std_AplusB`.
|
||||||
|
|
||||||
For example, the following code is a C++ version of a standard solution of _A + B problem_, compile it into `std_AplusB`:
|
For example, here is a C++ version of it, just compile it:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// std_AplusB.cpp
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
long long a, b;
|
long long a, b;
|
||||||
std::cin >> a >> b;
|
std::cin >> a >> b;
|
||||||
std::cout << a + b;
|
std::cout << a + b;
|
||||||
@ -104,33 +104,28 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Compile commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
g++ std_AplusB.cpp -o std_AplusB
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Create an executable named `mk_AplusB` which is a Maker (described above).
|
5. Create an executable named `mk_AplusB` which is a Maker (described above).
|
||||||
|
|
||||||
For example, the following is a C++ version of the test-data Maker, compile it into `mk_AplusB`:
|
For example, here is a C++ version of it, just compile it:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// mk_AplusB.cpp
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
int subtask_id;
|
int subtask_id;
|
||||||
std::cin >> subtask_id;
|
std::cin >> subtask_id;
|
||||||
|
|
||||||
if (subtask_id == 1) {
|
if (subtask_id == 1)
|
||||||
|
{
|
||||||
std::mt19937 rng(std::random_device{}());
|
std::mt19937 rng(std::random_device{}());
|
||||||
std::cout << rng() << " " << rng();
|
std::cout << rng() << " " << rng();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subtask_id == 2) {
|
if (subtask_id == 2)
|
||||||
// In this subtask, we will generate larger inputs
|
{
|
||||||
// which can hack solutions without using long long.
|
// In this subtask, we will try to hack solutions without using long long
|
||||||
std::mt19937_64 rng(std::random_device{}());
|
std::mt19937_64 rng(std::random_device{}());
|
||||||
std::cout << rng() << " " << rng();
|
std::cout << rng() << " " << rng();
|
||||||
}
|
}
|
||||||
@ -139,36 +134,28 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Compile commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
g++ mk_AplusB.cpp -o mk_AplusB
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Run `vmake.py`.
|
6. Run `vmake.py`.
|
||||||
|
|
||||||
You can use the following command or simply double-click on `vmake.py`:
|
You can use these commands if you are a command-line user:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 vmake.py
|
python3 vmake.py
|
||||||
```
|
```
|
||||||
|
|
||||||
The output is similar to the following:
|
The program outputs like this:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
Start Making data for AplusB.
|
|
||||||
|
|
||||||
Making subtask #1
|
Making subtask #1
|
||||||
[ 10%] Made case #1.1: (9.0ms)
|
[10%] Made case #1.1: (9.0ms)
|
||||||
[ 20%] Made case #1.2: (2.17ms)
|
[20%] Made case #1.2: (2.17ms)
|
||||||
[ 30%] Made case #1.3: (5.08ms)
|
[30%] Made case #1.3: (5.08ms)
|
||||||
[ 40%] Made case #1.4: (2.53ms)
|
[40%] Made case #1.4: (2.53ms)
|
||||||
[ 50%] Made case #1.5: (4.01ms)
|
[50%] Made case #1.5: (4.01ms)
|
||||||
[ 60%] Made case #1.6: (3.81ms)
|
[60%] Made case #1.6: (3.81ms)
|
||||||
Making subtask #2
|
Making subtask #2
|
||||||
[ 70%] Made case #2.1: (1.99ms)
|
[70%] Made case #2.1: (1.99ms)
|
||||||
[ 80%] Made case #2.2: (3.06ms)
|
[80%] Made case #2.2: (3.06ms)
|
||||||
[ 90%] Made case #2.3: (2.04ms)
|
[90%] Made case #2.3: (2.04ms)
|
||||||
[100%] Made case #2.4: (3.4ms)
|
[100%] Made case #2.4: (3.4ms)
|
||||||
|
|
||||||
Summary:
|
Summary:
|
||||||
@ -179,23 +166,23 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
|
|||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├─ data
|
|- data
|
||||||
| ├─ AplusB.1.1.in
|
| |- AplusB.1.1.in
|
||||||
| ├─ AplusB.1.1.out
|
| |- AplusB.1.1.out
|
||||||
| ├─ ...
|
| |- ...
|
||||||
| ├─ AplusB.2.4.in
|
| |- AplusB.2.4.in
|
||||||
| └─ AplusB.2.4.out
|
| |- AplusB.2.4.out
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Lets try another solution without using `long long` (who cannot pass the test).
|
7. Lets try another solution without using `long long` (who cannot pass the test).
|
||||||
|
|
||||||
This is a C++ version of a wrong solution, compile it into `run_AplusB`:
|
This is a C++ version of it, just compile it to `run_AplusB`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// AplusB_wrong.cpp
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
int a, b;
|
int a, b;
|
||||||
std::cin >> a >> b;
|
std::cin >> a >> b;
|
||||||
std::cout << a + b;
|
std::cout << a + b;
|
||||||
@ -203,53 +190,35 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Compile commands:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
g++ AplusB_wrong.cpp -o run_AplusB
|
|
||||||
```
|
|
||||||
|
|
||||||
8. Run `vcheck.py`
|
8. Run `vcheck.py`
|
||||||
|
|
||||||
You can use the following command or simply double-click on `vcheck.py`:
|
You can use these commands if you are a command-line user:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 vcheck.py
|
python3 vcheck.py
|
||||||
```
|
```
|
||||||
|
|
||||||
The output is similar to the following:
|
The program may outputs like this:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
Start checking subtask #1
|
Start checking subtask #1
|
||||||
[ 10%] Case #1.1: Answer Correct (2.56ms)
|
[10%] Case #1.1: Answer Correct (2.56ms)
|
||||||
[ 20%] Case #1.2: Answer Correct (2.33ms)
|
[20%] Case #1.2: Answer Correct (2.33ms)
|
||||||
[ 30%] Case #1.3: Answer Correct (2.6ms)
|
[30%] Case #1.3: Answer Correct (2.6ms)
|
||||||
[ 40%] Case #1.4: Answer Correct (7.18ms)
|
[40%] Case #1.4: Answer Correct (7.18ms)
|
||||||
[ 50%] Case #1.5: Answer Correct (2.22ms)
|
[50%] Case #1.5: Answer Correct (2.22ms)
|
||||||
[ 60%] Case #1.6: Answer Correct (2.24ms)
|
[60%] Case #1.6: Answer Correct (2.24ms)
|
||||||
Start checking subtask #2
|
Start checking subtask #2
|
||||||
[ 70%] Case #2.1: Wrong Answer (3.17ms)
|
[70%] Case #2.1: Wrong Answer (3.17ms)
|
||||||
[ 80%] Case #2.2: Wrong Answer (2.85ms)
|
[80%] Case #2.2: Wrong Answer (2.85ms)
|
||||||
[ 90%] Case #2.3: Wrong Answer (2.28ms)
|
[90%] Case #2.3: Wrong Answer (2.28ms)
|
||||||
[100%] Case #2.4: Wrong Answer (2.76ms)
|
[100%] Case #2.4: Wrong Answer (2.76ms)
|
||||||
|
|
||||||
Summary: WA
|
Summary: WA
|
||||||
Total time: 30.2ms
|
Total time: 30.2ms
|
||||||
Slowest case: #1.4 (7.18ms)
|
Slowest case: #1.4 (7.18ms)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
AC: 6 [ 60%]
|
AC: 6 [60%]
|
||||||
WA: 4 [ 40%]
|
WA: 4 [40%]
|
||||||
RE: 0 [ 0%]
|
RE: 0 [0%]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Todo
|
|
||||||
|
|
||||||
1. Add `.exe` suffix on Windows in `vcheck.py` and `vhack.py`. (see #2)
|
|
||||||
1. Introduce `vhack.py` in README.
|
|
||||||
1. Add a `zh-cn` version of the README introduction.
|
|
||||||
1. Extract shared codes in `vmake.py`, `vhack.py` and `vcheck.py`.
|
|
||||||
1. Auto generate subtask configuration files for HustOJ, LibraOJ, HydroOJ and more (maybe `vconf.py` ?).
|
|
||||||
1. Use command-line arguments rather that fixed `std_xxx`, `mk_xxx` stuff.
|
|
||||||
1. Check inputs with a codeforces styled validator (maybe `vvalidate.py` ?).
|
|
||||||
1. Write an introduction and documention about libvmake.
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::concat(vmake::range(1, 3)
|
|
||||||
, vmake::range(1, 4), vmake::range(1, 4, 2)));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
// equivlant to vmake::range(2, 11, 2)
|
|
||||||
struct my_sequence {
|
|
||||||
using result = int;
|
|
||||||
|
|
||||||
int p;
|
|
||||||
my_sequence() : p(2) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return p > 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator()() {
|
|
||||||
p += 2;
|
|
||||||
return p - 2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
static_assert(vmake::is_sequence_t<my_sequence>::value, "my_sequence is not a valid sequence!");
|
|
||||||
vmake::outputln(cout, " ", my_sequence{});
|
|
||||||
vmake::outputln(cout, " ", vmake::range(2, 11, 2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::discard_n(vmake::range(1, 10), 2));
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
#include <bits/stdc++.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::output(cout, vmake::nothing<string>());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::filter(vmake::range(1, 10), [](int x) {
|
|
||||||
return x % 2 == 0;
|
|
||||||
}), '\n');
|
|
||||||
vmake::outputln(cout, " ", vmake::take(vmake::filter(vmake::iota(1), [](int x) {
|
|
||||||
return x <= 5;
|
|
||||||
}), 5));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln_n(cout, 5, " ", vmake::transform(vmake::group<2>(vmake::iota(1)), [](auto x) {
|
|
||||||
return get<0>(x) * get<1>(x);
|
|
||||||
}));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vector<string> a{"HELLO", "WORLD", "!"};
|
|
||||||
vmake::outputln(cout, " ", vmake::transform(vmake::extract(a.begin(), a.end()), [](auto &&s) {
|
|
||||||
std::transform(s.cbegin(), s.cend(), s.begin(), [] (auto c) { return std::tolower(c); });
|
|
||||||
return s;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
int n;
|
|
||||||
cin >> n;
|
|
||||||
vmake::output_n(cout, n, " ", vmake::transform(vmake::extract(istream_iterator<int>(cin)), [](int x) {
|
|
||||||
return x * x;
|
|
||||||
}));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln_n(cout, 1000, " ", vmake::filter(
|
|
||||||
vmake::rng::uniform_ints(vmake::require_unique, 1, 10000),
|
|
||||||
[](auto x) { return x % 2 == 0; }));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::take(vmake::rng::uniform_ints(1, 10), 15));
|
|
||||||
vmake::outputln(cout, " ", vmake::take(vmake::rng::uniform_ints(vmake::require_unique, 1, 20), 15));
|
|
||||||
vmake::outputln(cout, " ", vmake::take(vmake::rng::uniform_reals(1., 10.), 5));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::repeat_n("hello", 5));
|
|
||||||
vmake::outputln_n(cout, 5, " ", vmake::repeat("world"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
#include "../vmake.hpp"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
vmake::outputln(cout, " ", vmake::transform(vmake::zip(vmake::range(1, 10)
|
|
||||||
, vmake::range(2, 10, 2)), [](const auto &x) {
|
|
||||||
return std::get<0>(x) + std::get<1>(x);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,825 +0,0 @@
|
|||||||
#ifndef _VTEST_VMAKE_HPP
|
|
||||||
#define _VTEST_VMAKE_HPP
|
|
||||||
|
|
||||||
#include <bits/stdc++.h>
|
|
||||||
|
|
||||||
#if __cplusplus < 201703L
|
|
||||||
#include "optional.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace vmake {
|
|
||||||
|
|
||||||
using std::size_t;
|
|
||||||
|
|
||||||
struct require_unique_t {} require_unique;
|
|
||||||
|
|
||||||
struct sequence_terminated_error : std::exception {
|
|
||||||
virtual const char *what() const noexcept override final {
|
|
||||||
return "iterating on a terminated sequence.";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace polyfill {
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
|
|
||||||
using std::optional;
|
|
||||||
using std::as_const;
|
|
||||||
using std::apply;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
using nonstd::optional;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
constexpr typename std::add_const<T>::type& as_const(T& t) noexcept {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> void as_const(const T&&) = delete;
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Func, typename Tuple, size_t ...index>
|
|
||||||
decltype(auto) apply_helper(Func &&f, Tuple &&t, std::index_sequence<index...>) {
|
|
||||||
return f(std::get<index>(std::forward<Tuple>(t))...);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Func, typename Tuple>
|
|
||||||
decltype(auto) apply(Func &&f, Tuple &&t) {
|
|
||||||
return details::apply_helper(std::forward<Func>(f), std::forward<Tuple>(t)
|
|
||||||
, std::make_index_sequence<std::tuple_size<
|
|
||||||
typename std::decay<Tuple>::type>::value>());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace polyfill
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
auto is_sequence_helper(char) -> decltype(
|
|
||||||
std::declval<T>()()
|
|
||||||
, typename std::enable_if<std::is_same<decltype(
|
|
||||||
std::declval<typename std::add_const<T>::type>().is_terminated())
|
|
||||||
, bool>::value, int>::type{0}
|
|
||||||
, typename std::enable_if<std::is_same<decltype(std::declval<T>()())
|
|
||||||
, typename T::result>::value, int>::type{0}
|
|
||||||
, std::true_type{});
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
auto is_sequence_helper(int) -> std::false_type;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
using is_sequence_t = decltype(details::is_sequence_helper<T>(' '));
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct iota_sequence {
|
|
||||||
using result = T;
|
|
||||||
|
|
||||||
T start;
|
|
||||||
iota_sequence(T&& start) : start(std::forward<T>(start)) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
return start++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct ranged_sequence {
|
|
||||||
using result = T;
|
|
||||||
|
|
||||||
T start, end;
|
|
||||||
ranged_sequence(T&& start, T&& end)
|
|
||||||
: start(std::forward<T>(start)), end(std::forward<T>(end)) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return !(start < end);
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
if (start == end) throw sequence_terminated_error();
|
|
||||||
return start++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct ranged_step_sequence {
|
|
||||||
using result = T;
|
|
||||||
|
|
||||||
T start, end, step;
|
|
||||||
ranged_step_sequence(T&& start, T&& end, T&& step)
|
|
||||||
: start(std::forward<T>(start)), end(std::forward<T>(end))
|
|
||||||
, step(std::forward<T>(step)) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return !(start < end);
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
if (start == end) throw sequence_terminated_error();
|
|
||||||
T res = start;
|
|
||||||
start += step;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Val>
|
|
||||||
inline auto iota(Val &&start) {
|
|
||||||
return details::iota_sequence<typename std::decay<Val>::type>(std::forward<Val>(start));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Val>
|
|
||||||
inline auto range(Val &&start, Val &&end) {
|
|
||||||
return details::ranged_sequence<typename std::decay<Val>::type>(std::forward<Val>(start)
|
|
||||||
, std::forward<Val>(end));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Val>
|
|
||||||
inline auto range(Val &&start, Val &&end, Val &&step) {
|
|
||||||
return details::ranged_step_sequence<typename std::decay<Val>::type>(
|
|
||||||
std::forward<Val>(start), std::forward<Val>(end), std::forward<Val>(step));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct empty_sequence {
|
|
||||||
using result = T;
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
T operator()() {
|
|
||||||
throw sequence_terminated_error();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline auto nothing() {
|
|
||||||
return details::empty_sequence<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename ContIt>
|
|
||||||
struct ranged_iterator_extractor {
|
|
||||||
using result = typename std::remove_reference<decltype(*std::declval<ContIt>())>::type;
|
|
||||||
|
|
||||||
ContIt cur, end;
|
|
||||||
bool added;
|
|
||||||
|
|
||||||
ranged_iterator_extractor(const ContIt &begin, const ContIt &end) : cur(begin)
|
|
||||||
, end(end), added(false) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return cur == end;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
// WARN: use for strange iterators such as std::istream_iterator
|
|
||||||
// do NOT try to optimize this into *it++
|
|
||||||
if (cur == end) throw sequence_terminated_error();
|
|
||||||
if (added) return *++cur;
|
|
||||||
added = true;
|
|
||||||
return *cur;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ContIt>
|
|
||||||
struct iterator_extractor {
|
|
||||||
using result = typename std::remove_reference<decltype(*std::declval<ContIt>())>::type;
|
|
||||||
|
|
||||||
ContIt it;
|
|
||||||
bool added;
|
|
||||||
|
|
||||||
iterator_extractor(const ContIt &begin) : it(begin), added(false) {};
|
|
||||||
|
|
||||||
constexpr bool is_terminated() const noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
// WARN: use for strange iterators such as std::istream_iterator
|
|
||||||
// do NOT try to optimize this into *it++
|
|
||||||
if (added) return *++it;
|
|
||||||
added = true;
|
|
||||||
return *it;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename ContIt>
|
|
||||||
inline auto extract(const ContIt &begin, const ContIt &end) {
|
|
||||||
return details::ranged_iterator_extractor<ContIt>(begin, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ContIt>
|
|
||||||
inline auto extract(const ContIt &begin) {
|
|
||||||
return details::iterator_extractor<ContIt>(begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ContIt>
|
|
||||||
inline auto extract_n(const ContIt &begin, size_t n) {
|
|
||||||
return take(details::iterator_extractor<ContIt>(begin), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Func>
|
|
||||||
struct generator {
|
|
||||||
using result = decltype(std::declval<Func>()());
|
|
||||||
|
|
||||||
Func g;
|
|
||||||
|
|
||||||
generator(Func &&g) : g(std::forward<Func>(g)) {}
|
|
||||||
generator(const Func &g) : g(g) {}
|
|
||||||
|
|
||||||
generator(generator<Func> &&y) = default;
|
|
||||||
generator(const generator<Func> &y) = default;
|
|
||||||
|
|
||||||
constexpr bool is_terminated() const noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
return g();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Func, typename... Args>
|
|
||||||
inline auto make_generator(Args&&... args) {
|
|
||||||
return details::generator<Func>(std::move(Func(std::forward<Args>(args)...)));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Func>
|
|
||||||
inline constexpr auto generate(Func &&f) {
|
|
||||||
return details::generator<typename std::decay<Func>::type>(std::forward<Func>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Gen>
|
|
||||||
struct limitor {
|
|
||||||
using core = Gen;
|
|
||||||
using result = typename Gen::result;
|
|
||||||
|
|
||||||
Gen g;
|
|
||||||
size_t lim;
|
|
||||||
limitor(Gen &&g, size_t lim) : g(std::move(g)), lim(lim) {}
|
|
||||||
limitor(limitor<Gen> &&g) = default;
|
|
||||||
limitor(const limitor<Gen> &g) = default;
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return lim <= 0 || g.is_terminated();
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
if (lim-- > 0) return g();
|
|
||||||
else throw sequence_terminated_error();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Gen>
|
|
||||||
inline auto take(Gen &&g, size_t lim) {
|
|
||||||
return details::limitor<typename std::decay<decltype(g)>::type>(std::forward<Gen>(g), lim);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Tval>
|
|
||||||
struct repeater {
|
|
||||||
using result = Tval;
|
|
||||||
|
|
||||||
Tval x;
|
|
||||||
repeater(Tval &&x) : x(std::forward<Tval>(x)) {};
|
|
||||||
repeater(const repeater<Tval>&) = default;
|
|
||||||
repeater(repeater<Tval> &&) = default;
|
|
||||||
|
|
||||||
constexpr bool is_terminated() const noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tval operator()() const {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Tval>
|
|
||||||
inline auto repeat(Tval &&x) {
|
|
||||||
return details::repeater<typename std::decay<Tval>::type>(std::forward<Tval>(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tval>
|
|
||||||
inline decltype(auto) repeat_n(Tval &&x, size_t n) {
|
|
||||||
return take(repeat(std::forward<Tval>(x)), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
inline constexpr bool concat_terminate_helper() noexcept {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Seq, typename ...Seqs>
|
|
||||||
inline bool concat_terminate_helper(Seq& f, Seqs& ...rest) noexcept {
|
|
||||||
if (!f.is_terminated()) return false;
|
|
||||||
return concat_terminate_helper(rest...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tuple, size_t ...index>
|
|
||||||
inline auto concat_terminate_applier(Tuple &t, std::index_sequence<index...>) noexcept {
|
|
||||||
return polyfill::apply(concat_terminate_helper<
|
|
||||||
typename std::tuple_element<index, Tuple>::type...>, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Seq, typename ...Seqs>
|
|
||||||
inline decltype(auto) concat_call_helper(Seq& f, Seqs& ...rest) {
|
|
||||||
if (f.is_terminated()) return concat_call_helper(rest...);
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Seq>
|
|
||||||
inline decltype(auto) concat_call_helper(Seq &f) {
|
|
||||||
return f();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tuple, size_t ...index>
|
|
||||||
inline decltype(auto) concat_call_applier(Tuple &t, std::index_sequence<index...>) {
|
|
||||||
return polyfill::apply(concat_call_helper<
|
|
||||||
typename std::tuple_element<index, Tuple>::type...>, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Gen1, typename ...Gen>
|
|
||||||
struct concator {
|
|
||||||
using result = typename Gen1::result;
|
|
||||||
using core = std::tuple<Gen1, Gen...>;
|
|
||||||
|
|
||||||
core g;
|
|
||||||
|
|
||||||
concator(Gen1&& g1, Gen&&... g2) : g(std::forward<Gen1>(g1), std::forward<Gen>(g2)...) {}
|
|
||||||
concator(concator<Gen1, Gen...>&&) = default;
|
|
||||||
concator(const concator<Gen1, Gen...>&) = default;
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return concat_terminate_applier(g, std::make_index_sequence<sizeof...(Gen) + 1>());
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
return concat_call_applier(g, std::make_index_sequence<sizeof...(Gen) + 1>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename ...Gen>
|
|
||||||
inline constexpr auto concat(Gen&&... g) noexcept {
|
|
||||||
return details::concator<typename std::decay<Gen>::type...>(std::forward<Gen>(g)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Gen, typename Func>
|
|
||||||
struct transformer {
|
|
||||||
using result = decltype(std::declval<Func>()(std::declval<typename Gen::result>()));
|
|
||||||
using core = Gen;
|
|
||||||
|
|
||||||
Gen g;
|
|
||||||
Func f;
|
|
||||||
|
|
||||||
transformer(Gen &&g, Func &&gf) : g(std::move(g)), f(std::move(f)) {}
|
|
||||||
transformer(transformer<Gen, Func> &&c) = default;
|
|
||||||
transformer(const transformer<Gen, Func> &c) = default;
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return g.is_terminated();
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
return f(g());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Gen, typename Func>
|
|
||||||
inline auto transform(Gen &&g, Func &&f) {
|
|
||||||
return details::transformer<typename std::decay<Gen>::type
|
|
||||||
, typename std::decay<Func>::type>(std::forward<Gen>(g)
|
|
||||||
, std::forward<Func>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Gen, typename Pred>
|
|
||||||
struct filteror {
|
|
||||||
using result = typename Gen::result;
|
|
||||||
using core = Gen;
|
|
||||||
|
|
||||||
filteror(filteror<Gen, Pred> &&) = default;
|
|
||||||
filteror(const filteror<Gen, Pred> &) = default;
|
|
||||||
|
|
||||||
mutable Gen g;
|
|
||||||
Pred p;
|
|
||||||
mutable polyfill::optional<result> preview;
|
|
||||||
|
|
||||||
filteror(Gen &&g, Pred &&p) : g(std::forward<Gen>(g)), p(std::forward<Pred>(p)) {
|
|
||||||
_find_next();
|
|
||||||
};
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
if (g.is_terminated() && !preview.has_value()) return true;
|
|
||||||
if (!preview.has_value()) _find_next();
|
|
||||||
return !preview.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
if (is_terminated()) throw sequence_terminated_error();
|
|
||||||
result res = std::move(*preview);
|
|
||||||
preview.reset();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _find_next() const {
|
|
||||||
preview.reset();
|
|
||||||
do {
|
|
||||||
if (g.is_terminated()) {
|
|
||||||
preview.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
preview.emplace(std::move(g()));
|
|
||||||
} while (!p(polyfill::as_const<result>(*preview)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Gen, typename Pred>
|
|
||||||
inline filteror<typename std::decay<Gen>::type
|
|
||||||
, typename std::decay<Pred>::type> filter(Gen &&g, Pred &&p) {
|
|
||||||
return {std::forward<Gen>(g), std::forward<Pred>(p)};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
//template<typename ...Ts>
|
|
||||||
//using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
|
|
||||||
|
|
||||||
template<typename Tp, size_t n, size_t ...index>
|
|
||||||
auto repeat_tuple_builder(std::index_sequence<index...> seq)
|
|
||||||
-> std::tuple<typename std::enable_if<(void(index), true), Tp>::type...>;
|
|
||||||
|
|
||||||
template<typename Tp, size_t n>
|
|
||||||
struct repeat_tuple_t {
|
|
||||||
using type = decltype(repeat_tuple_builder<Tp, n>(std::make_index_sequence<n>()));
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Gen, size_t ...index>
|
|
||||||
inline auto group_builder(Gen &g, std::index_sequence<index...> seq) {
|
|
||||||
auto val = std::array<typename Gen::result, seq.size()>{
|
|
||||||
(void(index), g())...
|
|
||||||
};
|
|
||||||
return std::make_tuple(std::move(std::get<index>(val))...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Gen, size_t n>
|
|
||||||
struct grouper {
|
|
||||||
static_assert(n > 0, "");
|
|
||||||
using result = typename repeat_tuple_t<typename Gen::result, n>::type;
|
|
||||||
using core = Gen;
|
|
||||||
|
|
||||||
Gen g;
|
|
||||||
|
|
||||||
grouper(grouper<Gen, n>&& g) = default;
|
|
||||||
grouper(const grouper<Gen, n>& g) = default;
|
|
||||||
grouper(Gen &&g) : g(std::forward<Gen>(g)) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return g.is_terminated();
|
|
||||||
}
|
|
||||||
|
|
||||||
result operator()() {
|
|
||||||
return group_builder<Gen>(g, std::make_index_sequence<n>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<size_t n, typename Gen>
|
|
||||||
inline auto group(Gen &&g) {
|
|
||||||
return details::grouper<typename std::decay<Gen>::type, n>(std::forward<Gen>(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Gen>
|
|
||||||
inline decltype(auto) discard_n(Gen &&g, size_t n) {
|
|
||||||
for (size_t i = 0; i < n; ++i) g();
|
|
||||||
return std::forward<Gen>(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Gen, size_t ...index>
|
|
||||||
auto zipper_call_helper(Gen &&g, std::index_sequence<index...>) {
|
|
||||||
return std::make_tuple(std::get<index>(g)()...);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline constexpr bool zip_terminate_helper() noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Seq, typename ...Seqs>
|
|
||||||
inline bool zip_terminate_helper(Seq& f, Seqs& ...rest) noexcept {
|
|
||||||
if (f.is_terminated()) return true;
|
|
||||||
return zip_terminate_helper(rest...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tuple, size_t ...index>
|
|
||||||
inline auto zip_terminate_applier(Tuple &t, std::index_sequence<index...>) noexcept {
|
|
||||||
return polyfill::apply(zip_terminate_helper<
|
|
||||||
typename std::tuple_element<index, Tuple>::type...>, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Gen>
|
|
||||||
struct zipper {
|
|
||||||
private:
|
|
||||||
static constexpr auto _n = std::tuple_size<Gen>::value;
|
|
||||||
using _make_index = std::make_index_sequence<_n>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using result = decltype(zipper_call_helper(std::declval<Gen>(), _make_index()));
|
|
||||||
using core = Gen;
|
|
||||||
|
|
||||||
Gen g;
|
|
||||||
|
|
||||||
zipper(zipper<Gen> &&) = default;
|
|
||||||
zipper(const zipper<Gen> &) = default;
|
|
||||||
|
|
||||||
zipper(Gen &&g) : g(std::forward<Gen>(g)) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return zip_terminate_applier(g, _make_index());
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(auto) operator()() {
|
|
||||||
return zipper_call_helper(g, _make_index());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename ...Gen>
|
|
||||||
inline decltype(auto) zip(Gen&&... g) {
|
|
||||||
using Tuple = std::tuple<typename std::decay<Gen>::type...>;
|
|
||||||
return details::zipper<Tuple>(std::make_tuple(std::forward<Gen>(g)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace rng {
|
|
||||||
|
|
||||||
inline auto make_seed() {
|
|
||||||
// NOTE: MinGW GCC older than 9.2 have a fixed random_device
|
|
||||||
#if defined(__GNUC__) && defined(_WIN32) && __GNUC__ * 100 + __GNUC_MINOR__ <= 902
|
|
||||||
return std::chrono::steady_clock::now().time_since_epoch().count();
|
|
||||||
#else
|
|
||||||
return std::random_device{}();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Engine = std::default_random_engine>
|
|
||||||
inline auto common() {
|
|
||||||
return make_generator<Engine>(make_seed());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Engine, typename Seed>
|
|
||||||
inline auto common(Seed seed) {
|
|
||||||
return make_generator<Engine>(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
struct cstyle_rng {
|
|
||||||
using result = decltype(std::rand());
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator()() {
|
|
||||||
return std::rand();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto cstyle() {
|
|
||||||
std::srand(time(0));
|
|
||||||
std::rand();
|
|
||||||
return details::cstyle_rng();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto cstyle(unsigned seed) {
|
|
||||||
std::srand(seed);
|
|
||||||
std::rand();
|
|
||||||
return details::cstyle_rng();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tval = int, typename Engine = std::default_random_engine>
|
|
||||||
inline auto uniform_ints(Tval &&l, Tval &&r) {
|
|
||||||
return generate([rng = Engine(make_seed())
|
|
||||||
, dis = std::uniform_int_distribution<typename std::decay<Tval>::type>(
|
|
||||||
std::forward<Tval>(l), std::forward<Tval>(r))]() mutable {
|
|
||||||
return dis(rng);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Tval, typename Engine>
|
|
||||||
struct unique_ints_sequence {
|
|
||||||
using result = Tval;
|
|
||||||
|
|
||||||
unique_ints_sequence(unique_ints_sequence<Tval, Engine> &&) = default;
|
|
||||||
unique_ints_sequence(const unique_ints_sequence<Tval, Engine> &) = default;
|
|
||||||
|
|
||||||
Tval l, r;
|
|
||||||
Engine rng;
|
|
||||||
std::uniform_int_distribution<Tval> dis;
|
|
||||||
bool halfed;
|
|
||||||
std::unordered_set<Tval> used;
|
|
||||||
std::vector<Tval> rest;
|
|
||||||
|
|
||||||
unique_ints_sequence(Engine &&e, Tval &&l, Tval &&r) : l(std::forward<Tval>(l))
|
|
||||||
, r(std::forward<Tval>(r)), rng(std::forward<Engine>(e))
|
|
||||||
, dis(std::forward<Tval>(l), std::forward<Tval>(r)), halfed(false) {}
|
|
||||||
|
|
||||||
bool is_terminated() const noexcept {
|
|
||||||
return halfed && rest.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator()() {
|
|
||||||
if (!halfed && (used.size() + 1) * 2 - (r - l + 1) >= 0) {
|
|
||||||
for (Tval i = l; i <= r; ++i) {
|
|
||||||
if (!used.count(i)) rest.push_back(i);
|
|
||||||
}
|
|
||||||
std::shuffle(rest.begin(), rest.end(), rng);
|
|
||||||
halfed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (halfed) {
|
|
||||||
if (rest.empty()) throw sequence_terminated_error();
|
|
||||||
auto res = std::move(rest.back());
|
|
||||||
rest.pop_back();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
auto res = dis(rng);
|
|
||||||
if (used.count(res)) continue;
|
|
||||||
used.insert(res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Tval = int, typename Engine = std::default_random_engine>
|
|
||||||
inline auto uniform_ints(require_unique_t _, Tval &&l, Tval &&r) {
|
|
||||||
return details::unique_ints_sequence<typename std::decay<Tval>::type, Engine>(
|
|
||||||
Engine(make_seed()), std::forward<Tval>(l), std::forward<Tval>(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tval = double, typename Engine = std::default_random_engine>
|
|
||||||
inline auto uniform_reals(Tval &&l, Tval &&r) {
|
|
||||||
return generate([rng = Engine(make_seed())
|
|
||||||
, dis = std::uniform_real_distribution<typename std::decay<Tval>::type>(
|
|
||||||
std::forward<Tval>(l), std::forward<Tval>(r))]() mutable {
|
|
||||||
return dis(rng);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename OutputIt, typename Gen>
|
|
||||||
inline OutputIt copy(OutputIt it, Gen&& g) {
|
|
||||||
while (!g.is_terminated()) {
|
|
||||||
*it++ = g();
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename OutputIt, typename Gen>
|
|
||||||
inline OutputIt copy_n(OutputIt it, size_t n, Gen&& g) {
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
*it++ = g();
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen>
|
|
||||||
inline auto output(std::basic_ostream<CharT, Traits>& out, const char *delim, Gen &&g) {
|
|
||||||
return copy(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out, delim), std::move(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen>
|
|
||||||
inline auto output(std::basic_ostream<CharT, Traits>& out, Gen &&g) {
|
|
||||||
return copy(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out), std::move(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen>
|
|
||||||
inline auto output_n(std::basic_ostream<CharT, Traits>& out, size_t n, const char *delim, Gen &&g) {
|
|
||||||
return copy_n(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out, delim), n, std::move(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen>
|
|
||||||
inline auto output_n(std::basic_ostream<CharT, Traits>& out, size_t n, Gen &&g) {
|
|
||||||
return copy_n(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out), n, std::move(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen
|
|
||||||
, typename Endl = decltype(std::endl<CharT, Traits>)>
|
|
||||||
inline auto outputln(std::basic_ostream<CharT, Traits>& out, const char *delim
|
|
||||||
, Gen &&g, const Endl &endl = std::endl<CharT, Traits>) {
|
|
||||||
auto res = copy(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out, delim), std::forward<Gen>(g));
|
|
||||||
out << endl;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen
|
|
||||||
, typename Endl = decltype(std::endl<CharT, Traits>)>
|
|
||||||
inline auto outputln(std::basic_ostream<CharT, Traits>& out
|
|
||||||
, Gen &&g, const Endl &endl = std::endl<CharT, Traits>) {
|
|
||||||
auto res = copy(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out), std::forward<Gen>(g));
|
|
||||||
out << endl;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen
|
|
||||||
, typename Endl = decltype(std::endl<CharT, Traits>)>
|
|
||||||
inline auto outputln_n(std::basic_ostream<CharT, Traits>& out, size_t n
|
|
||||||
, const char *delim, Gen &&g, const Endl &endl = std::endl<CharT, Traits>) {
|
|
||||||
auto res = copy_n(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out, delim), n, std::forward<Gen>(g));
|
|
||||||
out << endl;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Gen
|
|
||||||
, typename Endl = decltype(std::endl<CharT, Traits>)>
|
|
||||||
inline auto outputln_n(std::basic_ostream<CharT, Traits>& out, size_t n
|
|
||||||
, Gen &&g, const Endl &endl = std::endl<CharT, Traits>) {
|
|
||||||
auto res = copy_n(std::ostream_iterator<
|
|
||||||
typename std::decay<Gen>::type::result>(out), n, std::forward<Gen>(g));
|
|
||||||
out << endl;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Endl = decltype(std::endl<CharT, Traits>)>
|
|
||||||
inline void outputln(std::basic_ostream<CharT, Traits>& out
|
|
||||||
, const Endl &endl = std::endl<CharT, Traits>) {
|
|
||||||
out << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace _checks {
|
|
||||||
|
|
||||||
using empty_sequence_int = decltype(nothing<int>());
|
|
||||||
|
|
||||||
static_assert(is_sequence_t<empty_sequence_int>::value
|
|
||||||
&& is_sequence_t<decltype(take(empty_sequence_int{}, 1))>::value
|
|
||||||
&& is_sequence_t<decltype(group<20>(empty_sequence_int{}))>::value
|
|
||||||
&& is_sequence_t<decltype(concat(empty_sequence_int{}, empty_sequence_int{}))>::value
|
|
||||||
&& !is_sequence_t<int>::value
|
|
||||||
&& !is_sequence_t<std::less<int>>::value
|
|
||||||
, "compile-time self-checking failed(try upgrading your compiler).");
|
|
||||||
|
|
||||||
} // namespace _checks
|
|
||||||
|
|
||||||
} // namespace vmake
|
|
||||||
|
|
||||||
#endif
|
|
||||||
47
vcheck.py
47
vcheck.py
@ -18,24 +18,29 @@ def run(name: str, in_path, out_path):
|
|||||||
|
|
||||||
|
|
||||||
def cmp_file(file_path1, file_path2):
|
def cmp_file(file_path1, file_path2):
|
||||||
with open(file_path1, mode="r") as file1:
|
file1 = open(file_path1, mode="r")
|
||||||
with open(file_path2, mode="r") as file2:
|
file2 = open(file_path2, mode="r")
|
||||||
while True:
|
|
||||||
a = file1.readline()
|
|
||||||
b = file2.readline()
|
|
||||||
|
|
||||||
if (len(a) == 0 and len(b) != 0) or (len(a) == 0 and len(b) != 0):
|
in_1 = "#"
|
||||||
return False
|
in_2 = "#"
|
||||||
|
while not len(in_1) == 0 and not len(in_1) == 0:
|
||||||
|
in_1 = file1.readline()
|
||||||
|
in_2 = file2.readline()
|
||||||
|
|
||||||
if len(a) == 0 and len(b) == 0:
|
while len(in_1.split()) == 0 and not len(in_1) == 0:
|
||||||
break
|
in_1 = file1.readline()
|
||||||
|
|
||||||
a = a.split()
|
while len(in_2.split()) == 0 and not len(in_2) == 0:
|
||||||
b = b.split()
|
in_2 = file2.readline()
|
||||||
if a != b:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
if in_1.split() != in_2.split():
|
||||||
|
file1.close()
|
||||||
|
file2.close()
|
||||||
|
return False
|
||||||
|
|
||||||
|
file1.close()
|
||||||
|
file2.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def check_res(code, in_path, ans_path):
|
def check_res(code, in_path, ans_path):
|
||||||
@ -57,7 +62,6 @@ def check_file(file_path: str, err_msg: str):
|
|||||||
|
|
||||||
task_cnt = []
|
task_cnt = []
|
||||||
|
|
||||||
check_file("vtest.conf", "[ERR] Configure file 'vtest.conf' not found.")
|
|
||||||
vconf = open("vtest.conf", "r")
|
vconf = open("vtest.conf", "r")
|
||||||
|
|
||||||
name, sub_tasks = vconf.readline().split()
|
name, sub_tasks = vconf.readline().split()
|
||||||
@ -65,9 +69,6 @@ folder = vconf.readline().strip()
|
|||||||
if (not os.path.exists(folder)):
|
if (not os.path.exists(folder)):
|
||||||
os.makedirs(folder)
|
os.makedirs(folder)
|
||||||
|
|
||||||
print("Start CHECKING solution for {}.".format(name))
|
|
||||||
print()
|
|
||||||
|
|
||||||
sub_tasks = int(sub_tasks)
|
sub_tasks = int(sub_tasks)
|
||||||
tot_tasks = 0
|
tot_tasks = 0
|
||||||
|
|
||||||
@ -117,7 +118,7 @@ for i in range(1, sub_tasks + 1):
|
|||||||
re += 1
|
re += 1
|
||||||
|
|
||||||
print(
|
print(
|
||||||
" [{:>3}%] Case #{}.{}: {:^14} ({}ms)".format(
|
" [{}%] Case #{}.{}: {} ({}ms)".format(
|
||||||
round((tot_id / tot_tasks) * 100),
|
round((tot_id / tot_tasks) * 100),
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
@ -140,13 +141,13 @@ if wa == 0 and re == 0:
|
|||||||
print(" AC", end="")
|
print(" AC", end="")
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print(" Total time: {}ms".format(round(tot_time * 1000, 2)))
|
print(" Total time: {}ms".format(round(tot_time * 1000, 2)))
|
||||||
print(
|
print(
|
||||||
" Slowest case: #{}.{} ({}ms)".format(
|
" Slowest case: #{}.{} ({}ms)".format(
|
||||||
max_case[0], max_case[1], round(max_time * 1000, 2)
|
max_case[0], max_case[1], round(max_time * 1000, 2)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
print("--------------------------------")
|
print("--------------------------------")
|
||||||
print(" AC: {:>3} [{:>3}%]".format(ac, ac * 100 // tot_tasks))
|
print(" AC: {} [{}%]".format(ac, ac * 100 // tot_tasks))
|
||||||
print(" WA: {:>3} [{:>3}%]".format(wa, wa * 100 // tot_tasks))
|
print(" WA: {} [{}%]".format(wa, wa * 100 // tot_tasks))
|
||||||
print(" RE: {:>3} [{:>3}%]".format(re, re * 100 // tot_tasks))
|
print(" RE: {} [{}%]".format(re, re * 100 // tot_tasks))
|
||||||
|
|||||||
129
vhack.py
129
vhack.py
@ -1,129 +0,0 @@
|
|||||||
import subprocess
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def run(name: str, in_path, out_path):
|
|
||||||
in_file = open(in_path, mode="r")
|
|
||||||
out_file = open(out_path, mode="w")
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
code = subprocess.call(name, stdin=in_file, stdout=out_file)
|
|
||||||
end_time = time.time()
|
|
||||||
|
|
||||||
in_file.close()
|
|
||||||
out_file.close()
|
|
||||||
return (end_time - start_time, code)
|
|
||||||
|
|
||||||
|
|
||||||
def cmp_file(file_path1, file_path2):
|
|
||||||
with open(file_path1, mode="r") as file1:
|
|
||||||
with open(file_path2, mode="r") as file2:
|
|
||||||
while True:
|
|
||||||
a = file1.readline()
|
|
||||||
b = file2.readline()
|
|
||||||
|
|
||||||
if (len(a) == 0 and len(b) != 0) or (len(a) == 0 and len(b) != 0):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if len(a) == 0 and len(b) == 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
a = a.split()
|
|
||||||
b = b.split()
|
|
||||||
if a != b:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_res(code, in_path, ans_path):
|
|
||||||
if not code == 0:
|
|
||||||
return ("Runtime Error (return {})".format(code), 2)
|
|
||||||
|
|
||||||
if not cmp_file(in_path, ans_path):
|
|
||||||
return ("Wrong Answer", 1)
|
|
||||||
|
|
||||||
return ("Answer Correct", 0)
|
|
||||||
|
|
||||||
|
|
||||||
def check_file(file_path: str, err_msg: str):
|
|
||||||
if not os.path.exists(file_path):
|
|
||||||
print(err_msg, file=sys.stderr, flush=True)
|
|
||||||
exit(1)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
check_file("vhack.conf", "[ERR] Configure file 'vhack.conf' not found.")
|
|
||||||
vconf = open("vhack.conf", "r")
|
|
||||||
|
|
||||||
name, type = vconf.readline().split()
|
|
||||||
|
|
||||||
print("Start HACKING data for {}.".format(name))
|
|
||||||
print()
|
|
||||||
|
|
||||||
atp = 0
|
|
||||||
while True:
|
|
||||||
atp += 1
|
|
||||||
|
|
||||||
std_path = "./std_{}".format(name)
|
|
||||||
run_path = "./run_{}".format(name)
|
|
||||||
mk_path = "./mk_{}".format(name)
|
|
||||||
in_path = ".input.tmp"
|
|
||||||
out_path = "hack.in"
|
|
||||||
ans_path = "hack.out"
|
|
||||||
fatout_path = "hack.fat"
|
|
||||||
|
|
||||||
|
|
||||||
check_file(mk_path, "[ERR] Executable file {} not found.".format(mk_path))
|
|
||||||
check_file(std_path, "[ERR] Executable file {} not found.".format(std_path))
|
|
||||||
check_file(std_path, "[ERR] Executable file {} not found.".format(run_path))
|
|
||||||
|
|
||||||
input_tmp = open(in_path, "w")
|
|
||||||
input_tmp.write(str(type))
|
|
||||||
input_tmp.close()
|
|
||||||
|
|
||||||
|
|
||||||
mk_time, mk_code = run(mk_path, in_path, out_path)
|
|
||||||
|
|
||||||
if mk_code != 0:
|
|
||||||
print(
|
|
||||||
"****[ERR] {} Runtime Error on making test-case of attemption#{}. (abort)".format(
|
|
||||||
mk_path, atp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
std_time, std_code = run(std_path, out_path, ans_path)
|
|
||||||
|
|
||||||
if std_code != 0:
|
|
||||||
print(
|
|
||||||
"****[ERR] {} Runtime Error on making test-case of attemption#{}. (abort)".format(
|
|
||||||
std_path, atp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
fat_time, fat_code = run(run_path, out_path, fatout_path)
|
|
||||||
|
|
||||||
if fat_code != 0:
|
|
||||||
print(
|
|
||||||
"Attemption#{}: Hack Success[{}ms --- Runtime Error]".format(
|
|
||||||
atp, round(std_time, 2)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
if not cmp_file(ans_path, fatout_path):
|
|
||||||
print(
|
|
||||||
"Attemption#{}: Hack Success[{}ms --- {}ms]".format(
|
|
||||||
atp, round(std_time, 2), round(fat_time, 2)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
print(
|
|
||||||
"Attemption#{}: Hack Failed[{}ms --- {}ms]".format(
|
|
||||||
atp, round(std_time, 2), round(fat_time, 2)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
16
vmake.py
16
vmake.py
@ -26,7 +26,6 @@ def check_file(file_path: str, err_msg: str):
|
|||||||
|
|
||||||
task_cnt = []
|
task_cnt = []
|
||||||
|
|
||||||
check_file("vtest.conf", "[ERR] Configure file 'vtest.conf' not found.")
|
|
||||||
vconf = open("vtest.conf", "r")
|
vconf = open("vtest.conf", "r")
|
||||||
|
|
||||||
name, sub_tasks = vconf.readline().split()
|
name, sub_tasks = vconf.readline().split()
|
||||||
@ -34,9 +33,6 @@ folder = vconf.readline().strip()
|
|||||||
if (not os.path.exists(folder)):
|
if (not os.path.exists(folder)):
|
||||||
os.makedirs(folder)
|
os.makedirs(folder)
|
||||||
|
|
||||||
print("Start Making data for {}.".format(name))
|
|
||||||
print()
|
|
||||||
|
|
||||||
sub_tasks = int(sub_tasks)
|
sub_tasks = int(sub_tasks)
|
||||||
tot_tasks = 0
|
tot_tasks = 0
|
||||||
|
|
||||||
@ -58,12 +54,8 @@ for i in range(1, sub_tasks + 1):
|
|||||||
|
|
||||||
for j in range(1, task_cnt[i - 1] + 1):
|
for j in range(1, task_cnt[i - 1] + 1):
|
||||||
tot_id += 1
|
tot_id += 1
|
||||||
if platform.system() == "Windows":
|
mk_path = "./mk_{}".format(name)
|
||||||
mk_path = "./mk_{}.exe".format(name)
|
std_path = "./std_{}".format(name)
|
||||||
std_path = "./std_{}.exe".format(name)
|
|
||||||
else:
|
|
||||||
mk_path = "./mk_{}".format(name)
|
|
||||||
std_path = "./std_{}".format(name)
|
|
||||||
in_path = "{}/.input.tmp".format(folder)
|
in_path = "{}/.input.tmp".format(folder)
|
||||||
out_path = "{}/{}.{}.{}.in".format(folder, name, i, j)
|
out_path = "{}/{}.{}.{}.in".format(folder, name, i, j)
|
||||||
ans_path = "{}/{}.{}.{}.out".format(folder, name, i, j)
|
ans_path = "{}/{}.{}.{}.out".format(folder, name, i, j)
|
||||||
@ -72,7 +64,7 @@ for i in range(1, sub_tasks + 1):
|
|||||||
check_file(std_path, "[ERR] Executable file {} not found.".format(std_path))
|
check_file(std_path, "[ERR] Executable file {} not found.".format(std_path))
|
||||||
|
|
||||||
input_tmp = open(in_path, "w")
|
input_tmp = open(in_path, "w")
|
||||||
input_tmp.write(str(i) + " " + str(j))
|
input_tmp.write(str(i))
|
||||||
input_tmp.close()
|
input_tmp.close()
|
||||||
|
|
||||||
mk_time, mk_code = run(mk_path, in_path, out_path)
|
mk_time, mk_code = run(mk_path, in_path, out_path)
|
||||||
@ -100,7 +92,7 @@ for i in range(1, sub_tasks + 1):
|
|||||||
max_case = (i, j)
|
max_case = (i, j)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
" [{:>3}%] Made case #{}.{}: ({}ms)".format(
|
" [{}%] Made case #{}.{}: ({}ms)".format(
|
||||||
round((tot_id / tot_tasks) * 100),
|
round((tot_id / tot_tasks) * 100),
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user