鱼C论坛

 找回密码
 立即注册
查看: 1036|回复: 0

[技术交流] 五子棋后端代码,评分代码

[复制链接]
发表于 2021-12-7 16:26:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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评分
  • 如果你觉得最后采集的敌我双方评分点不合适,可以自己更换逻辑


  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/python3
  3. """
  4. @ version: ??
  5. @ author: Alex
  6. @ file: Chess
  7. @ datetime: 2021/12/1 - 21:00
  8. @ explain:
  9. """
  10. from typing import List

  11. from settings import VECTOR5, VECTOR3, BLACK, WHITE, ChessType, BRANCH


  12. class CheckTheChessPattern(object):

  13.     @staticmethod
  14.     def _get_xy_score(dat: str, num: int):
  15.         """
  16.         辅助函数,返回当前着点的棋形
  17.         """
  18.         result = []
  19.         for v1, v2 in VECTOR5:
  20.             v1e = ""
  21.             for e in v1:
  22.                 if 0 <= e + num <= 224:
  23.                     v1e = dat[e + num] + v1e
  24.             v1e = v1e + dat[num]
  25.             for e in v2:
  26.                 if 0 <= e + num <= 224:
  27.                     v1e += dat[e + num]
  28.             result.append(v1e)
  29.         return result

  30.     @staticmethod
  31.     def _update_spots(spots: List[int], dat: str):
  32.         result = set()
  33.         for idx, spot in enumerate(spots):
  34.             # TODO 跟新数据
  35.             value = WHITE if idx % 2 else BLACK
  36.             dat = dat[:spot] + value + dat[spot + 1:]

  37.             for p in VECTOR3:
  38.                 # TODO 如果点没有超出边界,则加入待搜索的点
  39.                 if 0 <= spot + p <= 225:
  40.                     result.add(spot + p)
  41.         for spot in spots:
  42.             result.discard(spot)

  43.         return result, dat

  44.     @staticmethod
  45.     def get_xy_score(spot: int, flag: str, dat: str, hostility=False) -> int:
  46.         """
  47.         :param spot: 一个着点, int := x + y * 15
  48.         :param flag: 着点身份, ’1‘ or '2'
  49.         :return:  ChessType.score(scores) -> int 当前着点参数落点评估分数
  50.         TODO 尝试落子后,返回该点周围八个方向的五格拼接为四个方向的数据(横轴,竖轴,左斜轴,右斜轴)
  51.             拿到棋形后(例如00011A22200,A是spot着点),在到棋形数据进行比对,如果棋形出现在其中,给与对应分数评估。
  52.             取两个方向的最大值评估分和值作为返回值
  53.         """
  54.         dat = dat[:spot] + dat[spot] + dat[spot + 1:]

  55.         # TODO 获取棋形
  56.         chess_type = CheckTheChessPattern._get_xy_score(dat=dat, num=spot)

  57.         _flag = BLACK if flag == WHITE else WHITE

  58.         def get(chess):
  59.             for score, rules in ChessType.ScoreRules.items():
  60.                 for rule in rules:
  61.                     if rule.format(flag, _flag) in chess:
  62.                         # TODO 如果是敌对方,进行修正
  63.                         if hostility:
  64.                             if score == ChessType.LIVE_THREE:
  65.                                 score = ChessType.PLAYER_LIVE_THREE
  66.                             if score == ChessType.RUSH_FOUR:
  67.                                 score = ChessType.PLAYER_RUSH_FOUR
  68.                         return score
  69.             return 0.5

  70.         scores = sorted([get(chess) for chess in chess_type], reverse=True)
  71.         return ChessType.score(scores)

  72.     @staticmethod
  73.     def evaluation(spots: List[int]):
  74.         """返回当前局面最优的BRANCH个着点"""
  75.         # TODO 获得待搜索的点
  76.         dat = '0' * 225
  77.         waiting_for_search_points, dat = CheckTheChessPattern._update_spots(spots=spots, dat=dat)
  78.         # TODO 获得当前身份与对手身份
  79.         our = WHITE if len(spots) % 2 else BLACK
  80.         enemy = BLACK if our == WHITE else WHITE
  81.         # TODO 获得敌我双方所有点的估值
  82.         our_scores = [(CheckTheChessPattern.get_xy_score(spot=spot, flag=our, dat=dat), spot) for spot in
  83.                       waiting_for_search_points]

  84.         enemy_scores = [(CheckTheChessPattern.get_xy_score(spot=spot, flag=enemy, dat=dat, hostility=True), spot) for
  85.                         spot in
  86.                         waiting_for_search_points]
  87.         # TODO 获得敌我双方所有点的估值 排序 获得最大收益点
  88.         socre = our_scores + enemy_scores
  89.         socre = sorted(socre, key=lambda p: p[0], reverse=True)

  90.         return socre[:BRANCH]


  91. if __name__ == '__main__':
  92.     a = [112, 41, 96, 203, 128, 192, 80, 3]
  93.     print(CheckTheChessPattern.evaluation(a))
