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

Dart实现固定长度整数数组n选2组合 模拟抽2张卡牌逻辑

问题描述

您好,感谢阅读我的问题:
我正在参加编程挑战赛,目前遇到了开发难题。
需求如下:基于存储整数数组的父Stack节点,生成所有可能的状态实例:从第一个数组(draw,即牌堆)中移除2个元素,放入第二个数组(hand,即手牌)。逻辑类似卡牌游戏场景:共有10种卡牌,每次抽2张,需要枚举所有可能的抽牌结果。
现有基础代码框架如下,已给出一种可行结果的示例,需要补全逻辑获取所有可能的抽牌情况:

class Stack {

  Stack? p;
  List<Stack> child = [];
  List<int> hand = [];
  List<int> draw = [];

  @override
  String toString() => "hand ${hand} draw ${draw}";  
}

void generate( Stack _ )
{
  //...
  //  Generate all combine 2 from card
}

void main() {
  
  Stack start = new Stack();
  start.draw = [ 0 , 3 , 2 , 0 , 0 , 1 , 2 , 0 , 1 , 2 ];
  start.hand = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ];
  
  generate(start);
  
  //  A solution
  Stack aChild = new Stack();
  aChild.draw = [ 0 , 1 , 2 , 0 , 0 , 1 , 2 , 0 , 1 , 2 ];
  aChild.hand = [ 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ];
  start.child.add( aChild );

  print(start);
  print(aChild);
}

给出的运行结果示例:

hand [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] draw [0, 3, 2, 0, 0, 1, 2, 0, 1, 2]
hand [0, 2, 0, 0, 0, 0, 0, 0, 0, 0] draw [0, 1, 2, 0, 0, 1, 2, 0, 1, 2]

代码可在Dartpad上直接运行,需要补全generate函数:实现从draw数组中选取2个元素的所有合法组合,为每一种组合生成对应的子Stack节点(同步更新子节点的draw、hand数组取值),并将子节点加入父节点的child列表中。

实现思路

首先明确数组含义:draw和hand数组长度固定为10,索引对应卡牌种类ID,数组值对应该种类卡牌的数量,同种类卡牌无差别。抽2张牌的所有合法组合分两类枚举,避免重复生成状态:

  • 抽到2张相同种类的卡牌:遍历每种卡牌,若该卡牌在牌堆中剩余数量≥2,则生成对应子状态
  • 抽到2张不同种类的卡牌:遍历所有i<j的卡牌种类对,若两种卡牌在牌堆中剩余数量都≥1,则生成对应子状态
补全后的完整代码
class Stack {
  Stack? p;
  List<Stack> child = [];
  List<int> hand = [];
  List<int> draw = [];

  @override
  String toString() => "hand ${hand} draw ${draw}";  
}

void generate(Stack parent) {
  parent.child.clear();
  final cardTypeCount = parent.draw.length;

  // 枚举抽2张相同卡牌的情况
  for (int i = 0; i < cardTypeCount; i++) {
    if (parent.draw[i] >= 2) {
      final child = Stack();
      child.p = parent;
      child.draw = List.from(parent.draw);
      child.hand = List.from(parent.hand);
      child.draw[i] -= 2;
      child.hand[i] += 2;
      parent.child.add(child);
    }
  }

  // 枚举抽2张不同卡牌的情况,i<j避免重复枚举(i,j)和(j,i)的等价组合
  for (int i = 0; i < cardTypeCount; i++) {
    if (parent.draw[i] < 1) continue;
    for (int j = i + 1; j < cardTypeCount; j++) {
      if (parent.draw[j] >= 1) {
        final child = Stack();
        child.p = parent;
        child.draw = List.from(parent.draw);
        child.hand = List.from(parent.hand);
        child.draw[i] -= 1;
        child.draw[j] -= 1;
        child.hand[i] += 1;
        child.hand[j] += 1;
        parent.child.add(child);
      }
    }
  }
}

void main() {
  Stack start = Stack();
  start.draw = [0, 3, 2, 0, 0, 1, 2, 0, 1, 2];
  start.hand = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  
  generate(start);
  
  print(start);
  // 打印所有生成的合法抽牌子状态
  for (final c in start.child) {
    print(c);
  }
}
逻辑验证

示例中给出的抽2张ID为1的卡牌的状态,会在「抽2张相同卡牌」的逻辑分支中自动生成,和预期结果完全匹配。所有枚举的子状态无重复、无遗漏,覆盖了抽2张牌的全部可能结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:09:21