feat: 实现起卦、设置与积分系统

This commit is contained in:
qzl
2026-04-03 16:56:47 +08:00
parent 31594558eb
commit f245eec5f6
170 changed files with 20728 additions and 328 deletions
@@ -0,0 +1,100 @@
enum DivinationMethod { manual, auto }
enum QuestionType {
career,
love,
wealth,
fortune,
dream,
health,
study,
search,
other,
}
enum YaoType { undetermined, youngYang, youngYin, oldYang, oldYin }
class DivinationParams {
const DivinationParams({
required this.method,
required this.questionType,
required this.question,
required this.divinationTime,
required this.coinBalance,
required this.userId,
});
final DivinationMethod method;
final QuestionType questionType;
final String question;
final DateTime divinationTime;
final int coinBalance;
final String userId;
DivinationParams copyWith({
DivinationMethod? method,
QuestionType? questionType,
String? question,
DateTime? divinationTime,
int? coinBalance,
String? userId,
}) {
return DivinationParams(
method: method ?? this.method,
questionType: questionType ?? this.questionType,
question: question ?? this.question,
divinationTime: divinationTime ?? this.divinationTime,
coinBalance: coinBalance ?? this.coinBalance,
userId: userId ?? this.userId,
);
}
Map<String, dynamic> toPayload() {
return <String, dynamic>{
'method': method.name,
'questionType': questionType.name,
'question': question,
'divinationTime': divinationTime.toIso8601String(),
'coinBalance': coinBalance,
'userId': userId,
};
}
String toBinary(List<YaoType> yaoStates) {
return yaoStates
.map(
(v) => switch (v) {
YaoType.youngYang || YaoType.oldYang => '1',
_ => '0',
},
)
.join();
}
String toChangedBinary(List<YaoType> yaoStates) {
return yaoStates
.map(
(v) => switch (v) {
YaoType.youngYang => '1',
YaoType.youngYin => '0',
YaoType.oldYang => '0',
YaoType.oldYin => '1',
YaoType.undetermined => '0',
},
)
.join();
}
}
class DivinationMockData {
static DivinationParams initial() {
return DivinationParams(
method: DivinationMethod.manual,
questionType: QuestionType.career,
question: '',
divinationTime: DateTime.now(),
coinBalance: 8,
userId: 'mock_user_10001',
);
}
}
@@ -0,0 +1,91 @@
import 'divination_params.dart';
class DivinationResultData {
const DivinationResultData({
required this.params,
required this.binaryCode,
required this.changedBinaryCode,
required this.guaName,
required this.targetGuaName,
required this.upperName,
required this.lowerName,
required this.signType,
required this.keywords,
required this.conclusion,
required this.analysis,
required this.suggestion,
required this.ganzhi,
required this.wuXingStatus,
required this.yaoLines,
required this.targetYaoLines,
});
final DivinationParams params;
final String binaryCode;
final String changedBinaryCode;
final String guaName;
final String targetGuaName;
final String upperName;
final String lowerName;
final String signType;
final String keywords;
final String conclusion;
final String analysis;
final String suggestion;
final GanzhiData ganzhi;
final Map<String, String> wuXingStatus;
final List<YaoLineData> yaoLines;
final List<YaoLineData> targetYaoLines;
bool get hasChangingYao => binaryCode != changedBinaryCode;
}
class GanzhiData {
const GanzhiData({
required this.yearGanZhi,
required this.monthGanZhi,
required this.dayGanZhi,
required this.timeGanZhi,
required this.yearKongWang,
required this.monthKongWang,
required this.dayKongWang,
required this.timeKongWang,
required this.yueJian,
required this.riChen,
required this.yuePo,
required this.riChong,
});
final String yearGanZhi;
final String monthGanZhi;
final String dayGanZhi;
final String timeGanZhi;
final String yearKongWang;
final String monthKongWang;
final String dayKongWang;
final String timeKongWang;
final String yueJian;
final String riChen;
final String yuePo;
final String riChong;
}
class YaoLineData {
const YaoLineData({
required this.index,
required this.spirit,
required this.relation,
required this.branch,
required this.element,
required this.type,
required this.mark,
});
final int index;
final String spirit;
final String relation;
final String branch;
final String element;
final YaoType type;
final String mark;
}
@@ -0,0 +1,222 @@
import '../models/divination_params.dart';
import '../models/divination_result.dart';
class DivinationResultBuilder {
DivinationResultData build({
required DivinationParams params,
required List<YaoType> yaoStates,
}) {
final binaryCode = params.toBinary(yaoStates);
final changedBinaryCode = params.toChangedBinary(yaoStates);
final baseHexagram = _hexagramMap[binaryCode];
final changedHexagram = _hexagramMap[changedBinaryCode];
if (baseHexagram == null || changedHexagram == null) {
throw StateError(
'Unknown hexagram mapping for binary=$binaryCode changed=$changedBinaryCode',
);
}
final signType = _signByStates(yaoStates);
final content = _mockContent(
params.questionType,
params.question,
signType,
);
final lineData = _buildYaoLines(yaoStates, false);
final targetStates = _toChangedStates(yaoStates);
final targetLineData = _buildYaoLines(targetStates, true);
return DivinationResultData(
params: params,
binaryCode: binaryCode,
changedBinaryCode: changedBinaryCode,
guaName: baseHexagram.name,
targetGuaName: changedHexagram.name,
upperName: baseHexagram.upper,
lowerName: baseHexagram.lower,
signType: signType,
keywords: content.keywords,
conclusion: content.conclusion,
analysis: content.analysis,
suggestion: content.suggestion,
ganzhi: const GanzhiData(
yearGanZhi: '丙午',
monthGanZhi: '甲辰',
dayGanZhi: '辛亥',
timeGanZhi: '乙巳',
yearKongWang: '子丑',
monthKongWang: '申酉',
dayKongWang: '寅卯',
timeKongWang: '午未',
yueJian: '',
riChen: '',
yuePo: '',
riChong: '',
),
wuXingStatus: const {'': '', '': '', '': '', '': '', '': ''},
yaoLines: lineData,
targetYaoLines: targetLineData,
);
}
List<YaoLineData> _buildYaoLines(List<YaoType> states, bool target) {
const spirits = ['', '', '', '', '', ''];
const relations = ['父母', '兄弟', '官鬼', '妻财', '子孙', '父母'];
const branches = ['', '', '', '', '', ''];
const elements = ['', '', '', '', '', ''];
return List<YaoLineData>.generate(6, (idx) {
final mark = switch (idx) {
1 => '',
4 => '',
_ => '',
};
return YaoLineData(
index: idx,
spirit: spirits[idx],
relation: relations[idx],
branch: branches[idx],
element: elements[idx],
type: states[idx],
mark: target ? '' : mark,
);
});
}
List<YaoType> _toChangedStates(List<YaoType> source) {
return source.map((state) {
return switch (state) {
YaoType.oldYang => YaoType.youngYin,
YaoType.oldYin => YaoType.youngYang,
_ => state,
};
}).toList();
}
String _signByStates(List<YaoType> states) {
final dynamicCount = states
.where((e) => e == YaoType.oldYang || e == YaoType.oldYin)
.length;
if (dynamicCount <= 1) {
return '上上签';
}
if (dynamicCount <= 3) {
return '中上签';
}
return '中下签';
}
_MockContent _mockContent(
QuestionType type,
String question,
String signType,
) {
final domain = switch (type) {
QuestionType.career || QuestionType.study => '事业与成长',
QuestionType.love => '关系与情感',
QuestionType.wealth => '财富与资源',
QuestionType.fortune => '阶段运势',
QuestionType.dream => '潜意识信号',
QuestionType.health => '身心节律',
QuestionType.search => '寻物线索',
QuestionType.other => '综合事项',
};
return _MockContent(
keywords: '$signType · $domain',
conclusion: '这个卦象的结果为$signType。你关注的“$question”处于可推进阶段,当前节奏重在稳步而行,不宜急进。',
analysis:
'本卦显示外在条件逐步成形,内在决心也在增强。若短期遇到反复,通常是资源重组与信息修正,并非方向错误。建议将目标拆分为可验证的小节点,持续复盘。',
suggestion:
'建议一:先定三周内可执行动作并按日推进。\n建议二:重要决定留有缓冲期,避免情绪化判断。\n建议三:遇到阻滞先调整节奏,再补关键资源。',
);
}
}
class _MockContent {
const _MockContent({
required this.keywords,
required this.conclusion,
required this.analysis,
required this.suggestion,
});
final String keywords;
final String conclusion;
final String analysis;
final String suggestion;
}
class _HexagramShort {
const _HexagramShort(this.name, this.upper, this.lower);
final String name;
final String upper;
final String lower;
}
const Map<String, _HexagramShort> _hexagramMap = {
'111111': _HexagramShort('乾为天', '', ''),
'011111': _HexagramShort('天风姤', '', ''),
'001111': _HexagramShort('天山遁', '', ''),
'000111': _HexagramShort('天地否', '', ''),
'000011': _HexagramShort('风地观', '', ''),
'000001': _HexagramShort('山地剥', '', ''),
'000101': _HexagramShort('火地晋', '', ''),
'111101': _HexagramShort('火天大有', '', ''),
'010010': _HexagramShort('坎为水', '', ''),
'110010': _HexagramShort('水泽节', '', ''),
'100010': _HexagramShort('水雷屯', '', ''),
'101010': _HexagramShort('水火既济', '', ''),
'101110': _HexagramShort('泽火革', '', ''),
'101100': _HexagramShort('雷火丰', '', ''),
'101000': _HexagramShort('地火明夷', '', ''),
'010000': _HexagramShort('地水师', '', ''),
'001001': _HexagramShort('艮为山', '', ''),
'101001': _HexagramShort('山火贲', '', ''),
'111001': _HexagramShort('山天大畜', '', ''),
'110001': _HexagramShort('山泽损', '', ''),
'110101': _HexagramShort('火泽睽', '', ''),
'110111': _HexagramShort('天泽履', '', ''),
'110011': _HexagramShort('风泽中孚', '', ''),
'001011': _HexagramShort('风山渐', '', ''),
'100100': _HexagramShort('震为雷', '', ''),
'000100': _HexagramShort('雷地豫', '', ''),
'010100': _HexagramShort('雷水解', '', ''),
'011100': _HexagramShort('雷风恒', '', ''),
'011000': _HexagramShort('地风升', '', ''),
'011010': _HexagramShort('水风井', '', ''),
'011110': _HexagramShort('泽风大过', '', ''),
'100110': _HexagramShort('泽雷随', '', ''),
'011011': _HexagramShort('巽为风', '', ''),
'111011': _HexagramShort('风天小畜', '', ''),
'101011': _HexagramShort('风火家人', '', ''),
'100011': _HexagramShort('风雷益', '', ''),
'100111': _HexagramShort('天雷无妄', '', ''),
'100101': _HexagramShort('火雷噬嗑', '', ''),
'100001': _HexagramShort('山雷颐', '', ''),
'011001': _HexagramShort('山风蛊', '', ''),
'101101': _HexagramShort('离为火', '', ''),
'001101': _HexagramShort('火山旅', '', ''),
'011101': _HexagramShort('火风鼎', '', ''),
'010101': _HexagramShort('火水未济', '', ''),
'010001': _HexagramShort('山水蒙', '', ''),
'010011': _HexagramShort('风水涣', '', ''),
'010111': _HexagramShort('天水讼', '', ''),
'101111': _HexagramShort('天火同人', '', ''),
'000000': _HexagramShort('坤为地', '', ''),
'100000': _HexagramShort('地雷复', '', ''),
'110000': _HexagramShort('地泽临', '', ''),
'111000': _HexagramShort('地天泰', '', ''),
'111100': _HexagramShort('雷天大壮', '', ''),
'111110': _HexagramShort('泽天夬', '', ''),
'111010': _HexagramShort('水天需', '', ''),
'000010': _HexagramShort('水地比', '', ''),
'110110': _HexagramShort('兑为泽', '', ''),
'010110': _HexagramShort('泽水困', '', ''),
'000110': _HexagramShort('泽地萃', '', ''),
'001110': _HexagramShort('泽山咸', '', ''),
'001010': _HexagramShort('水山蹇', '', ''),
'001000': _HexagramShort('地山谦', '', ''),
'001100': _HexagramShort('雷山小过', '', ''),
'110100': _HexagramShort('雷泽归妹', '', ''),
};