如何实现Python中Viki AI类生成不重复的Dot坐标?
解决Viki类生成不重复Dot坐标的方案
核心思路是给AI角色Viki维护一个已使用坐标集合,每次生成新坐标时先检查是否已被使用,直到找到未被占用的单元格,再将该坐标标记为已使用。以下是完整的可运行代码实现:
1. 基础类定义
首先完善Dot类,确保它可以被正确比较和存入集合:
class Dot: def __init__(self, x, y): self.x = x self.y = y # 定义两个Dot相等的条件:x和y都相同 def __eq__(self, other): if not isinstance(other, Dot): return False return self.x == other.x and self.y == other.y # 实现哈希方法,让Dot可以存入集合 def __hash__(self): return hash((self.x, self.y)) def __repr__(self): return f"Dot({self.x}, {self.y})"
然后定义Player父类,规范子类的方法接口:
from abc import ABC, abstractmethod import random class Player(ABC): @abstractmethod def make_move(self, board_size): # board_size是棋盘的尺寸,比如(10,10)表示10x10的棋盘 pass
2. Viki类实现(AI角色)
在Viki类中维护已使用坐标的集合,生成坐标时循环校验:
class Viki(Player): def __init__(self): self.used_dots = set() # 存储已选过的Dot def make_move(self, board_size): max_x, max_y = board_size while True: # 生成随机坐标(假设坐标从0开始) x = random.randint(0, max_x - 1) y = random.randint(0, max_y - 1) new_dot = Dot(x, y) # 检查是否未被使用 if new_dot not in self.used_dots: self.used_dots.add(new_dot) return new_dot # 可选:添加棋盘已满的判断,防止死循环 if len(self.used_dots) == max_x * max_y: raise ValueError("棋盘已无可用单元格")
3. Human类实现(人类玩家)
作为对比,实现简单的人类玩家输入逻辑:
class Human(Player): def make_move(self, board_size): max_x, max_y = board_size while True: try: x = int(input("请输入X坐标:")) y = int(input("请输入Y坐标:")) if 0 <= x < max_x and 0 <= y < max_y: return Dot(x, y) else: print(f"坐标超出范围,请输入0到{max_x-1}之间的X,0到{max_y-1}之间的Y") except ValueError: print("请输入有效的整数坐标")
4. 测试验证
运行以下代码可以验证Viki生成的坐标不会重复:
if __name__ == "__main__": viki = Viki() board_size = (5, 5) # 5x5的棋盘 # 生成10个坐标,检查是否重复 moves = [viki.make_move(board_size) for _ in range(10)] print("Viki生成的坐标:") print(moves) # 验证是否有重复 unique_moves = set(moves) print(f"生成的10个坐标中,唯一坐标数量:{len(unique_moves)}")
关键细节说明
- Dot类的
__eq__和__hash__:这两个方法是让Dot可以被集合正确识别的核心,集合依赖哈希值判断元素是否存在,__eq__定义相等逻辑,__hash__生成唯一哈希值。 - 使用集合而非列表:集合的
in操作是O(1)时间复杂度,比列表的O(n)效率高得多,尤其是棋盘较大时,性能差异会很明显。 - 循环终止条件:添加了棋盘已满的判断,避免当棋盘没有可用单元格时进入无限循环。
内容的提问来源于stack exchange,提问作者iMAN
相关产品推荐
相关产品推荐

