|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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
|
|