You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)).

使用说明

  1. 确保加载了clpfd和lists库
  2. 执行查询isDobble(X),即可得到合法的55张Dobble卡牌集合

内容的提问来源于stack exchange,提问作者Prologer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:10:31