五子棋后端代码,评分代码
本帖最后由 Stubborn 于 2021-12-7 21:02 编辑我已经演示了如何使用这两段代码
[*]其中a列表是是当前局面的着点记录,每个数字代表的是 int = x + y * 15。
[*]其中规定位于棋盘的左上角(0, 0),右上角位(14, 0),左下角(0, 14),右下角(14, 14)
[*]返回的结果里面,是List] , 元组的第二个元素,表示一个着点,第一个元素,表示当前着点的评分。
[*]该返回的结果也有对手的最优着点,是双方着点的,经过评估分排序后集合,对手的最优着点也是我们的最优着点。
[*]如果你只想做一个初级版的五子棋游戏,那么你可以拿这评分代码直接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 + v1e
v1e = v1e + dat
for e in v2:
if 0 <= e + num <= 224:
v1e += dat
result.append(v1e)
return result
@staticmethod
def _update_spots(spots: List, dat: str):
result = set()
for idx, spot in enumerate(spots):
# TODO 跟新数据
value = WHITE if idx % 2 else BLACK
dat = dat[:spot] + value + dat
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 + dat
# 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(, reverse=True)
return ChessType.score(scores)
@staticmethod
def evaluation(spots: List):
"""返回当前局面最优的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, reverse=True)
return socre[:BRANCH]
if __name__ == '__main__':
a =
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], ],
[, [-15, -30, -45, -60, -75]],
[, [-14, -28, -42, -56, -70]],
[[-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 得分:棋型List
#如果有新的棋型,在此添加,范围仅限,单活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是一个落子的四个方向的棋型得分
"""
value = scores + scores
# 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
页:
[1]