Compare commits

..

No commits in common. "main" and "v1.0" have entirely different histories.
main ... v1.0

20 changed files with 100 additions and 3108 deletions

6
.gitignore vendored
View File

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

34
NOTICE
View File

@ -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.
================================================================================

163
README.md
View File

@ -1,14 +1,14 @@
# py-Vtest
![[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/ZTL-UwU/py-vtest?style=flat-square)
![[LICENSE](https://github.com/zhangtianli2006/py-vtest/blob/main/LICENSE)](https://img.shields.io/github/license/zhangtianli2006/py-vtest?style=flat-square)
![Code Size](https://img.shields.io/github/languages/code-size/zhangtianli2006/py-vtest?style=flat-square)
An OI test-data maker & std test tool.
## Mode
1. **vmake**: Automatically generate test-data with user-provided standard solution and Maker (described below).
2. **vcheck**: Execute a solution on set of test-data like an OnlineJudge does.
1. **vmake**: Automatically generate test-data with user-provided std and Maker (described below).
2. **vcheck**: Judge a solution like a OnlineJudge does.
**WARNING: No sandbox protection, don't run any untrusted code!**
## Maker
@ -51,25 +51,25 @@ A Maker is an executable that generates the input of a single test case.
```plaintext
.
├─ <data path> // Auto Generated
│ ├─ <name>.1.1.in
│ ├─ <name>.1.1.out
│ ├─ ...
│ ├─ <name>.<subtask count>.<n>.in
│ └─ <name>.<subtask count>.<n>.out
├─ mk_<name> // Compile yourself
├─ std_<name> // Compile yourself
├─ run_<name> // Compile yourself
├─ vmake.py // Downloaded
└─ vcheck.py // Downloaded
|- <data path> // Auto Generated
| |- <name>.1.1.in
| |- <name>.1.1.out
| |- ...
| |- <name>.<subtask count>.<n>.in
| |- <name>.<subtask count>.<n>.out
|
|- mk_<name> // Compile yourself
|- std_<name> // Compile yourself
|- run_<name> // Compile yourself
|- vmake.py // Downloaded
|- vcheck.py // Downloaded
```
## Example
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:
```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`.
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
wget https://github.com/ZTL-UwU/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/vmake.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
// std_AplusB.cpp
#include <iostream>
int main() {
int main()
{
long long a, b;
std::cin >> 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).
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
// mk_AplusB.cpp
#include <iostream>
#include <random>
int main() {
int main()
{
int subtask_id;
std::cin >> subtask_id;
if (subtask_id == 1) {
if (subtask_id == 1)
{
std::mt19937 rng(std::random_device{}());
std::cout << rng() << " " << rng();
}
if (subtask_id == 2) {
// In this subtask, we will generate larger inputs
// which can hack solutions without using long long.
if (subtask_id == 2)
{
// In this subtask, we will try to hack solutions without using long long
std::mt19937_64 rng(std::random_device{}());
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`.
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
python3 vmake.py
```
The output is similar to the following:
The program outputs like this:
```plaintext
Start Making data for AplusB.
Making subtask #1
[ 10%] Made case #1.1: (9.0ms)
[ 20%] Made case #1.2: (2.17ms)
[ 30%] Made case #1.3: (5.08ms)
[ 40%] Made case #1.4: (2.53ms)
[ 50%] Made case #1.5: (4.01ms)
[ 60%] Made case #1.6: (3.81ms)
[10%] Made case #1.1: (9.0ms)
[20%] Made case #1.2: (2.17ms)
[30%] Made case #1.3: (5.08ms)
[40%] Made case #1.4: (2.53ms)
[50%] Made case #1.5: (4.01ms)
[60%] Made case #1.6: (3.81ms)
Making subtask #2
[ 70%] Made case #2.1: (1.99ms)
[ 80%] Made case #2.2: (3.06ms)
[ 90%] Made case #2.3: (2.04ms)
[70%] Made case #2.1: (1.99ms)
[80%] Made case #2.2: (3.06ms)
[90%] Made case #2.3: (2.04ms)
[100%] Made case #2.4: (3.4ms)
Summary:
@ -179,23 +166,23 @@ Here is a example of generating test-data of the _A + B problem_ and testing a s
```
.
├─ data
| ├─ AplusB.1.1.in
| ├─ AplusB.1.1.out
| ├─ ...
| ├─ AplusB.2.4.in
| └─ AplusB.2.4.out
|- data
| |- AplusB.1.1.in
| |- AplusB.1.1.out
| |- ...
| |- AplusB.2.4.in
| |- AplusB.2.4.out
```
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
// AplusB_wrong.cpp
#include <iostream>
int main() {
int main()
{
int a, b;
std::cin >> 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`
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
python3 vcheck.py
```
The output is similar to the following:
The program may outputs like this:
```plaintext
Start checking subtask #1
[ 10%] Case #1.1: Answer Correct (2.56ms)
[ 20%] Case #1.2: Answer Correct (2.33ms)
[ 30%] Case #1.3: Answer Correct (2.6ms)
[ 40%] Case #1.4: Answer Correct (7.18ms)
[ 50%] Case #1.5: Answer Correct (2.22ms)
[ 60%] Case #1.6: Answer Correct (2.24ms)
[10%] Case #1.1: Answer Correct (2.56ms)
[20%] Case #1.2: Answer Correct (2.33ms)
[30%] Case #1.3: Answer Correct (2.6ms)
[40%] Case #1.4: Answer Correct (7.18ms)
[50%] Case #1.5: Answer Correct (2.22ms)
[60%] Case #1.6: Answer Correct (2.24ms)
Start checking subtask #2
[ 70%] Case #2.1: Wrong Answer (3.17ms)
[ 80%] Case #2.2: Wrong Answer (2.85ms)
[ 90%] Case #2.3: Wrong Answer (2.28ms)
[70%] Case #2.1: Wrong Answer (3.17ms)
[80%] Case #2.2: Wrong Answer (2.85ms)
[90%] Case #2.3: Wrong Answer (2.28ms)
[100%] Case #2.4: Wrong Answer (2.76ms)
Summary: WA
Total time: 30.2ms
Slowest case: #1.4 (7.18ms)
--------------------------------
AC: 6 [ 60%]
WA: 4 [ 40%]
RE: 0 [ 0%]
AC: 6 [60%]
WA: 4 [40%]
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

@ -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;
}

View File

@ -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;
}

View File

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

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}));
}

View File

@ -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;
}

View File

@ -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; }));
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -18,23 +18,28 @@ def run(name: str, in_path, out_path):
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()
file1 = open(file_path1, mode="r")
file2 = open(file_path2, mode="r")
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:
in_1 = "#"
in_2 = "#"
while not len(in_1) == 0 and not len(in_1) == 0:
in_1 = file1.readline()
in_2 = file2.readline()
while len(in_1.split()) == 0 and not len(in_1) == 0:
in_1 = file1.readline()
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
file1.close()
file2.close()
return True
@ -57,7 +62,6 @@ def check_file(file_path: str, err_msg: str):
task_cnt = []
check_file("vtest.conf", "[ERR] Configure file 'vtest.conf' not found.")
vconf = open("vtest.conf", "r")
name, sub_tasks = vconf.readline().split()
@ -65,9 +69,6 @@ folder = vconf.readline().strip()
if (not os.path.exists(folder)):
os.makedirs(folder)
print("Start CHECKING solution for {}.".format(name))
print()
sub_tasks = int(sub_tasks)
tot_tasks = 0
@ -117,7 +118,7 @@ for i in range(1, sub_tasks + 1):
re += 1
print(
" [{:>3}%] Case #{}.{}: {:^14} ({}ms)".format(
" [{}%] Case #{}.{}: {} ({}ms)".format(
round((tot_id / tot_tasks) * 100),
i,
j,
@ -147,6 +148,6 @@ print(
)
)
print("--------------------------------")
print(" AC: {:>3} [{:>3}%]".format(ac, ac * 100 // tot_tasks))
print(" WA: {:>3} [{:>3}%]".format(wa, wa * 100 // tot_tasks))
print(" RE: {:>3} [{:>3}%]".format(re, re * 100 // tot_tasks))
print(" AC: {} [{}%]".format(ac, ac * 100 // tot_tasks))
print(" WA: {} [{}%]".format(wa, wa * 100 // tot_tasks))
print(" RE: {} [{}%]".format(re, re * 100 // tot_tasks))

129
vhack.py
View File

@ -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)
)
)

View File

@ -26,7 +26,6 @@ def check_file(file_path: str, err_msg: str):
task_cnt = []
check_file("vtest.conf", "[ERR] Configure file 'vtest.conf' not found.")
vconf = open("vtest.conf", "r")
name, sub_tasks = vconf.readline().split()
@ -34,9 +33,6 @@ folder = vconf.readline().strip()
if (not os.path.exists(folder)):
os.makedirs(folder)
print("Start Making data for {}.".format(name))
print()
sub_tasks = int(sub_tasks)
tot_tasks = 0
@ -58,10 +54,6 @@ for i in range(1, sub_tasks + 1):
for j in range(1, task_cnt[i - 1] + 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)
std_path = "./std_{}".format(name)
in_path = "{}/.input.tmp".format(folder)
@ -72,7 +64,7 @@ for i in range(1, sub_tasks + 1):
check_file(std_path, "[ERR] Executable file {} not found.".format(std_path))
input_tmp = open(in_path, "w")
input_tmp.write(str(i) + " " + str(j))
input_tmp.write(str(i))
input_tmp.close()
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)
print(
" [{:>3}%] Made case #{}.{}: ({}ms)".format(
" [{}%] Made case #{}.{}: ({}ms)".format(
round((tot_id / tot_tasks) * 100),
i,
j,