Files
Api/DouyinApi.Services/Naming/FallbackNameGenerator.cs
2025-11-05 17:26:45 +08:00

291 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using DouyinApi.Model.Naming;
#nullable enable
namespace DouyinApi.Services.Naming;
internal sealed class FallbackNameGenerator
{
private const int TargetCount = 5;
private static readonly string[] ElementOrder = { "木", "火", "土", "金", "水" };
private readonly CharacterLibrary _library = new();
public IReadOnlyList<NamingSuggestion> Generate(NamingRequest request, BaziProfile profile)
{
var surname = request.Surname;
var isSingle = string.Equals(request.NameLength, "single", StringComparison.OrdinalIgnoreCase);
var gender = NormalizeGender(request.Gender);
var results = new List<NamingSuggestion>();
var usedCharacters = new HashSet<string>(StringComparer.Ordinal);
var usedNames = new HashSet<string>(StringComparer.Ordinal);
var sequence = BuildElementSequence(profile);
var attempts = 0;
while (results.Count < TargetCount && attempts < 80)
{
var primaryElement = sequence[attempts % sequence.Count];
var first = _library.Pick(primaryElement, gender, usedCharacters);
if (first == null)
{
attempts++;
continue;
}
if (isSingle)
{
var fullName = surname + first.Character;
if (usedNames.Add(fullName))
{
results.Add(new NamingSuggestion
{
Name = fullName,
Meaning = first.Meaning,
ElementReason = BuildSingleReason(profile, first)
});
usedCharacters.Add(first.Character);
}
attempts++;
continue;
}
var tempUsed = new HashSet<string>(usedCharacters, StringComparer.Ordinal)
{
first.Character
};
var secondaryElement = sequence[(attempts + 1) % sequence.Count];
var second = _library.Pick(secondaryElement, gender, tempUsed);
if (second == null)
{
attempts++;
continue;
}
var givenName = first.Character + second.Character;
var full = surname + givenName;
if (usedNames.Add(full))
{
results.Add(new NamingSuggestion
{
Name = full,
Meaning = $"{first.Meaning}{second.Meaning}",
ElementReason = BuildDoubleReason(profile, first, second)
});
usedCharacters.Add(first.Character);
usedCharacters.Add(second.Character);
}
attempts++;
}
return results;
}
private static string NormalizeGender(string gender)
{
return string.Equals(gender, "female", StringComparison.OrdinalIgnoreCase) ? "female" : "male";
}
private static List<string> BuildElementSequence(BaziProfile profile)
{
var sequence = new List<string>();
if (profile.WeakElements.Count > 0)
{
sequence.AddRange(profile.WeakElements);
}
foreach (var element in ElementOrder)
{
if (!sequence.Contains(element))
{
sequence.Add(element);
}
}
return sequence;
}
private static string BuildSingleReason(BaziProfile profile, CharacterProfile profileChar)
{
if (!profile.IsBalanced && profile.WeakElements.Contains(profileChar.Element))
{
return $"命局中{profileChar.Element}势偏弱,选用同属性的“{profileChar.Character}”以补足生机。";
}
return $"“{profileChar.Character}”属{profileChar.Element},与命局相协,凸显个人气韵。";
}
private static string BuildDoubleReason(BaziProfile profile, CharacterProfile first, CharacterProfile second)
{
var clauses = new List<string>();
if (!profile.IsBalanced && profile.WeakElements.Contains(first.Element))
{
clauses.Add($"命局中{first.Element}势弱,首取“{first.Character}”以增添此行之力");
}
else
{
clauses.Add($"“{first.Character}”属{first.Element},奠定名字的核心气场");
}
if (first.Element == second.Element)
{
clauses.Add($"再以同为{second.Element}属性的“{second.Character}”相辅,巩固能量");
}
else if (!profile.IsBalanced && profile.WeakElements.Contains(second.Element))
{
clauses.Add($"辅以{second.Element}属性“{second.Character}”同步补益");
}
else
{
clauses.Add($"叠加{second.Element}属性“{second.Character}”,使五行流转更趋和谐");
}
return string.Join("", clauses) + "。";
}
}
internal sealed class CharacterLibrary
{
private readonly Dictionary<string, List<CharacterProfile>> _profiles;
public CharacterLibrary()
{
_profiles = new Dictionary<string, List<CharacterProfile>>(StringComparer.Ordinal)
{
["木"] = new List<CharacterProfile>
{
new("林", "木", 8, "林木森郁,生机盎然", GenderAffinity.Neutral),
new("杉", "木", 7, "杉木挺拔,坚韧自持", GenderAffinity.Male),
new("柏", "木", 9, "柏树常青,守正不渝", GenderAffinity.Male),
new("桐", "木", 10, "梧桐清雅,自带高洁", GenderAffinity.Neutral),
new("柯", "木", 9, "柯木坚劲,胸怀正义", GenderAffinity.Male),
new("梓", "木", 11, "梓木葱郁,延续家风", GenderAffinity.Neutral),
new("芸", "木", 10, "芸草幽香,温婉灵动", GenderAffinity.Female),
new("茜", "木", 9, "茜草明艳,朝气蓬勃", GenderAffinity.Female)
},
["火"] = new List<CharacterProfile>
{
new("炜", "火", 9, "炜火明亮,奋发向上", GenderAffinity.Male),
new("炎", "火", 8, "炎光熠熠,激情澎湃", GenderAffinity.Male),
new("晗", "火", 11, "晨晗初照,温暖柔和", GenderAffinity.Female),
new("晟", "火", 11, "晟意光盛,事业昌隆", GenderAffinity.Male),
new("旭", "火", 6, "旭日东升,胸怀朝阳", GenderAffinity.Neutral),
new("烁", "火", 10, "烁光璀璨,灵动敏捷", GenderAffinity.Neutral),
new("炫", "火", 9, "炫彩熠熠,才华外露", GenderAffinity.Neutral)
},
["土"] = new List<CharacterProfile>
{
new("坤", "土", 8, "坤厚载物,包容从容", GenderAffinity.Neutral),
new("均", "土", 7, "均衡端稳,踏实可靠", GenderAffinity.Neutral),
new("垣", "土", 9, "垣墙坚实,守护安宁", GenderAffinity.Neutral),
new("城", "土", 9, "城池稳固,守正不移", GenderAffinity.Male),
new("岳", "土", 8, "山岳巍峨,志向高远", GenderAffinity.Male),
new("培", "土", 11, "培土厚植,涵养成长", GenderAffinity.Neutral),
new("堇", "土", 12, "堇色沉静,内敛温润", GenderAffinity.Female),
new("坦", "土", 8, "坦荡诚笃,胸怀光明", GenderAffinity.Male)
},
["金"] = new List<CharacterProfile>
{
new("钧", "金", 9, "钧衡公正,持中守衡", GenderAffinity.Neutral),
new("铭", "金", 11, "铭记初心,彰显才华", GenderAffinity.Neutral),
new("锐", "金", 11, "锋芒锐利,果敢决断", GenderAffinity.Male),
new("钦", "金", 9, "钦敬谦和,端方稳重", GenderAffinity.Neutral),
new("钥", "金", 9, "钥启智慧,开拓视野", GenderAffinity.Neutral),
new("铠", "金", 12, "铠甲护身,坚毅勇敢", GenderAffinity.Male),
new("钰", "金", 10, "钰石珍贵,坚贞明亮", GenderAffinity.Female)
},
["水"] = new List<CharacterProfile>
{
new("泽", "水", 9, "泽润万物,胸怀宽广", GenderAffinity.Neutral),
new("泓", "水", 8, "泓水清澈,心境澄明", GenderAffinity.Neutral),
new("润", "水", 10, "润泽柔润,涵养细腻", GenderAffinity.Female),
new("涵", "水", 11, "涵容自守,温婉内敛", GenderAffinity.Female),
new("沐", "水", 7, "沐浴春风,清新怡然", GenderAffinity.Neutral),
new("泊", "水", 8, "泊舟安然,沉稳淡泊", GenderAffinity.Male),
new("洵", "水", 9, "洵美诚笃,信义笃实", GenderAffinity.Male),
new("沁", "水", 8, "沁香流淌,气质清雅", GenderAffinity.Female)
}
};
}
public CharacterProfile? Pick(string element, string gender, HashSet<string> usedCharacters)
{
if (!_profiles.TryGetValue(element, out var candidates))
{
return null;
}
// 优先匹配性别偏好
foreach (var profile in candidates)
{
if (usedCharacters.Contains(profile.Character))
{
continue;
}
if (profile.Affinity == GenderAffinity.Neutral ||
(profile.Affinity == GenderAffinity.Male && gender == "male") ||
(profile.Affinity == GenderAffinity.Female && gender == "female"))
{
if (profile.StrokeCount <= 12)
{
return profile;
}
}
}
// 兜底选择中性字
foreach (var profile in candidates)
{
if (usedCharacters.Contains(profile.Character))
{
continue;
}
if (profile.Affinity == GenderAffinity.Neutral && profile.StrokeCount <= 12)
{
return profile;
}
}
return null;
}
}
internal sealed class CharacterProfile
{
public CharacterProfile(string character, string element, int strokeCount, string meaning, GenderAffinity affinity)
{
Character = character;
Element = element;
StrokeCount = strokeCount;
Meaning = meaning;
Affinity = affinity;
}
public string Character { get; }
public string Element { get; }
public int StrokeCount { get; }
public string Meaning { get; }
public GenderAffinity Affinity { get; }
}
internal enum GenderAffinity
{
Neutral,
Male,
Female
}