Compare commits

..

34 Commits
v1.0 ... main

Author SHA1 Message Date
785d40e578 [libvmake] add vmake::zip() 2023-07-23 16:28:39 +08:00
2ac908690f [libvamke] add discard_n() 2023-07-23 15:50:52 +08:00
0306a11812 add the missing const of grouper::is_terminated() 2023-07-23 15:29:52 +08:00
3deeedc7aa add example random_even.cpp 2023-07-23 15:24:35 +08:00
753b474376 strict is_sequence_t 2023-07-23 15:24:13 +08:00
b71ef30f3e better diagnosis info 2023-07-23 14:27:01 +08:00
ac82ce9267 better concat template 2023-07-23 14:11:26 +08:00
a96009adf7 [libvmake] allow concat multiple sequences 2023-07-20 00:11:54 +08:00
4b183a10c2 Move NOTICE to project root 2023-07-19 22:40:21 +08:00
99d0e5f144 Add thurd-party license notice 2023-07-19 22:38:58 +08:00
d9576953b1 Tweak README and add a TODO list 2023-07-19 22:25:37 +08:00
41090efaf5 [libvmake] add meta type vmake::is_sequence_t to check if a type is a valid sequence
fixed a bug with vmake::range(start, end, step)
added an example about how to define costum sequences
2023-07-19 21:49:49 +08:00
43b5d469b3 [libvmake] refactor group types 2023-07-19 21:11:19 +08:00
0d0edbb549 move mark object vmake::rng::require_unique -> vmake::require_unique 2023-07-19 19:37:26 +08:00
b846678d29 add uniform int sequence with unique elements 2023-07-19 18:33:19 +08:00
650c363f03 [libvmake]add gourp() 2023-07-19 17:08:59 +08:00
708f9ca9ec [libvmake] add repeat() and repeat_n() 2023-07-19 14:49:25 +08:00
46367b0a59 add conditional compile 2023-07-18 21:16:56 +08:00
989c5353d5 remove swap file 2023-07-18 20:33:05 +08:00
87d2db06c1 add outputln variant 2023-07-18 20:31:35 +08:00
8b8cf836f3 add ranged uniform real sequence 2023-07-18 20:10:39 +08:00
c4666278c8 add ranged uniform int sequence 2023-07-18 20:04:28 +08:00
63d21bcb1f refactor: sort codes 2023-07-18 19:45:41 +08:00
e96f56a5da add unranged iterator extraction 2023-07-18 19:36:59 +08:00
23b0a79200 add ranges & fix filter 2023-07-18 19:11:03 +08:00
0ec206cade Add libvmake folder 2023-07-18 17:24:46 +08:00
Tony Zhang
6d23fdc571
Merge pull request #2 from szdytom/main
[fix] add .exe suffix on Windows in vmake.py
2023-01-21 11:36:09 +08:00
6d917be515 [fix] add .exe suffix on Windows in vmake.py
Signed-off-by: szdytom <szdytom@163.com>
2023-01-20 22:43:13 +08:00
Tony Zhang
58c16ab3c4
Merge pull request #1 from szdytom/main
add vhack
2022-01-18 23:54:14 +08:00
079527f9f9
fix & add 2022-01-18 10:35:17 +08:00
5411ecd19c [README] update output format
Signed-off-by: zhangtianli2006 <zhangtianli2006@163.com>
2021-08-25 13:50:22 +08:00
fc72ff4cd1 [feature] check if vtest.conf exists
Signed-off-by: zhangtianli2006 <zhangtianli2006@163.com>
2021-08-25 13:45:33 +08:00
ee500e6510 [feature] better output format
Signed-off-by: zhangtianli2006 <zhangtianli2006@163.com>
2021-08-25 13:43:04 +08:00
Tony Zhang
e1c7c59345
[README] use tasble symbols 2021-08-24 13:12:06 +08:00
20 changed files with 3108 additions and 100 deletions

6
.gitignore vendored
View File

@ -1,6 +1,12 @@
# Editor # Editor
.vscode/ .vscode/
*.swp
# Test # Test
test* test*
test/ test/
# Executables & Builds
*.exe
*.pch
*.o

34
NOTICE Normal file
View File

@ -0,0 +1,34 @@
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.
================================================================================

121
README.md
View File

