73 lines
2.6 KiB
C++
73 lines
2.6 KiB
C++
#include "roster.h"
|
|
#include <QSet>
|
|
|
|
namespace Roster {
|
|
ParsedNames parse(const QString &text)
|
|
{
|
|
ParsedNames result;
|
|
QSet<QString> seen;
|
|
const QStringList lines = text.split(QLatin1Char('\n'));
|
|
int lineNumber = 0;
|
|
for (const QString &line : lines) {
|
|
++lineNumber;
|
|
const QString name = line.trimmed();
|
|
if (name.isEmpty()) continue;
|
|
if (seen.contains(name)) {
|
|
result.error = QStringLiteral("第 %1 行与前面的条目重复:%2。"
|
|
"同名学生请加上学号后再应用名单。").arg(lineNumber).arg(name);
|
|
return result;
|
|
}
|
|
if (name.size() > 100) {
|
|
result.error = QStringLiteral("第 %1 行超过 100 个字符,请检查是否粘贴了整段文字。")
|
|
.arg(lineNumber);
|
|
return result;
|
|
}
|
|
seen.insert(name);
|
|
result.names.append(name);
|
|
}
|
|
if (result.names.isEmpty())
|
|
result.error = QStringLiteral("名单为空,请每行输入一位学生。");
|
|
else if (result.names.size() > 5000)
|
|
result.error = QStringLiteral("名单超过 5000 人,请分批操作。");
|
|
return result;
|
|
}
|
|
|
|
void Session::setNames(const QStringList &names)
|
|
{
|
|
m_names = names;
|
|
resetDraw();
|
|
}
|
|
|
|
void Session::resetDraw() { m_pool = m_names; }
|
|
|
|
QStringList Session::draw(int count, QRandomGenerator &random)
|
|
{
|
|
QStringList selected;
|
|
if (count <= 0 || count > m_pool.size()) return selected;
|
|
for (int i = 0; i < count; ++i) {
|
|
const int index = random.bounded(static_cast<int>(m_pool.size()));
|
|
// 从候选池中移除已抽到的人,本轮后续抽签就不会重复。
|
|
selected.append(m_pool.takeAt(index));
|
|
}
|
|
return selected;
|
|
}
|
|
|
|
QList<QStringList> Session::groups(int value, bool valueIsGroupCount,
|
|
QRandomGenerator &random) const
|
|
{
|
|
QList<QStringList> result;
|
|
const int n = static_cast<int>(m_names.size());
|
|
if (n == 0 || value <= 0 || (valueIsGroupCount && value > n)) return result;
|
|
const int count = valueIsGroupCount ? value : (n + value - 1) / value;
|
|
QStringList shuffled = m_names;
|
|
// Fisher–Yates 洗牌。每次从尚未固定的位置中均匀选取一个。
|
|
for (int i = n - 1; i > 0; --i)
|
|
qSwap(shuffled[i], shuffled[random.bounded(i + 1)]);
|
|
for (int i = 0; i < count; ++i) result.append(QStringList());
|
|
// 轮流放入各组,保证每人出现一次,各组人数最多相差 1。
|
|
for (int i = 0; i < n; ++i) result[i % count].append(shuffled.at(i));
|
|
return result;
|
|
}
|
|
}
|
|
|