-
Notifications
You must be signed in to change notification settings - Fork 0
/
mixed_radix_gray_codes.cpp
113 lines (101 loc) · 3.11 KB
/
mixed_radix_gray_codes.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <docopt/docopt.h>
#include <fmt/core.h>
#include <sstream>
static constexpr auto USAGE =
R"(Mixed Radix Gray Codes
Usage:
mixed_radix_gray_codes -- <digit_radix>...
mixed_radix_gray_codes (-h | --help)
mixed_radix_gray_codes --version
Options:
-h --help Show this screen.
--version Show version.
)";
/**
* \brief Helper Enum for counting directions
*/
enum class Direction { Up, Down };
/**
* \brief just for some nice formated output
* \param[in] word the mixed-radix number to be formated
*/
template<typename T>
[[maybe_unused]] static inline std::string
format_word(const std::vector<T>& word) {
std::stringstream ss;
ss << "[ ";
for (const auto& a : word) {
if (a == 0) {
ss << '.';
} else {
ss << a;
}
ss << ' ';
}
ss << ']';
return ss.str();
}
/**
* \brief lists all numbers. Every digit is counted from 0 towards its radix
* \param[in] radices radix per position radix[0] is most significant digit
*/
void all_numbers(const std::vector<int>& radices) {
std::vector<int> number(radices.size());
std::vector<Direction> direction(radices.size());
// ensure a correct initial counting direction
std::transform(
radices.begin(), radices.end(), direction.begin(), [](const auto& s) {
return s >= 0 ? Direction::Up : Direction::Down;
});
// save the first direction the least significant digit will take for later
const auto firstDir = direction.back();
// we are done when the direction of the least significant digit has changed
while (firstDir == direction.back()) {
fmt::print("{}\n", format_word(number));
for (auto i = 0U; i < number.size(); ++i) {
if (direction[i] == Direction::Up) {
if (number[i] == std::max(radices[i]-1, 0)) {
// change direction and move to the next digit
direction[i] = Direction::Down;
} else {
// increment current digit and continue
++number[i];
break;
}
} else {
if (number[i] == std::min(radices[i]+1, 0)) {
// change direction and move to the next digit
direction[i] = Direction::Up;
} else {
// decrement current digit and continue
--number[i];
break;
}
}
}
}
}
int main(int argc, char* argv[]) {
const auto args = docopt::docopt(
USAGE,
{std::next(argv), std::next(argv, argc)},
true, // show help if requested
"Mixed Radix Gray Codes 1.0.0"); // version string
try {
const auto digit_radix = args.at("<digit_radix>");
if (digit_radix.isStringList()) {
const auto& digit_radix_list = digit_radix.asStringList();
std::vector<int> radices(digit_radix_list.size());
// get those numbers out of the Strings
std::transform(
digit_radix_list.begin(),
digit_radix_list.end(),
radices.begin(),
[](const auto& s) {
return std::stoi(s);
});
all_numbers(radices);
}
} catch (const std::exception&) {}
return 0;
}