@ -1,14 +1,14 @@
# py-Vtest # py-Vtest
![[LICENSE](https://github.com/zhangtianli2006/py-vtest/blob/main/LICENSE)](https://img.shields.io/github/license/zhangtianli2006/py-vtest?style=flat-square) ![[LICENSE](https://github.com/ZTL-UwU/py-vtest/blob/main/LICENSE)](https://img.shields.io/github/license/ZTL-UwU/py-vtest?style=flat-square)
![Code Size](https://img.shields.io/github/languages/code-size/zhangtianli2006/py-vtest?style=flat-square) ![Code Size](https://img.shields.io/github/languages/code-size/ZTL-UwU/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 std and Maker (described below). 1. **vmake**: Automatically generate test-data with user-provided standard solution and Maker (described below).
2. **vcheck**: Judge a solution like a OnlineJudge does. 2. **vcheck**: Execute a solution on set of test-data like an 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. Make an empty folder. 1. Create 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 these commands if you are a command-line user: 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`:
```bash ```bash
wget https://github.com/zhangtianli2006/py-vtest/raw/main/vmake.py wget https://github.com/ZTL-UwU/py-vtest/raw/main/vmake.py
wget https://github.com/zhangtianli2006/py-vtest/raw/main/vcheck.py wget https://github.com/ZTL-UwU/py-vtest/raw/main/vcheck.py
``` ```
4. Create an executable named `std_AplusB`. 4. Create a standard solutoion as an executable named `std_AplusB`.
For example, here is a C++ version of it, just compile it: For example, the following code is a C++ version of a standard solution of _A + B problem_, compile it into `std_AplusB`:
```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,28 +104,33 @@ 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, here is a C++ version of it, just compile it: For example, the following is a C++ version of the test-data Maker, compile it into `mk_AplusB`:
```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
// In this subtask, we will try to hack solutions without using long long // which can 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();
} }
@ -134,17 +139,25 @@ 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 these commands if you are a command-line user: You can use the following command or simply double-click on `vmake.py`:
```bash ```bash
python3 vmake.py python3 vmake.py
``` ```
The program outputs like this: The output is similar to the following:
```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)
@ -166,23 +179,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 it, just compile it to `run_AplusB`: This is a C++ version of a wrong solution, compile it into `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;
@ -190,15 +203,21 @@ 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 these commands if you are a command-line user: You can use the following command or simply double-click on `vcheck.py`:
```bash ```bash
python3 vcheck.py python3 vcheck.py
``` ```
The program may outputs like this: The output is similar to the following:
```plaintext ```plaintext
Start checking subtask #1 Start checking subtask #1
@ -222,3 +241,15 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
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.

View File

@ -0,0 +1,9 @@
#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;
}

View File

@ -0,0 +1,26 @@
#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;
}

View File

@ -0,0 +1,6 @@
#include "../vmake.hpp"
using namespace std;
int main() {
vmake::outputln(cout, " ", vmake::discard_n(vmake::range(1, 10), 2));
}

View File

@ -0,0 +1,8 @@
#include "../vmake.hpp"
#include <bits/stdc++.h>
using namespace std;
int main() {
vmake::output(cout, vmake::nothing<string>());
return 0;
}

View File

@ -0,0 +1,13 @@
#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;
}

View File

@ -0,0 +1,9 @@
#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;
}

View File

@ -0,0 +1,10 @@
#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;
}));
}

View File

@ -0,0 +1,11 @@
#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;
}

View File

@ -0,0 +1,10 @@
#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; }));
}

View File

@ -0,0 +1,10 @@
#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;
}

View File

@ -0,0 +1,8 @@
#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;
}

View File

@ -0,0 +1,9 @@
#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);
}));
}

1847
libvmake/optional.hpp Normal file

File diff suppressed because it is too large Load Diff

825
libvmake/vmake.hpp Normal file
View File

@ -0,0 +1,825 @@
#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

View File

@ -18,28 +18,23 @@ def run(name: str, in_path, out_path):
def cmp_file(file_path1, file_path2): def cmp_file(file_path1, file_path2):
file1 = open(file_path1, mode="r") with open(file_path1, mode="r") as file1:
file2 = open(file_path2, mode="r") with open(file_path2, mode="r") as file2:
while True:
a = file1.readline()
b = file2.readline()
in_1 = "#" if (len(a) == 0 and len(b) != 0) or (len(a) == 0 and len(b) != 0):
in_2 = "#" return False
while not len(in_1) == 0 and not len(in_1) == 0:
in_1 = file1.readline() if len(a) == 0 and len(b) == 0:
in_2 = file2.readline() break
while len(in_1.split()) == 0 and not len(in_1) == 0: a = a.split()
in_1 = file1.readline() b = b.split()
if a != b:
while len(in_2.split()) == 0 and not len(in_2) == 0:
in_2 = file2.readline()
if in_1.split() != in_2.split():
file1.close()
file2.close()
return False return False
file1.close()
file2.close()
return True return True
@ -62,6 +57,7 @@ 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()
@ -69,6 +65,9 @@ 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
@ -118,7 +117,7 @@ for i in range(1, sub_tasks + 1):
re += 1 re += 1
print( print(
" [{}%] Case #{}.{}: {} ({}ms)".format( " [{:>3}%] Case #{}.{}: {:^14} ({}ms)".format(
round((tot_id / tot_tasks) * 100), round((tot_id / tot_tasks) * 100),
i, i,
j, j,
@ -148,6 +147,6 @@ print(
) )
) )
print("--------------------------------") print("--------------------------------")
print(" AC: {} [{}%]".format(ac, ac * 100 // tot_tasks)) print(" AC: {:>3} [{:>3}%]".format(ac, ac * 100 // tot_tasks))
print(" WA: {} [{}%]".format(wa, wa * 100 // tot_tasks)) print(" WA: {:>3} [{:>3}%]".format(wa, wa * 100 // tot_tasks))
print(" RE: {} [{}%]".format(re, re * 100 // tot_tasks)) print(" RE: {:>3} [{:>3}%]".format(re, re * 100 // tot_tasks))

129
vhack.py Normal file
View File

@ -0,0 +1,129 @@
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)
)
)

View File

@ -26,6 +26,7 @@ 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()
@ -33,6 +34,9 @@ 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
@ -54,6 +58,10 @@ 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_{}.exe".format(name)
std_path = "./std_{}.exe".format(name)
else:
mk_path = "./mk_{}".format(name) mk_path = "./mk_{}".format(name)
std_path = "./std_{}".format(name) std_path = "./std_{}".format(name)
in_path = "{}/.input.tmp".format(folder) in_path = "{}/.input.tmp".format(folder)
@ -64,7 +72,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)) input_tmp.write(str(i) + " " + str(j))
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)
@ -92,7 +100,7 @@ for i in range(1, sub_tasks + 1):
max_case = (i, j) max_case = (i, j)
print( print(
" [{}%] Made case #{}.{}: ({}ms)".format( " [{:>3}%] Made case #{}.{}: ({}ms)".format(
round((tot_id / tot_tasks) * 100), round((tot_id / tot_tasks) * 100),
i, i,
j, j,