80 lines
2.7 KiB
C++
80 lines
2.7 KiB
C++
#include <algorithm>
|
|
#include <map>
|
|
#include <vector>
|
|
#include "defs.hpp"
|
|
|
|
const char keyboard[2][4][15] = {{"`1234567890-=", "\0qwertyuiop[]\\", "\0asdfghjkl;'", "\0zxcvbnm,./"},
|
|
{"~!@#$%^&*()_+", "\0QWERTYUIOP{}|", "\0ASDFGHJKL:\"", "\0ZXCVBNM<>?"}};
|
|
|
|
auto string_to_cord(const std::string &password) -> std::vector<Cord> {
|
|
std::vector<Cord> ret;
|
|
for (auto ch : password) {
|
|
for (const auto &kbd : keyboard) {
|
|
for (int j = 0; j < 4; ++j) {
|
|
auto bgn = kbd[j][0] == '\0' ? 1 : 0;
|
|
auto pos = std::strchr(kbd[j] + bgn, ch);
|
|
if (pos) {
|
|
ret.push_back({j, static_cast<int>(pos - kbd[j])});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
auto cord_to_string(const std::vector<Cord> &cords) -> std::string {
|
|
std::ostringstream ret;
|
|
for (auto cord : cords) {
|
|
auto ch = keyboard[0][cord.x][cord.y]; // only consider not shifted keyboard
|
|
if (ch != '\0')
|
|
ret << ch;
|
|
else
|
|
spdlog::warn("cord_to_string: invalid cord: ({}, {})", cord.x, cord.y);
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
auto is_neighbour(const Cord &a, const Cord &b) -> bool {
|
|
auto [x1, y1] = a;
|
|
auto [x2, y2] = b;
|
|
|
|
auto same = x1 == x2 && y1 == y2; // NOTE: consider the case of `same` is true
|
|
return !same && std::abs(x1 - x2) <= 1 && std::abs(y1 - y2) <= 1;
|
|
}
|
|
|
|
void stat_keystroke(const DataSource &source) {
|
|
timeit(fmt::format("stat_keystroke({})", magic_enum::enum_name(source)));
|
|
|
|
std::map<std::string, size_t> stat;
|
|
for (auto const &password : passwords(source)) {
|
|
if (password.size() <= 1) continue;
|
|
|
|
auto cords = string_to_cord(password);
|
|
if (cords.size() <= 1) continue;
|
|
|
|
std::string longest;
|
|
size_t max_len = 0, cur_len = 1;
|
|
for (int i = 0; i < cords.size() - 1; i++) {
|
|
auto ok = is_neighbour(cords[i], cords[i + 1]);
|
|
if (ok) {
|
|
cur_len++;
|
|
} else {
|
|
if (cur_len > max_len) {
|
|
max_len = cur_len;
|
|
longest = cord_to_string(
|
|
std::vector<Cord>(cords.begin() + (int)(i - cur_len + 1), cords.begin() + i + 1));
|
|
}
|
|
cur_len = 1;
|
|
}
|
|
}
|
|
|
|
if (max_len > 5) stat[longest]++;
|
|
}
|
|
|
|
std::vector<std::pair<std::string, size_t>> vec(stat.begin(), stat.end());
|
|
std::sort(vec.begin(), vec.end(), [](auto const &lhs, auto const &rhs) { return lhs.second > rhs.second; });
|
|
|
|
for (auto const &[length, count] : vec | std::views::take(10)) spdlog::info("{}: {}", length, count);
|
|
}
|