如何计算Connect4随机0/1落子列表的总可能组合数 优化循环效率
核心结论
你现在用固定100次循环的写法本质是无目标的随机采样,只要先按规则算出合法组合的总数量,把终止条件改成「收集到全部组合就退出」,就能完全消除多余迭代。如果要进一步把效率拉满,直接放弃随机采样逻辑,用枚举法可以做到零无效运算。
合法组合总数计算规则
按照你设定的生成规则(当前玩家先手落子,之后双方交替下满所有空位),合法组合的数量可以直接用数学组合数计算,不需要靠试错:
- 先算双方的棋子数,设空位数为
n:- 若
n为奇数:当前玩家比对手多1子,当前玩家棋子数为(n+1)//2,对手为(n-1)//2 - 若
n为偶数:双方棋子数相等,各占n//2个
- 若
- 总组合数 = 从
n个空位中选k个位置放当前玩家棋子的方案数,也就是数学上的组合数C(n, k)——因为只要当前玩家的位置确定,剩下的位置按交替规则自然就是对手的棋子,不需要额外排列。
举个你示例代码里的例子:调用create_all_combinations("O", 4)时,n=4是偶数,当前玩家O的棋子数是2,总组合数是C(4,2)=6,根本不需要跑100次,凑够6个合法组合就可以终止。
代码修改方案
1. 最小改动版(保留原随机逻辑,仅修正终止条件)
你原来的代码还有个隐藏bug:second_player变量会在循环内被反复修改,下一轮生成新组合时初始值会出错,需要每次迭代重置。修改后代码如下:
import math import random all_possible_combinations = [] def create_all_combinations(current_player, empty_squares): # 提前计算总合法组合数 current_piece_count = (empty_squares + 1) // 2 total_comb_num = math.comb(empty_squares, current_piece_count) second_player = "O" if current_player == "X" else "X" # 终止条件:收集齐所有组合立刻退出,不跑固定次数 while len(all_possible_combinations) < total_comb_num: current_comb = [0] * empty_squares # 第一个子固定是当前玩家 first_pos = random.randint(0, empty_squares - 1) current_comb[first_pos] = current_player # 每次生成新组合时重置对手标识,避免上一轮循环修改值的干扰 cur_p = second_player for _ in range(empty_squares - 1): # 找空位落子 rand_pos = random.randint(0, empty_squares - 1) while current_comb[rand_pos] != 0: rand_pos = random.randint(0, empty_squares - 1) current_comb[rand_pos] = cur_p # 交替切换执子方 cur_p = "O" if cur_p == "X" else "X" if current_comb not in all_possible_combinations: all_possible_combinations.append(current_comb) print(current_comb, first_pos) print(f"生成完成,总组合数:{len(all_possible_combinations)}") create_all_combinations("O", 4)
这个版本跑你给的示例参数时,最多十几次循环就能凑齐6个组合,不会跑到100次。
2. 最优效率版(放弃随机,直接枚举零无效迭代)
随机采样+去重的逻辑在空位数多的时候,会因为大量重复采样浪费性能。实际上你完全不需要随机,直接枚举所有合法位置组合就行,一次生成全部结果,连重试、去重都不需要:
import itertools def create_all_combinations_fast(current_player, empty_squares): second_player = "O" if current_player == "X" else "X" current_piece_count = (empty_squares + 1) // 2 all_combs = [] # 直接枚举所有当前玩家可以落子的位置组合 for current_positions in itertools.combinations(range(empty_squares), current_piece_count): comb = [0] * empty_squares # 填充当前玩家的棋子 for pos in current_positions: comb[pos] = current_player # 剩余位置填充对手棋子 for i in range(empty_squares): if comb[i] == 0: comb[i] = second_player all_combs.append(comb) return all_combs # 调用示例 combs = create_all_combinations_fast("O", 4) print(f"生成完成,总组合数:{len(combs)}")
这个版本不管空位数是多少,都只跑和组合数相等的次数,没有任何多余运算,空位数越大比随机方案的性能优势越明显。
内容的提问来源于stack exchange,提问作者Punzicul
相关产品推荐
相关产品推荐