复制代码


  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/python3
  3. """
  4. @ version: ??
  5. @ author: Alex
  6. @ file: setting
  7. @ datetime: 2021/12/1 - 21:00
  8. @ explain:
  9. """

  10. # TODO 黑棋子
  11. BLACK = '1'
  12. # TODO 白棋子
  13. WHITE = '2'
  14. # TODO 分支8,从当前棋盘内搜索8个最优点
  15. BRANCH = 10

  16. VECTOR5 = [
  17.     [[-1, -2, -3, -4, -5], [1, 2, 3, 4, 5]],
  18.     [[15, 30, 45, 60, 75], [-15, -30, -45, -60, -75]],
  19.     [[14, 28, 42, 56, 70], [-14, -28, -42, -56, -70]],
  20.     [[-16, -32, -48, -64, -80], [16, 32, 48, 64, 80]]
  21. ]

  22. 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]


  23. class ChessType:
  24.     """
  25.     (1) 如果有一个方向已经成5连, 其分值记为5000;
  26.     (2) 未出现 (1) , 有一个方向已经成活4, 其分值记为1000;
  27.     (3) 未出现 (1) 、 (2) , 有两个方向出现单4, 其分值记为1000;
  28.     (4) 未出现 (1) 、 (2) 、 (3) , 有两个方向出现单4和活3, 其分值记为998;
  29.     (5) 未出现 (1) 、 (2) 、 (3) 、 (4) , 有两个方向成活3, 其分值记为954;
  30.     (6) 未出现上述情况, 将4个方向中单子分值最大的2个值相加作为其分值。
  31.     己方单4   73
  32.     对方单4   84
  33.     己方活3   67
  34.     对方活3   79
  35.     单3       16
  36.     活2       13
  37.     单2       7
  38.     活1       3
  39.     单1       1
  40.     """
  41.     ScoreRules = {
  42.         # TODO 得分[int]:棋型List[str]
  43.         #  如果有新的棋型,在此添加,范围仅限,单活1-4棋型
  44.         #  TODO  连五型
  45.         5000: ["{0}{0}{0}{0}{0}"],
  46.         #  TODO  活四型
  47.         1000: ["0{0}{0}{0}{0}0"],
  48.         #  TODO  眠四型
  49.         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"],
  50.         #  TODO  活三型
  51.         67: ["0{0}{0}{0}0", "0{0}0{0}{0}0", "0{0}{0}0{0}0"],
  52.         #  TODO  眠三型
  53.         16: [
  54.             "0{0}{0}{0}{1}", "{1}{0}{0}{0}0", "0{0}0{0}{0}{1}",
  55.             "{1}{0}0{0}{0}0", "0{0}{0}0{0}{1}", "{1}{0}{0}0{0}0",
  56.             "{1}0{0}{0}{0}0{1}", "{0}00{0}{0}", "{0}0{0}0{0}"
  57.         ],
  58.         #  TODO  活二型
  59.         13: ["0{0}{0}0", "0{0}0{0}0", "{0}00{0}", "0{0}{0}0"],
  60.         #  TODO  眠二型
  61.         7: ["0{0}{0}{1}", "0{0}0{0}{1}", "0{0}00{0}{1}", "{0}000{0}"],
  62.         #  TODO  活一型
  63.         3: ["0{0}0"],
  64.         #  TODO  眠一型
  65.         1: ["0{0}{1}", "{1}{0}0"],
  66.     }
  67.     LIVE_THREE: int = 67
  68.     RUSH_FOUR: int = 73
  69.     # TODO 对方活3及单四评分
  70.     PLAYER_LIVE_THREE: int = 79
  71.     PLAYER_RUSH_FOUR: int = 84
  72.     # TODO 异常棋型得分,双活三,单四活三,双单四,
  73.     DOUBLE_LIVE_THREE: int = 954
  74.     RUSH_FOUR_LIVE_THREE: int = 998
  75.     DOUBLE_RUSH_FOUR: int = 1000

  76.     @staticmethod
  77.     def score(scores) -> int:
  78.         """返回最终评分
  79.             如果有新的异常棋型得分,在此修改。
  80.             scores->List[int]是一个落子的四个方向的棋型得分
  81.         """
  82.         value = scores[0] + scores[1]
  83.         # TODO 连五棋型 5000分
  84.         if value >= 5000:
  85.             return 5000
  86.         # TODO 双冲四棋型 1000分
  87.         if value >= ChessType.RUSH_FOUR * 2:
  88.             return ChessType.DOUBLE_RUSH_FOUR
  89.         # TODO 冲四+活三棋型 998分
  90.         elif value >= ChessType.RUSH_FOUR + ChessType.LIVE_THREE:
  91.             return ChessType.RUSH_FOUR_LIVE_THREE
  92.         # TODO 双活三棋型 954分
  93.         elif value >= ChessType.LIVE_THREE * 2:
  94.             return ChessType.DOUBLE_LIVE_THREE
  95.         # TODO 以上都不符
  96.         return value
复制代码


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-30 18:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表