简介:这份资源是Java实现的六爻起卦排盘小程序完整源码,面向对周易占卜文化感兴趣、希望用编程方式实现传统起卦流程的开发者与学习者。程序按六爻占卜规则模拟硬币抛掷或蓍草操作,随机生成由六个爻组成的卦象,并依据六十四卦卦辞自动完成解读,省去手工排盘与查卦的繁琐步骤。资源包共17个文件,以7个xml配置文件、5个class字节码、3个java源码及2个gitignore为主,压缩后约28KB,涵盖起卦、卦象分析与结果展示等模块,结构清晰,便于理解面向对象设计在传统占卜场景中的落地方式。目前已有268人学习下载,适合作为Java入门练手项目或传统文化与编程结合的参考案例,读者可从中获取完整的排盘算法思路、模块划分方式与可运行的工程骨架,并在此基础上扩展人机交互或个性化占卜功能。
1. 六爻排盘小程序:从「摇一卦」到可运行源码,Java 后端到底要做什么
很多人第一次听到「六爻起卦排盘小程序」,脑子里浮现的是玄学界面加动画铜钱,但真正落到 Java 代码层面,它其实是一套规则确定、状态可枚举、结果可复现的排盘计算系统。用户在小程序里点「摇卦」,后端要完成的是:记录六次摇动结果(老阴、少阳、少阴、老阳),映射成六爻的阴阳与动静,再叠加干支、月建、日辰、六亲、六神、世应、旬空这些固定规则,最后输出一份结构化排盘。它解决的不是「预测准不准」,而是「排得对不对、算得快不快、结果能不能稳定复现」。适合谁?适合有 Java 基础、想找一个规则明确又能练手的后端项目的人,也适合做小程序商城、工具类应用、fatemaster.ai 排盘这类产品时,需要自己掌控排盘逻辑而不是调第三方接口的开发者。源码的核心价值,是把散落在古籍和口传里的排盘规则,翻译成可测试的 Java 方法。
2. 六爻排盘的规则底座:干支、五行与六亲怎么用 Java 表达
2.1 先定数据结构,再谈算法
排盘这件事,最怕一上来就写if-else堆规则。我一般会先把「一个卦」拆成几个不可变对象:Yao(爻)、Gua(卦)、Pan(盘)。Yao只需要三个字段:位置(初爻到上爻)、阴阳(0/1)、动静(静爻/动爻)。Gua持有六个Yao,外加卦名、卦宫、世应位置。Pan则是在Gua之上叠加时间维度:起卦时的年、月、日、时四柱,以及由此推导出的六亲、六神、旬空、月破、日破。
为什么强调不可变?因为排盘结果一旦生成,后续所有展示、分享、存档都应该是同一份数据。如果对象可变,很容易在「重新排盘」时把旧盘改脏。用 Java 的record或者final字段加构造器就能做到。下面是一个最小化的爻对象定义:
public record Yao(int position, int yinYang, boolean moving) { // position: 1~6,1 为初爻 // yinYang: 0 表示阴,1 表示阳 // moving: true 表示动爻(老阴或老阳) public Yao { if (position < 1 || position > 6) { throw new IllegalArgumentException("爻位必须在 1~6 之间"); } if (yinYang != 0 && yinYang != 1) { throw new IllegalArgumentException("阴阳只能用 0 或 1 表示"); } } }这段代码没有玄学,只有约束。参数说明:position决定爻位,yinYang决定阴阳,moving决定是否发动。逻辑说明:构造器里做边界检查,避免后续排盘时出现「第七爻」这种脏数据。很多新手会忽略校验,结果在小程序端传参异常时,后端直接算出乱七八糟的卦。
2.2 干支与五行的映射表怎么落地
六爻排盘离不开干支。年、月、日、时各有一个天干一个地支,共八个字。Java 里不要用魔法字符串,而是用枚举加数组。天干十个、地支十二个,六十甲子循环。我一般会写一个GanZhi工具类,提供两个核心方法:根据公历日期推算日柱干支,以及根据年份推算年柱干支。月柱和时柱则依赖节气与时辰,这部分如果做完整版,需要引入节气表;如果只是排盘演示,可以先用简化规则,但要在代码里明确标注「简化版,未处理节气交接」。
public enum TianGan { JIA("甲"), YI("乙"), BING("丙"), DING("丁"), WU("戊"), JI("己"), GENG("庚"), XIN("辛"), REN("壬"), GUI("癸"); private final String name; TianGan(String name) { this.name = name; } public String getName() { return name; } public static TianGan fromIndex(int index) { return values()[Math.floorMod(index, 10)]; } }地支同理,十二个枚举值。五行则用另一个枚举WuXing,并给每个天干、地支绑定五行属性。六亲(父母、兄弟、子孙、妻财、官鬼)的推导规则是:以卦宫五行为「我」,看各爻地支五行与「我」的生克关系。生我者父母,我生者子孙,克我者官鬼,我克者妻财,比和者兄弟。这段逻辑用switch或映射表都能写,关键是把规则集中在一个类里,不要散落在各个 Service 中。
2.3 装卦与世应:规则固定,但顺序不能乱
装卦是指给六爻配上地支、六亲、六神。六神(青龙、朱雀、勾陈、腾蛇、白虎、玄武)的起始位置由日干决定:甲乙日起青龙,丙丁日起朱雀,戊日起勾陈,己日起腾蛇,庚辛日起白虎,壬癸日起玄武。然后按爻位从初爻到上爻依次排列。世应位置则由卦宫和卦序决定,八宫卦各有固定的世爻位置,比如本宫卦世在六爻,一世卦世在初爻,等等。
这部分最容易翻车的地方是顺序。六神要按爻位从下往上排,但很多人写循环时从 0 开始却忘了初爻对应索引 0。世应如果查表,表要写全六十四卦,不能只写八个宫的首卦。我一般会用一个Map<String, Integer>存世爻位置,键是卦名,值是爻位。这样虽然「笨」,但可读性和可维护性最好,也方便后续对照古籍校验。
3. 起卦与排盘的核心算法:从摇卦到完整盘面的 Java 实现
3.1 摇卦模拟:随机数怎么用才不「玄学」
小程序端通常提供两种起卦方式:手动输入六次摇动结果,或者点击按钮模拟摇卦。模拟摇卦的本质是生成六个爻,每个爻有三种可能:老阴(三背)、少阳(两背一字)、少阴(两字一背)、老阳(三字)。用 Java 实现时,可以用ThreadLocalRandom生成 0~3 的随机数,映射到四种结果。注意:老阴和老阳是动爻,会变卦;少阳和少阴是静爻,不变。
public static Yao randomYao(int position) { int r = ThreadLocalRandom.current().nextInt(4); // 0: 老阴(动), 1: 少阳(静), 2: 少阴(静), 3: 老阳(动) return switch (r) { case 0 -> new Yao(position, 0, true); case 1 -> new Yao(position, 1, false); case 2 -> new Yao(position, 0, false); case 3 -> new Yao(position, 1, true); default -> throw new IllegalStateException("随机数越界"); }; }逻辑说明:nextInt(4)返回 0 到 3,等概率。参数说明:position由调用方传入 1 到 6。这段代码没有用Math.random(),因为ThreadLocalRandom在并发环境下更稳,小程序后端如果同时处理多个起卦请求,不会因为随机数种子竞争导致结果异常。另外,不要用SecureRandom,排盘不需要密码学强度,用它会拖慢响应。
3.2 变卦与动爻:老阴老阳怎么处理
六爻排盘里,动爻是重点。老阴(阴动)变阳,老阳(阳动)变阴。变卦就是把所有动爻取反后得到的新卦。Java 实现时,先根据六个Yao确定本卦卦名,再根据动爻生成变卦卦名。卦名的确定依赖上下卦的组合:初、二、三爻为下卦,四、五、上爻为上卦。八卦各有三爻二进制表示,比如乾为 111,坤为 000,震为 001(从下往上读)。用Map<Integer, String>存八卦索引到卦名的映射,再组合成六十四卦名。
public static String guaName(List<Yao> yaos) { int lower = toBinary(yaos.subList(0, 3)); // 初、二、三 int upper = toBinary(yaos.subList(3, 6)); // 四、五、上 return BA_GUA_MAP.get(lower) + BA_GUA_MAP.get(upper); } private static int toBinary(List<Yao> three) { int result = 0; for (int i = 0; i < 3; i++) { if (three.get(i).yinYang() == 1) { result |= (1 << i); } } return result; }逻辑说明:toBinary把三爻的阴阳转成 0~7 的整数,低位对应初爻。参数说明:yaos必须按初爻到上爻的顺序传入。注意:八卦的二进制顺序各家略有差异,但只要你自己的映射表一致,排出来的卦名就是对的。我一般会在单元测试里把六十四卦全跑一遍,对照古籍确认无误。
3.3 六亲、六神、旬空的批量计算
当本卦和变卦都确定后,就要给每一爻配上六亲、六神,并计算旬空。旬空由日柱决定:甲子旬中戌亥空,甲戌旬中申酉空,以此类推。Java 里可以用一个Map<String, String[]>存旬空表,键是旬首,值是空亡的两个地支。六亲的计算前面说过,以卦宫五行为基准。六神则按日干起,顺序固定。
这部分代码量不大,但顺序敏感。我一般会写一个PanBuilder类,按固定步骤执行:1)确定本卦卦宫;2)装地支;3)定六亲;4)排六神;5)算旬空;6)标世应;7)处理动爻与变卦。每一步都输出中间结果,方便调试。如果最后盘面不对,可以逐层排查是哪一步错了,而不是对着最终结果发呆。
4. 小程序端与 Java 后端的接口设计:请求、响应与状态管理
4.1 起卦接口的入参与出参
小程序端发起卦请求时,通常只传一个sessionId或者用户标识,后端负责生成六个爻并返回完整盘面。如果支持手动输入,则传入六个爻的阴阳和动静。接口设计要遵循「前端轻、后端重」的原则,因为排盘规则复杂,放在后端更容易统一维护和升级。下面是一个典型的请求体:
{ "mode": "auto", "yaos": [] }mode为auto时,后端随机生成;为manual时,yaos数组必须包含六个对象,每个对象有yinYang和moving字段。响应体则包含本卦、变卦、六爻详情、四柱、旬空、六神等。注意:不要在小程序端做排盘计算,一是 JavaScript 处理干支容易出错,二是规则更新后需要发版,而小程序发版审核周期不可控。
4.2 用 Spring Boot 暴露排盘服务
Java 后端我一般用 Spring Boot,因为生态成熟,写 REST 接口快。一个最小的 Controller 如下:
@RestController @RequestMapping("/api/divination") public class DivinationController { private final PanService panService; public DivinationController(PanService panService) { this.panService = panService; } @PostMapping("/cast") public PanResponse cast(@RequestBody CastRequest request) { List<Yao> yaos = request.mode().equals("auto") ? YaoGenerator.randomSix() : request.yaos().stream() .map(y -> new Yao(y.position(), y.yinYang(), y.moving())) .toList(); Pan pan = panService.buildPan(yaos, LocalDateTime.now()); return PanResponse.from(pan); } }逻辑说明:cast方法根据mode决定是随机起卦还是手动起卦,然后调用PanService构建盘面。参数说明:CastRequest和PanResponse用 record 定义,字段与前端约定一致。注意:LocalDateTime.now()取的是服务器时间,如果用户分布在不同时区,要考虑时区转换,否则日柱可能算错。我一般会要求前端传一个timezone字段,或者统一用东八区。
4.3 会话与状态:排盘结果要不要存
如果只是即时排盘,可以不存数据库,直接返回。但如果用户想「保存卦例」或者「历史记录」,就需要持久化。我一般会存三张表:user、divination_record、yao_detail。divination_record存盘面主信息(起卦时间、本卦、变卦、四柱),yao_detail存六爻的明细。这样查询历史时不用反序列化大 JSON,也方便做统计。注意:不要用 Redis 存排盘结果,因为排盘数据量小但要求持久,Redis 重启可能丢数据,而且历史记录需要长期保存。
5. 避坑与排查:六爻排盘源码里最容易翻车的 5 个地方
5.1 日柱算错,整个盘全废
现象:排出来的六亲、旬空、六神全不对,但卦名是对的。原因:日柱干支推算错误,导致后续所有依赖日柱的规则都错。解决:单独写一个DayGanZhiTest,用已知公历日期对照万年历验证。注意:公历转日柱有公式,但闰年、月份天数容易算错,建议直接用java.time.LocalDate的toEpochDay()做基准偏移,再取模六十甲子。
5.2 动爻变卦时阴阳取反搞混
现象:变卦卦名不对,或者动爻数量对不上。原因:老阴是阴动,变阳;老阳是阳动,变阴。有人把「动」直接当成「取反」,但静爻不能取反。解决:在Yao里明确moving字段,变卦生成时只对moving == true的爻取反,其余保持不变。
5.3 六神起始位置记错
现象:六神顺序整体偏移一位。原因:日干对应的六神起始规则记混,比如把「甲乙起青龙」记成「甲己起青龙」。解决:把规则写成常量表,并在代码注释里标明出处。测试时用五个不同日干各跑一遍,检查初爻六神是否符合预期。
5.4 旬空表不完整
现象:某些日期排出来的旬空为空。原因:旬空表只写了几个旬,没写全。解决:六十甲子共六旬,每旬十个干支,空亡两个地支。把六旬全部写进Map,键用旬首干支,值用两个地支字符串。测试时遍历六十天,确保每天都能查到旬空。
5.5 小程序端传参顺序颠倒
现象:手动起卦时,卦象和用户输入完全相反。原因:小程序端习惯从上往下展示爻,但六爻规则是初爻在下。前端传数组时如果按从上到下,后端按从下到上解析,就会颠倒。解决:接口文档里明确「数组顺序为初爻到上爻」,并在后端做一次校验,如果发现顺序可疑(比如第一个元素是上爻),可以拒绝或自动反转。我一般会在响应里回显爻位,方便前端核对。
6. 进阶技巧:用单元测试锁死排盘规则,让源码可维护
排盘规则一旦写错,用户可能不会立刻发现,但懂行的人一眼就能看出问题。所以我在写完核心算法后,一定会补一套单元测试,把「已知卦例」固化下来。比如手动构造六个爻,断言卦名、世应、六亲、旬空全部符合预期。这样以后改代码,只要测试还绿,就说明没破坏原有规则。
@Test void testQianGua() { List<Yao> yaos = List.of( new Yao(1, 1, false), new Yao(2, 1, false), new Yao(3, 1, false), new Yao(4, 1, false), new Yao(5, 1, false), new Yao(6, 1, false) ); Pan pan = panService.buildPan(yaos, LocalDateTime.of(2025, 1, 1, 12, 0)); assertEquals("乾为天", pan.benGua().name()); assertEquals(6, pan.benGua().shiYaoPosition()); assertEquals(3, pan.benGua().yingYaoPosition()); }逻辑说明:六个阳爻静爻组成乾为天,世在上爻(位置 6),应在三爻(位置 3)。参数说明:LocalDateTime固定一个时间,保证日柱、旬空可复现。注意:测试里的时间要选一个已知日柱的日期,否则断言旬空时会依赖外部万年历。我一般会选一个甲子日,这样旬空是戌亥,容易记。
另一个技巧是把排盘结果导出为 JSON 快照。每次修改规则后,跑一遍所有测试卦例,对比 JSON 差异。如果差异只出现在预期变更的字段,就说明改动可控;如果出现意外差异,就要回头检查。这个习惯帮我省了很多「改一处崩三处」的后悔药。
最后说一个我自己的教训:早期我为了图快,把六亲计算直接写在 Controller 里,结果后来想加一个「按六亲筛选爻」的功能,发现逻辑散落各处,改起来非常痛苦。后来重构成PanService加LiuQinCalculator,才把规则收拢。如果你也打算做六爻排盘小程序,建议一开始就把规则层和接口层分开,哪怕多写几个类,后面会轻松很多。希望帮到你。
本文还有配套的精品资源,点击获取