Prolog实现Dobble卡牌集遇栈溢出问题求解决方案
Prolog实现Dobble卡牌集的问题修正
现有代码的核心问题
1. isCard/1逻辑错误
sublist(C, Sym)参数顺序颠倒,应该先生成所有允许的符号列表,再判断卡牌是其子集- 未检查卡牌内符号唯一性,仅靠
length(C,8)无法保证符号不重复
2. oneMatch/2逻辑错误
- 用
permutation完全多余,会生成所有排列,导致计算量爆炸 ATail \= BTail不能保证两张牌仅有一个共同符号,这个条件只判断尾列表不相等,不涉及元素交集检查
3. isDobble/1逻辑缺陷
permutation(D, [DHead|DTail])属于冗余操作,且仅检查了第一张牌与其他牌的关系,未覆盖所有两两卡牌组合- 盲目生成55张牌的搜索空间过大,直接触发无限计算和栈溢出。Dobble卡牌集基于有限射影平面的数学结构,不能靠暴力搜索生成
修正后的代码
1. 基础依赖与isCard/1修正
:- use_module(library(clpfd)). :- use_module(library(lists)). isCard(C) :- length(C, 8), % 每张牌包含8个符号 all_distinct(C), % 确保卡牌内符号无重复 findall(S, between(1, 57, S), AllSymbols), subset(C, AllSymbols). % 卡牌符号属于允许的1-57范围
2. oneMatch/2修正
oneMatch(A, B) :- intersection(A, B, Common), % 计算两张牌的共同符号集合 length(Common, 1). % 共同符号数量恰好为1
3. 基于射影平面构造isDobble/1
Dobble对应阶为7的有限射影平面,利用这个数学性质可直接生成合法卡牌集,避免暴力搜索:
isDobble(D) :- % 生成第一类卡牌:包含符号1,加上连续7个符号的组(共7张) findall(Card, ( Start between(2, 50, 7), End is Start + 6, findall(S, between(Start, End, S), Syms), Card = [1|Syms] ), FirstCards), length(FirstCards, 7), % 生成第二类卡牌:模拟射影平面的斜线,共42张 findall(Card, ( M between(1, 7), B between(1, 7), findall(Sym, ( K between(0, 6), GroupStart is 2 + K * 7, Sym is GroupStart + ((M * K + B - 1) mod 7) ), Syms), append(Syms, [57], Card) ), SecondCards), length(SecondCards, 42), % 生成第三类卡牌:模拟射影平面的垂直线,共7张 findall(Card, ( K between(0, 6), findall(Sym, ( Y between(0, 6), Sym is 2 + Y * 7 + K ), Syms), append(Syms, [57], Card) ), ThirdCards), length(ThirdCards, 7), % 合并所有57张卡牌,截取前55张作为商用版Dobble集 append(FirstCards, SecondCards, Temp), append(Temp, ThirdCards, AllCards), length(AllCards, 57), append(D, _, AllCards), length(D, 55), % 验证所有卡牌符合规则 maplist(isCard, D), forall((member(A, D), member(B, D), A @< B), oneMatch(A, B)).
使用说明
- 确保加载了
clpfd和lists库 - 执行查询
isDobble(X),即可得到合法的55张Dobble卡牌集合
内容的提问来源于stack exchange,提问作者Prologer
相关产品推荐
相关产品推荐

