test1
This commit is contained in:
parent
315417b8a8
commit
becfc8c634
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -468,6 +468,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"lazy_static",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["time"] }
|
||||
chrono = "0.4.34"
|
||||
colored = "2.1.0"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[features]
|
||||
default = ["simd"]
|
||||
|
127
src/cacluate.rs
Normal file
127
src/cacluate.rs
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
use crate::name::{Namer, TeamNamer};
|
||||
|
||||
use std::{io::Write, path::PathBuf};
|
||||
|
||||
use base16384::Base16384Utf8;
|
||||
use tracing::{info, warn};
|
||||
use colored::Colorize;
|
||||
|
||||
pub fn show_name(namer: &Namer) -> String {
|
||||
format!(
|
||||
"HP|{} 攻|{} 防|{} 速|{} 敏|{} 魔|{} 抗|{} 智|{} 八围:{}",
|
||||
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.name_prop[7],
|
||||
namer.get_property()
|
||||
)
|
||||
}
|
||||
|
||||
/// 根据 u64 生成对应的 name
|
||||
/// 转换成 base 16384
|
||||
/// 禁用:
|
||||
/// U00 ~ U1F ,换行,制表符 等
|
||||
/// ? , 问号
|
||||
/// U2000 - U202F , unicode特殊空格 等
|
||||
/// 不可以空格开头
|
||||
#[inline(always)]
|
||||
pub fn gen_name(id: u64) -> String {
|
||||
let id_bytes = id.to_be_bytes();
|
||||
Base16384Utf8::encode(id_bytes.as_slice())
|
||||
}
|
||||
|
||||
pub struct CacluateConfig {
|
||||
/// 开始的 id
|
||||
pub start: u64,
|
||||
/// 结束的 id
|
||||
pub end: u64,
|
||||
/// 线程数
|
||||
pub thread_count: u32,
|
||||
/// 八围预期值
|
||||
pub prop_expect: u32,
|
||||
/// 八围允许范围
|
||||
pub prop_allow: u32,
|
||||
/// 队伍名称
|
||||
pub team: String,
|
||||
/// 预期状态输出时间间隔 (秒)
|
||||
pub report_interval: u64,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn cacl(config: CacluateConfig, id: u64, outfile: &PathBuf) {
|
||||
// 初始猜测的时间间隔
|
||||
let mut report_interval = 10000; // 第一次猜测测 1w 次, 获取初始数据
|
||||
let mut run_speed = 0.0;
|
||||
let mut start_time = std::time::Instant::now();
|
||||
let mut k: u64 = 0;
|
||||
let mut get_count: u32 = 0;
|
||||
// 提前准备好 team_namer
|
||||
let team_namer = TeamNamer::new(&config.team).unwrap();
|
||||
|
||||
for i in (config.start + id..config.end).step_by(config.thread_count as usize) {
|
||||
let name = gen_name(i as u64);
|
||||
let namer = Namer::new_from_team_namer_unchecked(&team_namer, name.as_str());
|
||||
let prop = namer.get_property();
|
||||
|
||||
if (prop + config.prop_allow as f32) > config.prop_expect as f32 {
|
||||
get_count += 1;
|
||||
let name = gen_name(i as u64);
|
||||
let full_name = format!("{}@{}", name, config.team);
|
||||
info!("Id:{:>15}|{}|{}", i, full_name, show_name(&namer));
|
||||
// 写入 (写到最后一行)
|
||||
match std::fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(outfile)
|
||||
.and_then(|mut file| file.write(format!("{}\n", full_name).as_bytes()))
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
warn!("写入文件<{:?}>失败: {}", outfile, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
if k >= report_interval as u64 {
|
||||
let now = std::time::Instant::now();
|
||||
let d_t: std::time::Duration = now.duration_since(start_time);
|
||||
let new_run_speed = k as f64 / d_t.as_secs_f64();
|
||||
// 预估剩余时间
|
||||
let wait_time = (config.end - i) / config.thread_count as u64 / new_run_speed as u64;
|
||||
let wait_time = chrono::Duration::seconds(wait_time as i64);
|
||||
// 转换成 时:分:秒
|
||||
// 根据实际运行速率来调整 report_interval
|
||||
report_interval = config.report_interval * new_run_speed as u64;
|
||||
info!(
|
||||
"|{:>2}|Id:{:>15}|{:6.2}/s {:>3.3}E/d {:>5.2}{}|{:<3}|预计:{}:{}:{}|",
|
||||
id,
|
||||
i,
|
||||
new_run_speed,
|
||||
new_run_speed * 8.64 / 1_0000.0,
|
||||
d_t.as_secs_f64(),
|
||||
// 根据对比上一段运行速度 输出 emoji
|
||||
// ⬆️ ➡️ ⬇️
|
||||
if new_run_speed > run_speed {
|
||||
"⬆️".green()
|
||||
} else if new_run_speed < run_speed {
|
||||
// 橙色
|
||||
"⬇️".red()
|
||||
} else {
|
||||
"➡️".blue()
|
||||
},
|
||||
get_count,
|
||||
wait_time.num_hours(),
|
||||
wait_time.num_minutes() % 60,
|
||||
wait_time.num_seconds() % 60
|
||||
);
|
||||
run_speed = new_run_speed;
|
||||
start_time = std::time::Instant::now();
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -74,4 +74,32 @@ pub fn predict_13(name: &Namer) -> f64 {
|
||||
sum
|
||||
}
|
||||
|
||||
/*function Poly(x) {
|
||||
var xp = new Array()
|
||||
for (let y = 0; y < 1034; y++) {
|
||||
var l = 44
|
||||
var i = 0, p = 0, q = 0, r = 0
|
||||
var j = y
|
||||
for (let k = 0; k < 45; k++) {
|
||||
i++;
|
||||
if (i > 2) p++;
|
||||
q = j;
|
||||
j = j - l + p;
|
||||
if (j < 0) break;
|
||||
}
|
||||
if (i == 1) r = x[q]
|
||||
if (i > 1) {
|
||||
r = x[p] * x[p + q]
|
||||
}
|
||||
xp[y] = r
|
||||
}
|
||||
return xp
|
||||
} */
|
||||
pub fn poly(name: &Namer) -> [f64; 1034] {
|
||||
let mut result = [0.0; 1034];
|
||||
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn predict_20(name: &Namer) -> f64 { 0.0 }
|
||||
|
@ -1,5 +1,5 @@
|
||||
const MODEL: [f64; 1035] = [
|
||||
-10030.80226727643822,
|
||||
pub const BASE: f64 = -10030.80226727643822;
|
||||
pub const MODEL: [f64; 1034] = [
|
||||
4.23812347791656,
|
||||
64.98665601677689,
|
||||
2.08468428104832,
|
||||
@ -1036,8 +1036,8 @@ const MODEL: [f64; 1035] = [
|
||||
0.00530345515535,
|
||||
];
|
||||
|
||||
const MODEL_QD: [f64; 1035] = [
|
||||
106835.41068098737742,
|
||||
pub const BASE_QD: f64 = 106835.41068098737742;
|
||||
pub const MODEL_QD: [f64; 1034] = [
|
||||
-113.56364767281147,
|
||||
-122.71766831211856,
|
||||
-318.24366544790598,
|
||||
|
0
src/generate.rs
Normal file
0
src/generate.rs
Normal file
122
src/main.rs
122
src/main.rs
@ -1,42 +1,18 @@
|
||||
#![feature(portable_simd)]
|
||||
#![feature(slice_swap_unchecked)]
|
||||
|
||||
mod cacluate;
|
||||
mod evaluate;
|
||||
mod generate;
|
||||
mod name;
|
||||
|
||||
use std::{io::Write, path::PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use base16384::Base16384Utf8;
|
||||
use clap::Parser;
|
||||
use colored::Colorize;
|
||||
use tracing::{info, warn};
|
||||
|
||||
/// 根据 u64 生成对应的 name
|
||||
/// 转换成 base 16384
|
||||
/// 禁用:
|
||||
/// U00 ~ U1F ,换行,制表符 等
|
||||
/// ? , 问号
|
||||
/// U2000 - U202F , unicode特殊空格 等
|
||||
/// 不可以空格开头
|
||||
#[inline(always)]
|
||||
pub fn gen_name(id: u64) -> String {
|
||||
let id_bytes = id.to_be_bytes();
|
||||
Base16384Utf8::encode(id_bytes.as_slice())
|
||||
}
|
||||
use crate::cacluate::CacluateConfig;
|
||||
|
||||
pub fn show_name(namer: &name::Namer) -> String {
|
||||
format!(
|
||||
"HP|{} 攻|{} 防|{} 速|{} 敏|{} 魔|{} 抗|{} 智|{} 八围:{}",
|
||||
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.name_prop[7],
|
||||
namer.get_property()
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const allow_d: u32 = 10;
|
||||
@ -63,80 +39,16 @@ pub struct Command {
|
||||
pub report_interval: u64,
|
||||
}
|
||||
|
||||
/// 大概的预计速度
|
||||
/// 来自 5600X 的运行效率
|
||||
pub const GUESS_SPEED: u64 = 623772;
|
||||
|
||||
#[inline(always)]
|
||||
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;
|
||||
let mut start_time = std::time::Instant::now();
|
||||
let mut k: u64 = 0;
|
||||
let mut get_count: u32 = 0;
|
||||
// 提前准备好 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) {
|
||||
let name = gen_name(i as u64);
|
||||
let namer = name::Namer::new_from_team_namer_unchecked(&team_namer, name.as_str());
|
||||
let prop = namer.get_property();
|
||||
|
||||
if (prop + allow_d as f32) > config.prop_expect as f32 {
|
||||
get_count += 1;
|
||||
let name = gen_name(i as u64);
|
||||
let full_name = format!("{}@{}", name, config.team);
|
||||
info!("Id:{:>15}|{}|{}", i, full_name, show_name(&namer));
|
||||
// 写入 (写到最后一行)
|
||||
match std::fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(outfile)
|
||||
.and_then(|mut file| file.write(format!("{}\n", full_name).as_bytes()))
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
warn!("写入文件<{:?}>失败: {}", outfile, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
k += 1;
|
||||
if k >= report_interval as u64 {
|
||||
let now = std::time::Instant::now();
|
||||
let d_t: std::time::Duration = now.duration_since(start_time);
|
||||
let new_run_speed = k as f64 / d_t.as_secs_f64();
|
||||
// 预估剩余时间
|
||||
let wait_time = (config.end - i) / config.thread_count as u64 / new_run_speed as u64;
|
||||
let wait_time = chrono::Duration::seconds(wait_time as i64);
|
||||
// 转换成 时:分:秒
|
||||
// 根据实际运行速率来调整 report_interval
|
||||
report_interval = config.report_interval * new_run_speed as u64;
|
||||
info!(
|
||||
"|{:>2}|Id:{:>15}|{:6.2}/s {:>3.3}E/d {:>5.2}{}|{:<3}|预计:{}:{}:{}|",
|
||||
id,
|
||||
i,
|
||||
new_run_speed,
|
||||
new_run_speed * 8.64 / 1_0000.0,
|
||||
d_t.as_secs_f64(),
|
||||
// 根据对比上一段运行速度 输出 emoji
|
||||
// ⬆️ ➡️ ⬇️
|
||||
if new_run_speed > run_speed {
|
||||
"⬆️".green()
|
||||
} else if new_run_speed < run_speed {
|
||||
// 橙色
|
||||
"⬇️".red()
|
||||
} else {
|
||||
"➡️".blue()
|
||||
},
|
||||
get_count,
|
||||
wait_time.num_hours(),
|
||||
wait_time.num_minutes() % 60,
|
||||
wait_time.num_seconds() % 60
|
||||
);
|
||||
run_speed = new_run_speed;
|
||||
start_time = std::time::Instant::now();
|
||||
k = 0;
|
||||
impl Command {
|
||||
pub fn as_cacl_config(&self) -> CacluateConfig {
|
||||
CacluateConfig {
|
||||
start: self.start,
|
||||
end: self.end,
|
||||
thread_count: self.thread_count,
|
||||
prop_expect: self.prop_expect,
|
||||
prop_allow: allow_d,
|
||||
team: self.team.clone(),
|
||||
report_interval: self.report_interval,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,12 +82,12 @@ fn main() {
|
||||
|
||||
for i in 0..cli_arg.thread_count {
|
||||
n += 1;
|
||||
let cli = cli_arg.clone();
|
||||
let config = cli_arg.as_cacl_config();
|
||||
let out_path = out_path.clone();
|
||||
let thread_name = format!("thread_{}", i);
|
||||
threads.push(std::thread::spawn(move || {
|
||||
info!("线程 {} 开始计算", thread_name);
|
||||
cacl(cli, n, &out_path);
|
||||
cacluate::cacl(config, n, &out_path);
|
||||
info!("线程 {} 结束计算", thread_name);
|
||||
}));
|
||||
}
|
||||
|
86
src/name.rs
86
src/name.rs
@ -1,10 +1,26 @@
|
||||
use std::cmp::min;
|
||||
#[cfg(feature = "simd")]
|
||||
use std::simd::cmp::SimdPartialOrd;
|
||||
#[cfg(feature = "simd")]
|
||||
use std::simd::u8x64;
|
||||
|
||||
use tracing::warn;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
|
||||
// let simd_181 = u8x64::splat(181);
|
||||
// let simd_199 = u8x64::splat(199);
|
||||
// let simd_128 = u8x64::splat(128);
|
||||
// let simd_53 = u8x64::splat(53);
|
||||
// let simd_63 = u8x64::splat(63);
|
||||
// let simd_32 = u8x64::splat(32);
|
||||
lazy_static! {
|
||||
static ref SIMD_199: u8x64 = u8x64::splat(199);
|
||||
static ref SIMD_181: u8x64 = u8x64::splat(181);
|
||||
static ref SIMD_160: u8x64 = u8x64::splat(160);
|
||||
static ref SIMD_128: u8x64 = u8x64::splat(128);
|
||||
static ref SIMD_63: u8x64 = u8x64::splat(63);
|
||||
static ref SIMD_53: u8x64 = u8x64::splat(53);
|
||||
static ref SIMD_32: u8x64 = u8x64::splat(32);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn median<T>(x: T, y: T, z: T) -> T
|
||||
@ -137,18 +153,14 @@ impl Namer {
|
||||
let name_len = name_bytes.len();
|
||||
let b_name_len = name_len + 1;
|
||||
for _ in 0..2 {
|
||||
// 手动处理 0 的问题
|
||||
// 手动swap
|
||||
let mut s = 0_u8;
|
||||
val.swap(s as usize, 0);
|
||||
unsafe { val.swap_unchecked(s as usize, 0) };
|
||||
let mut k = 0;
|
||||
for i in 0..256 {
|
||||
// s = s.wrapping_add(name_bytes[i % name_len]);
|
||||
s = s.wrapping_add(match i % b_name_len {
|
||||
0 => 0,
|
||||
k => name_bytes[k - 1],
|
||||
});
|
||||
s = s.wrapping_add(if k == 0 { 0 } else { name_bytes[k - 1] });
|
||||
s = s.wrapping_add(val[i]);
|
||||
val.swap(i, s as usize);
|
||||
unsafe { val.swap_unchecked(i, s as usize) }
|
||||
k = if k == b_name_len - 1 { 0 } else { k + 1 };
|
||||
}
|
||||
}
|
||||
// simd 优化
|
||||
@ -156,33 +168,27 @@ impl Namer {
|
||||
{
|
||||
let mut simd_val = val.clone();
|
||||
let mut simd_val_b = [0_u8; 256];
|
||||
let mut simd_target = [false; 256];
|
||||
let simd_181 = u8x64::splat(181);
|
||||
let simd_160 = u8x64::splat(160);
|
||||
let simd_63 = u8x64::splat(63);
|
||||
let simd_88 = u8x64::splat(88);
|
||||
let simd_217 = u8x64::splat(217);
|
||||
|
||||
for i in (0..256).step_by(64) {
|
||||
// 一次性加载64个数字
|
||||
let mut x = u8x64::from_slice(&simd_val[i..]);
|
||||
x = x * simd_181 + simd_160;
|
||||
x = x * *SIMD_181 + *SIMD_160;
|
||||
// 写入到 simd_val
|
||||
x.copy_to_slice(&mut simd_val[i..]);
|
||||
// 提前判断 > 88 && < 217
|
||||
let mask = x.simd_ge(simd_88) & x.simd_lt(simd_217);
|
||||
// 写入到 simd_target
|
||||
let mask: [bool; 64] = mask.to_array();
|
||||
simd_target[i..i + 64].copy_from_slice(&mask);
|
||||
|
||||
x = x & simd_63;
|
||||
x.copy_to_slice(&mut simd_val_b[i..]);
|
||||
let y = x & *SIMD_63;
|
||||
y.copy_to_slice(&mut simd_val_b[i..]);
|
||||
}
|
||||
|
||||
let mut mod_count = 0;
|
||||
|
||||
for i in 0..96 {
|
||||
if simd_target[i] {
|
||||
name_base[mod_count as usize] = simd_val_b[i];
|
||||
if simd_val[i] > 88 && simd_val[i] < 217 {
|
||||
// name_base[mod_count as usize] = simd_val_b[i];
|
||||
unsafe {
|
||||
*name_base.get_unchecked_mut(mod_count as usize) =
|
||||
*simd_val_b.get_unchecked(i);
|
||||
}
|
||||
mod_count += 1;
|
||||
}
|
||||
if mod_count > 30 {
|
||||
@ -191,8 +197,12 @@ impl Namer {
|
||||
}
|
||||
if mod_count < 31 {
|
||||
for i in 96..256 {
|
||||
if simd_target[i] {
|
||||
name_base[mod_count as usize] = simd_val_b[i];
|
||||
if simd_val[i] > 88 && simd_val[i] < 217 {
|
||||
// name_base[mod_count as usize] = simd_val_b[i];
|
||||
unsafe {
|
||||
*name_base.get_unchecked_mut(mod_count as usize) =
|
||||
*simd_val_b.get_unchecked(i);
|
||||
}
|
||||
mod_count += 1;
|
||||
}
|
||||
if mod_count > 30 {
|
||||
@ -252,18 +262,12 @@ impl Namer {
|
||||
{
|
||||
let mut simd_val = self.val.clone();
|
||||
let mut simd_val_b = self.val.clone();
|
||||
let simd_181 = u8x64::splat(181);
|
||||
let simd_199 = u8x64::splat(199);
|
||||
let simd_128 = u8x64::splat(128);
|
||||
let simd_53 = u8x64::splat(53);
|
||||
let simd_63 = u8x64::splat(63);
|
||||
let simd_32 = u8x64::splat(32);
|
||||
|
||||
for i in (0..256).step_by(64) {
|
||||
let mut x = u8x64::from_slice(&simd_val[i..]);
|
||||
let mut y = u8x64::from_slice(&simd_val_b[i..]);
|
||||
x = x * simd_181 + simd_199 & simd_128;
|
||||
y = y * simd_53 & simd_63 ^ simd_32;
|
||||
x = x * *SIMD_181 + *SIMD_199 & *SIMD_128;
|
||||
y = y * *SIMD_53 & *SIMD_63 ^ *SIMD_32;
|
||||
x.copy_to_slice(&mut simd_val[i..]);
|
||||
y.copy_to_slice(&mut simd_val_b[i..]);
|
||||
}
|
||||
@ -393,10 +397,6 @@ mod test {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
assert_eq!(namer.name_base.to_vec(), base_name_vec);
|
||||
namer.update_skill();
|
||||
// update skill 之后才会是完整的 name
|
||||
|
||||
let full_base_name_vec: Vec<u8> = vec![
|
||||
53, 0, 40, 4, 58, 61, 37, 46, 56, 51, 21, 20, 27, 17, 15, 26, 13, 30, 52, 63, 36, 30,
|
||||
57, 34, 22, 37, 35, 6, 12, 25, 50, 49, 59, 23, 49, 27, 51, 58, 39, 28, 60, 20, 31, 36,
|
||||
@ -405,6 +405,10 @@ mod test {
|
||||
41, 55, 5, 34, 3, 7, 33, 33, 45, 16, 16, 32, 43, 18, 44, 22, 14, 17, 10, 11, 53, 18,
|
||||
44, 19, 52, 2, 32, 12, 8, 2, 54, 26, 48, 8, 3, 63, 54, 19, 25,
|
||||
];
|
||||
assert_eq!(namer.name_base.to_vec(), base_name_vec);
|
||||
namer.update_skill();
|
||||
// update skill 之后才会是完整的 name
|
||||
|
||||
assert_eq!(namer.name_base.to_vec(), full_base_name_vec);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user