2024-03-01 21:57:29 +08:00
|
|
|
#![feature(portable_simd)]
|
|
|
|
|
2024-02-28 19:04:57 +08:00
|
|
|
mod name;
|
|
|
|
|
2024-03-02 01:38:13 +08:00
|
|
|
use std::{io::Write, path::PathBuf};
|
2024-03-02 00:09:53 +08:00
|
|
|
|
2024-02-28 23:33:59 +08:00
|
|
|
use base16384::Base16384Utf8;
|
2024-02-29 01:05:41 +08:00
|
|
|
use clap::Parser;
|
2024-03-02 00:09:53 +08:00
|
|
|
use tracing::{info, warn};
|
2024-02-28 23:33:59 +08:00
|
|
|
|
|
|
|
/// 根据 u64 生成对应的 name
|
|
|
|
/// 转换成 base 16384
|
|
|
|
/// 禁用:
|
|
|
|
/// U00 ~ U1F ,换行,制表符 等
|
|
|
|
/// ? , 问号
|
|
|
|
/// U2000 - U202F , unicode特殊空格 等
|
|
|
|
/// 不可以空格开头
|
2024-02-29 01:59:03 +08:00
|
|
|
#[inline(always)]
|
2024-02-28 23:33:59 +08:00
|
|
|
pub fn gen_name(id: u64) -> String {
|
|
|
|
// u64 -> [u8]
|
|
|
|
let id_bytes = id.to_be_bytes();
|
|
|
|
Base16384Utf8::encode(id_bytes.as_slice())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn show_name(namer: &name::Namer) -> String {
|
|
|
|
// var attributeNames = ["HP", "攻", "防", "速", "敏", "魔", "抗", "智"]
|
|
|
|
format!(
|
|
|
|
"HP|{} 攻|{} 防|{} 速|{} 敏|{} 魔|{} 抗|{} 智|{} 八围:{}",
|
|
|
|
namer.name_prop[7],
|
|
|
|
namer.name_prop[0],
|
|
|
|
namer.name_prop[1],
|
|
|
|
namer.name_prop[2],
|
|
|
|
namer.name_prop[3],
|
|
|
|
namer.name_prop[4],
|
|
|
|
namer.name_prop[5],
|
|
|
|
namer.name_prop[6],
|
|
|
|
namer.get_property()
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(non_upper_case_globals)]
|
2024-02-29 00:25:19 +08:00
|
|
|
const allow_d: u32 = 10;
|
|
|
|
|
2024-03-02 00:09:53 +08:00
|
|
|
#[derive(Parser, Debug, Clone)]
|
2024-02-29 01:05:41 +08:00
|
|
|
pub struct Command {
|
2024-03-02 01:38:13 +08:00
|
|
|
/// 开始的 id
|
2024-02-29 01:05:41 +08:00
|
|
|
#[arg(long, default_value_t = 0)]
|
|
|
|
pub start: u64,
|
2024-03-02 01:38:13 +08:00
|
|
|
/// 结束的 id
|
2024-02-29 01:05:41 +08:00
|
|
|
#[arg(long, default_value_t = u64::MAX)]
|
|
|
|
pub end: u64,
|
2024-03-02 01:38:13 +08:00
|
|
|
/// 线程数
|
2024-02-29 01:05:41 +08:00
|
|
|
#[arg(long, short = 't', default_value_t = 10)]
|
|
|
|
pub thread_count: u32,
|
2024-03-02 01:38:13 +08:00
|
|
|
/// 八围预期值
|
|
|
|
#[arg(long = "prop-expected", short = 'p', default_value_t = 740)]
|
|
|
|
pub prop_expect: u32,
|
|
|
|
/// 队伍名称
|
2024-02-29 01:05:41 +08:00
|
|
|
#[arg(long)]
|
|
|
|
pub team: String,
|
2024-03-02 01:38:13 +08:00
|
|
|
/// 预期状态输出时间间隔 (秒)
|
|
|
|
#[arg(long, default_value_t = 10)]
|
|
|
|
pub report_interval: u64,
|
2024-02-29 01:05:41 +08:00
|
|
|
}
|
|
|
|
|
2024-03-02 01:43:18 +08:00
|
|
|
/// 大概的预计速度
|
|
|
|
/// 来自 5600X 的运行效率
|
2024-03-02 01:38:13 +08:00
|
|
|
pub const GUESS_SPEED: u64 = 623772;
|
|
|
|
|
2024-02-29 01:59:03 +08:00
|
|
|
#[inline(always)]
|
2024-03-02 01:38:13 +08:00
|
|
|
fn cacl(config: Command, id: u64, outfile: &PathBuf) {
|
|
|
|
// 初始猜测的时间间隔
|
|
|
|
let mut report_interval = config.report_interval * GUESS_SPEED;
|
|
|
|
let mut run_speed = GUESS_SPEED as f64;
|
2024-02-29 00:39:56 +08:00
|
|
|
let mut start_time = std::time::Instant::now();
|
2024-02-29 00:25:19 +08:00
|
|
|
let mut k: u64 = 0;
|
2024-03-02 01:38:13 +08:00
|
|
|
// 提前准备好 team_namer
|
|
|
|
let team_namer = name::TeamNamer::new_unchecked(&config.team);
|
|
|
|
|
|
|
|
for i in (config.start + id..config.end).step_by(config.thread_count as usize) {
|
2024-02-29 00:36:28 +08:00
|
|
|
let name = gen_name(i as u64);
|
2024-02-29 19:49:49 +08:00
|
|
|
let namer = name::Namer::new_from_team_namer_unchecked(&team_namer, name.as_str());
|
2024-02-29 01:59:03 +08:00
|
|
|
let prop = namer.get_property();
|
2024-03-02 01:38:13 +08:00
|
|
|
|
|
|
|
if (prop + allow_d as f32) > config.prop_expect as f32 {
|
2024-02-29 01:59:03 +08:00
|
|
|
let name = gen_name(i as u64);
|
2024-03-02 01:38:13 +08:00
|
|
|
let full_name = format!("{}@{}", name, config.team);
|
2024-02-29 01:59:03 +08:00
|
|
|
info!("{:>15}|{}|{}", i, full_name, show_name(&namer));
|
2024-03-02 01:38:13 +08:00
|
|
|
// 写入 (写到最后一行)
|
|
|
|
match std::fs::OpenOptions::new()
|
|
|
|
.append(true)
|
|
|
|
.open(outfile)
|
|
|
|
.and_then(|mut file| file.write(format!("{}\n", full_name).as_bytes()))
|
|
|
|
{
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => {
|
|
|
|
warn!("写入文件<{:?}>失败: {}", outfile, e);
|
|
|
|
}
|
2024-03-02 00:09:53 +08:00
|
|
|
}
|
2024-02-29 00:25:19 +08:00
|
|
|
}
|
|
|
|
k += 1;
|
2024-02-29 01:59:03 +08:00
|
|
|
if k >= report_interval as u64 {
|
2024-02-29 00:25:19 +08:00
|
|
|
let now = std::time::Instant::now();
|
2024-03-01 22:38:29 +08:00
|
|
|
let d_t: std::time::Duration = now.duration_since(start_time);
|
2024-03-02 01:38:13 +08:00
|
|
|
let new_run_speed = k as f64 / d_t.as_secs_f64();
|
|
|
|
// 根据实际运行速率来调整 report_interval
|
2024-03-02 01:43:18 +08:00
|
|
|
report_interval = config.report_interval * new_run_speed as u64;
|
2024-03-02 00:08:56 +08:00
|
|
|
info!(
|
2024-03-02 01:38:13 +08:00
|
|
|
"Id:{:>15} {:>2} {:.2}/s {:.3}E/d {:.2} {}",
|
2024-03-02 00:08:56 +08:00
|
|
|
i,
|
|
|
|
id,
|
2024-03-02 01:38:13 +08:00
|
|
|
run_speed,
|
|
|
|
run_speed * 8.64 / 1_0000.0,
|
|
|
|
d_t.as_secs_f64(),
|
|
|
|
// 根据对比上一段运行速度 输出 emoji
|
|
|
|
// ⬆️ ➡️ ⬇️
|
|
|
|
if new_run_speed > run_speed {
|
|
|
|
"⬆️"
|
|
|
|
} else if new_run_speed < run_speed {
|
|
|
|
"⬇️"
|
|
|
|
} else {
|
|
|
|
"➡️"
|
|
|
|
}
|
2024-03-02 00:08:56 +08:00
|
|
|
);
|
2024-03-02 01:38:13 +08:00
|
|
|
run_speed = new_run_speed;
|
2024-03-01 22:38:29 +08:00
|
|
|
start_time = std::time::Instant::now();
|
2024-02-29 00:25:19 +08:00
|
|
|
k = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-28 23:33:59 +08:00
|
|
|
|
2024-02-28 19:04:57 +08:00
|
|
|
fn main() {
|
2024-02-28 23:33:59 +08:00
|
|
|
tracing_subscriber::fmt::init();
|
2024-02-29 01:05:41 +08:00
|
|
|
let mut cli_arg = Command::parse();
|
2024-02-28 23:33:59 +08:00
|
|
|
|
|
|
|
// 将数据量处理成可被 thread_count 整除
|
2024-02-29 01:05:41 +08:00
|
|
|
let left = cli_arg.start % cli_arg.thread_count as u64;
|
2024-02-29 01:07:57 +08:00
|
|
|
cli_arg.end = cli_arg.end.wrapping_add(left);
|
2024-02-29 01:05:41 +08:00
|
|
|
|
2024-02-29 00:25:19 +08:00
|
|
|
let mut n = 0;
|
2024-02-29 01:05:41 +08:00
|
|
|
let mut threads = Vec::with_capacity(cli_arg.thread_count as usize);
|
2024-03-02 00:09:53 +08:00
|
|
|
let now = chrono::Local::now().format("%Y-%m-%d_%H-%M-%S").to_string();
|
|
|
|
// namerena-<team>-<time>.txt
|
2024-03-02 00:08:56 +08:00
|
|
|
// <time>: %Y-%m-%d-%H-%M-%S
|
2024-03-02 01:38:13 +08:00
|
|
|
let output_filename = format!("namerena-{}-{}.txt", cli_arg.team, now);
|
2024-03-02 00:09:53 +08:00
|
|
|
let out_path = PathBuf::from(format!("./namerena/{}", output_filename));
|
|
|
|
info!("输出文件: {:?}", out_path);
|
|
|
|
// 先创建文件夹
|
|
|
|
if let Err(e) = std::fs::create_dir_all(&out_path.parent().unwrap()) {
|
|
|
|
warn!("创建文件夹失败: {}", e);
|
|
|
|
}
|
|
|
|
// 再创建文件
|
|
|
|
if let Err(e) = std::fs::File::create(&out_path) {
|
|
|
|
warn!("创建文件失败: {}", e);
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("start: {} end: {}", cli_arg.start, cli_arg.end);
|
|
|
|
info!("thread_count: {}", cli_arg.thread_count);
|
2024-03-02 01:43:18 +08:00
|
|
|
info!("八围预期: {}", cli_arg.prop_expect);
|
2024-03-02 00:09:53 +08:00
|
|
|
info!("team: {}", cli_arg.team);
|
|
|
|
info!("output: {:?}", out_path);
|
|
|
|
|
2024-02-29 01:05:41 +08:00
|
|
|
for i in 0..cli_arg.thread_count {
|
2024-02-29 00:25:19 +08:00
|
|
|
n += 1;
|
2024-03-02 00:09:53 +08:00
|
|
|
let cli = cli_arg.clone();
|
|
|
|
let out_path = out_path.clone();
|
2024-02-29 00:25:19 +08:00
|
|
|
let thread_name = format!("thread_{}", i);
|
|
|
|
threads.push(std::thread::spawn(move || {
|
|
|
|
info!("线程 {} 开始计算", thread_name);
|
2024-03-02 00:08:56 +08:00
|
|
|
cacl(
|
2024-03-02 01:39:04 +08:00
|
|
|
cli,
|
|
|
|
n,
|
2024-03-02 00:09:53 +08:00
|
|
|
&out_path,
|
2024-03-02 00:08:56 +08:00
|
|
|
);
|
2024-02-29 00:25:19 +08:00
|
|
|
info!("线程 {} 结束计算", thread_name);
|
|
|
|
}));
|
2024-02-28 23:33:59 +08:00
|
|
|
}
|
2024-02-29 00:25:19 +08:00
|
|
|
info!("开始计算");
|
2024-02-28 23:33:59 +08:00
|
|
|
|
|
|
|
for t in threads {
|
|
|
|
t.join().unwrap();
|
|
|
|
}
|
2024-02-28 19:04:57 +08:00
|
|
|
}
|