|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 Stubborn 于 2021-12-7 21:02 编辑
我已经演示了如何使用这两段代码
- 其中a列表是是当前局面的着点记录,每个数字代表的是 int = x + y * 15 。
- 其中规定位于棋盘的左上角(0, 0),右上角位(14, 0),左下角(0, 14),右下角(14, 14)
- 返回的结果里面,是List[Tuple[int,int]] , 元组的第二个元素,表示一个着点,第一个元素,表示当前着点的评分。
- 该返回的结果也有对手的最优着点,是双方着点的,经过评估分排序后集合,对手的最优着点也是我们的最优着点。
- 如果你只想做一个初级版的五子棋游戏,那么你可以拿这评分代码直接OK了。如果想继续优化,则选择博弈树扩展搜索最优路径
- 请注意,这里的都评分,是一个点的评分,比如 AAXAA ,X点可以落子形成连五棋型,那么这个点的返回应该是这样(5000, X) ,即落X着点可以获得5000评分
- 如果你觉得最后采集的敌我双方评分点不合适,可以自己更换逻辑
- # -*- coding: utf-8 -*-
- # !/usr/bin/python3
- """
- @ version: ??
- @ author: Alex
- @ file: Chess
- @ datetime: 2021/12/1 - 21:00
- @ explain:
- """
- from typing import List
- from settings import VECTOR5, VECTOR3, BLACK, WHITE, ChessType, BRANCH
- class CheckTheChessPattern(object):
- @staticmethod
- def _get_xy_score(dat: str, num: int):
- """
- 辅助函数,返回当前着点的棋形
- """
- result = []
- for v1, v2 in VECTOR5:
- v1e = ""
- for e in v1:
- if 0 <= e + num <= 224:
- v1e = dat[e + num] + v1e
- v1e = v1e + dat[num]
- for e in v2:
- if 0 <= e + num <= 224:
- v1e += dat[e + num]
- result.append(v1e)
- return result
- @staticmethod
- def _update_spots(spots: List[int], dat: str):
- result = set()
- for idx, spot in enumerate(spots):
- # TODO 跟新数据
- value = WHITE if idx % 2 else BLACK
- dat = dat[:spot] + value + dat[spot + 1:]
- for p in VECTOR3:
- # TODO 如果点没有超出边界,则加入待搜索的点
- if 0 <= spot + p <= 225:
- result.add(spot + p)
- for spot in spots:
- result.discard(spot)
- return result, dat
- @staticmethod
- def get_xy_score(spot: int, flag: str, dat: str, hostility=False) -> int:
- """
- :param spot: 一个着点, int := x + y * 15
- :param flag: 着点身份, ’1‘ or '2'
- :return: ChessType.score(scores) -> int 当前着点参数落点评估分数
- TODO 尝试落子后,返回该点周围八个方向的五格拼接为四个方向的数据(横轴,竖轴,左斜轴,右斜轴)
- 拿到棋形后(例如00011A22200,A是spot着点),在到棋形数据进行比对,如果棋形出现在其中,给与对应分数评估。
- 取两个方向的最大值评估分和值作为返回值
- """
- dat = dat[:spot] + dat[spot] + dat[spot + 1:]
- # TODO 获取棋形
- chess_type = CheckTheChessPattern._get_xy_score(dat=dat, num=spot)
- _flag = BLACK if flag == WHITE else WHITE
- def get(chess):
- for score, rules in ChessType.ScoreRules.items():
- for rule in rules:
- if rule.format(flag, _flag) in chess:
- # TODO 如果是敌对方,进行修正
- if hostility:
- if score == ChessType.LIVE_THREE:
- score = ChessType.PLAYER_LIVE_THREE
- if score == ChessType.RUSH_FOUR:
- score = ChessType.PLAYER_RUSH_FOUR
- return score
- return 0.5
- scores = sorted([get(chess) for chess in chess_type], reverse=True)
- return ChessType.score(scores)
- @staticmethod
- def evaluation(spots: List[int]):
- """返回当前局面最优的BRANCH个着点"""
- # TODO 获得待搜索的点
- dat = '0' * 225
- waiting_for_search_points, dat = CheckTheChessPattern._update_spots(spots=spots, dat=dat)
- # TODO 获得当前身份与对手身份
- our = WHITE if len(spots) % 2 else BLACK
- enemy = BLACK if our == WHITE else WHITE
- # TODO 获得敌我双方所有点的估值
- our_scores = [(CheckTheChessPattern.get_xy_score(spot=spot, flag=our, dat=dat), spot) for spot in
- waiting_for_search_points]
- enemy_scores = [(CheckTheChessPattern.get_xy_score(spot=spot, flag=enemy, dat=dat, hostility=True), spot) for
- spot in
- waiting_for_search_points]
- # TODO 获得敌我双方所有点的估值 排序 获得最大收益点
- socre = our_scores + enemy_scores
- socre = sorted(socre, key=lambda p: p[0], reverse=True)
- return socre[:BRANCH]
- if __name__ == '__main__':
- a = [112, 41, 96, 203, 128, 192, 80, 3]
- print(CheckTheChessPattern.evaluation(a))
复制代码
- # -*- coding: utf-8 -*-
- # !/usr/bin/python3
- """
- @ version: ??
- @ author: Alex
- @ file: setting
- @ datetime: 2021/12/1 - 21:00
- @ explain:
- """
- # TODO 黑棋子
- BLACK = '1'
- # TODO 白棋子
- WHITE = '2'
- # TODO 分支8,从当前棋盘内搜索8个最优点
- BRANCH = 10
- VECTOR5 = [
- [[-1, -2, -3, -4, -5], [1, 2, 3, 4, 5]],
- [[15, 30, 45, 60, 75], [-15, -30, -45, -60, -75]],
- [[14, 28, 42, 56, 70], [-14, -28, -42, -56, -70]],
- [[-16, -32, -48, -64, -80], [16, 32, 48, 64, 80]]
- ]
- VECTOR3 = [-48, -45, -42, -32, -30, -28, -16, -15, -14, -3, -2, -1, 1, 2, 3, 14, 15, 16, 28, 30, 32, 42, 45, 48]
- class ChessType:
- """
- (1) 如果有一个方向已经成5连, 其分值记为5000;
- (2) 未出现 (1) , 有一个方向已经成活4, 其分值记为1000;
- (3) 未出现 (1) 、 (2) , 有两个方向出现单4, 其分值记为1000;
- (4) 未出现 (1) 、 (2) 、 (3) , 有两个方向出现单4和活3, 其分值记为998;
- (5) 未出现 (1) 、 (2) 、 (3) 、 (4) , 有两个方向成活3, 其分值记为954;
- (6) 未出现上述情况, 将4个方向中单子分值最大的2个值相加作为其分值。
- 己方单4 73
- 对方单4 84
- 己方活3 67
- 对方活3 79
- 单3 16
- 活2 13
- 单2 7
- 活1 3
- 单1 1
- """
- ScoreRules = {
- # TODO 得分[int]:棋型List[str]
- # 如果有新的棋型,在此添加,范围仅限,单活1-4棋型
- # TODO 连五型
- 5000: ["{0}{0}{0}{0}{0}"],
- # TODO 活四型
- 1000: ["0{0}{0}{0}{0}0"],
- # TODO 眠四型
- 73: ["0{0}{0}{0}{0}{1}", "{0}0{0}{0}{0}", "{0}{0}0{0}{0}", "{0}{0}{0}0{0}", "{1}{0}{0}{0}{0}0"],
- # TODO 活三型
- 67: ["0{0}{0}{0}0", "0{0}0{0}{0}0", "0{0}{0}0{0}0"],
- # TODO 眠三型
- 16: [
- "0{0}{0}{0}{1}", "{1}{0}{0}{0}0", "0{0}0{0}{0}{1}",
- "{1}{0}0{0}{0}0", "0{0}{0}0{0}{1}", "{1}{0}{0}0{0}0",
- "{1}0{0}{0}{0}0{1}", "{0}00{0}{0}", "{0}0{0}0{0}"
- ],
- # TODO 活二型
- 13: ["0{0}{0}0", "0{0}0{0}0", "{0}00{0}", "0{0}{0}0"],
- # TODO 眠二型
- 7: ["0{0}{0}{1}", "0{0}0{0}{1}", "0{0}00{0}{1}", "{0}000{0}"],
- # TODO 活一型
- 3: ["0{0}0"],
- # TODO 眠一型
- 1: ["0{0}{1}", "{1}{0}0"],
- }
- LIVE_THREE: int = 67
- RUSH_FOUR: int = 73
- # TODO 对方活3及单四评分
- PLAYER_LIVE_THREE: int = 79
- PLAYER_RUSH_FOUR: int = 84
- # TODO 异常棋型得分,双活三,单四活三,双单四,
- DOUBLE_LIVE_THREE: int = 954
- RUSH_FOUR_LIVE_THREE: int = 998
- DOUBLE_RUSH_FOUR: int = 1000
- @staticmethod
- def score(scores) -> int:
- """返回最终评分
- 如果有新的异常棋型得分,在此修改。
- scores->List[int]是一个落子的四个方向的棋型得分
- """
- value = scores[0] + scores[1]
- # TODO 连五棋型 5000分
- if value >= 5000:
- return 5000
- # TODO 双冲四棋型 1000分
- if value >= ChessType.RUSH_FOUR * 2:
- return ChessType.DOUBLE_RUSH_FOUR
- # TODO 冲四+活三棋型 998分
- elif value >= ChessType.RUSH_FOUR + ChessType.LIVE_THREE:
- return ChessType.RUSH_FOUR_LIVE_THREE
- # TODO 双活三棋型 954分
- elif value >= ChessType.LIVE_THREE * 2:
- return ChessType.DOUBLE_LIVE_THREE
- # TODO 以上都不符
- return value
复制代码
|
|