You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.6 KiB
79 lines
2.6 KiB
import { RankDataManager } from '../../../manager/RankDataManager';
|
|
import { aiLog } from './AiLog';
|
|
|
|
/** 普通字策略类型(Rank.aiusetext 两档) */
|
|
export enum AiTextPolicyType {
|
|
/** 类型 1:等级优先 */
|
|
Type1 = 1,
|
|
/** 类型 2:单字冲级 */
|
|
Type2 = 2,
|
|
}
|
|
|
|
/** 开战时按对手段位权重抽样,整局固定 */
|
|
export interface AiBattlePersonality {
|
|
/** 本局普通字策略类型 */
|
|
readonly textPolicy: AiTextPolicyType;
|
|
}
|
|
|
|
/** 从 Rank.aiusetext 加权抽样整局策略 */
|
|
export class AiBattlePersonalityFactory {
|
|
/**
|
|
* 按对手段位配表抽样 personality。
|
|
* @param opponentRankId 对手段位 id
|
|
* @param seed 随机种子
|
|
*/
|
|
roll(opponentRankId: number, seed: number): AiBattlePersonality | null {
|
|
const rank = RankDataManager.getRankConfig(opponentRankId);
|
|
if (!rank) {
|
|
console.warn('[AiBattlePersonalityFactory] Rank missing,使用默认策略', opponentRankId);
|
|
return {
|
|
textPolicy: AiTextPolicyType.Type1,
|
|
};
|
|
}
|
|
const text = this._pickType(rank.aiusetext, 2, seed ^ 0x85ebca6b, 1);
|
|
if (text == null) {
|
|
console.warn('[AiBattlePersonalityFactory] 权重无效,使用默认策略', opponentRankId);
|
|
return {
|
|
textPolicy: AiTextPolicyType.Type1,
|
|
};
|
|
}
|
|
return {
|
|
textPolicy: text as AiTextPolicyType,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 加权抽类型(返回 1-based 类型号)。
|
|
* @param weights 权重数组
|
|
* @param expectLen 期望长度
|
|
* @param seed 种子
|
|
* @param typeBase 起始类型号
|
|
*/
|
|
private _pickType(weights: number[] | undefined, expectLen: number, seed: number, typeBase: number): number | null {
|
|
if (!weights || weights.length !== expectLen) {
|
|
aiLog('[AiBattlePersonalityFactory] weight length invalid', expectLen);
|
|
return null;
|
|
}
|
|
const w: number[] = [];
|
|
let total = 0;
|
|
for (let i = 0; i < expectLen; i++) {
|
|
const v = Math.max(0, Math.floor(Number(weights[i]) || 0));
|
|
w.push(v);
|
|
total += v;
|
|
}
|
|
if (total <= 0) {
|
|
aiLog('[AiBattlePersonalityFactory] weight total <= 0');
|
|
return null;
|
|
}
|
|
let x = (Math.floor(Number(seed) || 0) >>> 0) || 1;
|
|
x ^= x << 13;
|
|
x ^= x >>> 17;
|
|
x ^= x << 5;
|
|
let roll = ((x >>> 0) / 4294967296) * total;
|
|
for (let i = 0; i < expectLen; i++) {
|
|
roll -= w[i];
|
|
if (roll < 0) return typeBase + i;
|
|
}
|
|
return typeBase + expectLen - 1;
|
|
}
|
|
}
|
|
|