一、课设要求
基于A*算法的五子棋博弈系统
A)给出用 A*算法设计实现五子棋博弈的思想与方法。
B)设计实现五子棋博弈交互系统。
C)对不同的格局,以及不同的初始状态和目标状态,记录 A*算法的落棋求解结果。
分析A*算法设计实现五子棋博弈的有效性。
二、代码实现
注:该代码在码者编辑此文档时进行过微调,如有bug可评论或私信,感谢。
2.1 原代码
因为本人不擅长python,再加上从零开始也很浪费时间,所以直接去gitee上面找的现有代码进行修改。(原作者如有介意请联系删除)
2.2 核心代码
2.2.1 A*算法实现
open表:用于存储待评估的点;closed表:用于记录已经评估过的点;价值:价值越高,越容易获胜;代价:价值取反;
- 首先,将所有落子的邻接点放入open表中,放入的时候会进行落子评估,获取落子在一个点后的棋局价值;
- 从open表中取出价值最高的点;
- 落子判断,判断当前点是否合法、当前点是否在closed表中、当前搜索是否达到搜索深度(DEPTH);
- 将当前落子的所有邻接点放入open表,放入前也会进行价值计算;
- 循环第二步至第四步,直到到达循环出口(open表为空,达到递归深度);
代码:
def a_star_search():
open_list = [] # 所有带搜索的点
closed_set = {
} # 记录已经搜索过的点以及其价值评估分数
for point in list3:
neighbors = get_neighbors(point) # 取出所有落子的邻接点
for neighbor in neighbors:
if neighbor in list_all and neighbor not in list3 and neighbor not in closed_set.keys(): # 修改此处检查邻居是否在 closed_set 的键中
# 后续两个append()和remove()是为了评估落下评估点后的棋局状态(但实际还未落下),所以需要先添加进两个list中,之后再删除
list1.append(neighbor) # 将邻居加入AI列表
list2.append(neighbor) # 将邻居加入人类落子列表
if neighbor not in [node for (_, node) in open_list]: # 检查节点是否已经存在于open列表中
heapq.heappush(open_list, (-evaluation(True), neighbor)) # 将当前点加入open列表
# 从列表中删除刚刚加入的邻居
list1.remove(neighbor)
list2.remove(neighbor)
if not open_list:
return None
while open_list:
# 在a_star_search函数中修改取出具有最小代价的节点的行为
min_cost = min(open_list)[0] # 获取当前最小代价
min_cost_nodes = [node for cost, node in open_list if cost == min_cost] # 找到所有具有最小代价的节点列表
current_node = random.choice(min_cost_nodes) # 从具有相同最小代价的节点列表中随机选择一个节点
open_list.remove((min_cost, current_node)) # 从open_list中移除选择的节点
current_cost = min_cost
if current_node not in closed_set:
if current_node not in list3:
closed_set[current_node] = current_cost # 记录当前点和评估分数
if len(closed_set) >= DEPTH: # 到达搜索深度
max_score_node = min(closed_set, key=closed_set.get) # 找到评估分数最大的点(代价最小,即价值最大)
return max_score_node
neighbors = get_neighbors(current_node)
for neighbor in neighbors:
if neighbor in list_all and neighbor not in list3 and neighbor not in closed_set.keys(): # 修改此处检查邻居是否在 closed_set 的键中
list1.append(neighbor) # 将邻居加入AI列表
list2.append(neighbor) # 将邻居加入列表
if neighbor not in [node for (_, node) in open_list]: # 检查节点是否不在open列表中
heapq.heappush(open_list, (-evaluation(True), neighbor)) # 将节点推入open列表
# 从列表中删除刚刚加入的邻居
list1.remove(neighbor)
list2.remove(neighbor)
# 如果搜索完所有可搜索的点时仍未到达搜索深度,则返回评估分数最大的点
max_score_node = min(closed_set, key=closed_set.get)
return max_score_node
2.2.2 评估函数
1> 评估模型
当某一行/列构成评估模型中的状态时,便相应的累加记分。
# 棋型的评估分数,例:落子为* * 1 1 0 0 0 * * 时的棋型得10分 1为计算分数的对象的棋子,0为可落子的空位置
shape_score = [(10, (1, 1, 0, 0, 0)),
(10, (1, 0, 1, 0, 0)),
(10, (1, 0, 0, 1, 0)),
(50, (0, 1, 1, 0, 0)),
(50, (0, 1, 0, 1, 0)),
(100, (1, 1, 0, 1, 0)),
(100, (0, 0, 1, 1, 1)),
(100, (1, 1, 1, 0, 0)),
(500, (0, 1, 0, 1, 1, 0)),
(500, (0, 1, 1, 0, 1, 0)),
(2000, (0, 1, 1, 1, 0)),
(4000, (1, 1, 1, 0, 1)),