成果展示
首先展示一下程序的成果,最后的画面会是这个模样:
。。。右边的两颗一黑一白的棋子比较调皮,它会动。
主要功能
主要实现了人机对弈,机机对弈(手动改几行注释就可以了),利用Pygame绘制游戏界面,运用了状态机, 估值函数。 由于状态机的运用,使得所有对象都可以被一个对象管理,方便了程序的扩展,只需要添加状态和创建实体类,就可以增加新的模块与功能。
程序的架构
这个程序文件包括了主要有以下类:
包含14个类与一个运行函数
———————————————————————————
重要的类
按理来说,只要具备了以下四个类,就可以按照这个框架写出所有游戏。。。
只是我说说而已,有待百度。
状态类
该类是虚类,实体的状态类需要继承它
状态 <- 是实体类的成员,该对象描述某个具体的实体类状态,以及在该状态下会做些什么,做之前要有什么准备工作,做完了怎么退出动作,怎么改变状态。比如一个智能棋手有一个下棋状态,、、、
# 状态
class State(object):
def __init__(self, name):
self.name = name
# 执行动作
def do_actions(self):
pass
# 检测外界条件
def check_conditions(self):
pass
# 进入动作
def entry_actions(self):
pass
# 退出动作
def exit_actions(self):
pass
状态机类
该类对状态进行统一管理
状态机 <- 是实体类的成员,它是实体类的大脑,管理着实体类的所有状态,以及状态间的转换(哪个状态是激活态)
# 状态机
class StateMachine(object):
def __init__(self):
self.states = {}
self.active_state = None
# 添加状态
def add_state(self, state):
self.states[state.name] = state
# 决策(思考)
def think(self):
if self.active_state is None:
return
self.active_state.do_actions()
new_state_name = self.active_state.check_conditions()
if new_state_name is not None and new_state_name is not self.active_state:
self.set_state(new_state_name)
# 设置活动状态
def set_state(self, new_state_name):
if self.active_state is not None:
self.active_state.exit_actions()
self.active_state = self.states[new_state_name]
self.active_state.entry_actions()
世界类
管理所有实体类对象
世界 <- 所有对象由它来处理,实体对象必须被它管理才能发挥作用。。。
# 世界类
class World(object):
def __init__(self):
self.entities = {}
self.entity_id = 0
self.update_time = 0
self.is_over = False # 游戏结束
self.playing = False #游戏正在进行
# 下面两句本不应该出现在这里,应该是出现在某个实体类中的,。。。。
# 谁叫我比较懒。。。。。破坏了代码的美感,应该干掉,,,谁有兴趣就做做吧,,
self.background = pygame.surface.Surface(SCREEN_SIZE).convert()
self.background.blit(pygame.image.load(CHESS_BOX).convert_alpha(), (0, 0))
# 添加实体
def add_entity(self, entity):
self.entities[self.entity_id] = entity
entity.id = self.entity_id
self.entity_id += 1
# 移除实体
def remove_entity(self, entity):
del self.entities[entity.id]
# 获取实体
def get(self, entity_id):
if entity_id in self.entities:
return self.entities[entity_id]
else:
return None
# 处理各个实体
def process(self, time_passed):
time_passed_seconds = time_passed / 1000.0
for entity in list(self.entities.values()):
entity.process(time_passed_seconds)
# 绘图
def render(self, surface, current_time):
if self.update_time < current_time:
surface.blit(self.background, (0, 0))
for entity in list(self.entities.values()):
entity.render(surface)
self.update_time = current_time + 30
# 得到接近的实体
def get_close_entity(self, name, location, range=10.):
location = Vector2(*location)
for entity in list(self.entities.values()):
if entity.name == name:
distance = location.get_distance_to(entity.location)
if distance < range:
return entity
return None
游戏实体类
该类需要被其它具有实际意义的实体类继承
实体类 <- 描述了一个实体,比如:一个智能棋手类,一个棋子, ,,,
# 游戏实体类
class GameEntity(object):
def __init__(self, world, name, image=None):
self.world = world
self.name = name
self.image = image
self.location = Vector2(0, 0)
self.destination = Vector2(0, 0)
self.speed = 0.
self.brain = StateMachine()
self.id = 0
# 绘图
def render(self, surface):
if self.image is None:
return
x, y = self.location
w, h = self.image.get_size()
surface.blit(self.image, (x-w/2, y-h/2))
# 处理实体对象
def process(self, time_passed):
self.brain.think()
if self.speed > 0. and self.location != self.destination:
vec_to_destination = self.destination - self.location
distance_to_destination = vec_to_destination.get_length()
heading = vec_to_destination.get_normalized()
travel_distance = min(distance_to_destination, time_passed * self.speed)
self.location += travel_distance * heading
———————————————————————————
不那么重要的类,但对于这个五子棋来说,就是核心类
这里放一个大概,后面会给出全部代码
棋子类
GameEntity的子类
# 棋子类
class Chessman(GameEntity):
def __init__(self, world, image):
GameEntity.__init__(self, world, "Chessman", image)
棋盘局势类
棋盘局势 <- 整个棋盘的局势走向
# 棋盘局势
class ChessBoxSituations(object):
def __init__(self, size=(19, 19)):
self.size = size
self.situations = {} #棋盘局势(棋子在棋盘的点集)
self.last_drop_position = (0, 0)
self.current_drop_player = 0
self.count = 0
# 局势发展(棋子增加)
def evolve(self, chessman_point, owner):
self.situations[chessman_point] = owner
self.last_drop_position = chessman_point
self.count += 1
# 获取棋盘某点坐标的状态
def get_state(self, point):
px, py = point
x, y = self.size
if x - px < 0 or y - py < 0 or x - px >= 19 or y - py >= 19:
return self.OutOfRange()
if point not in self.situations:
return None
return self.situations[point]
class OutOfRange(object):
pass
智能体棋手类
对战的AI
附:
# 八个方向 N:北, E:东, S:南, W:西
D_N = Vector2(0, -1)
D_EN = Vector2(1, -1)
D_E = Vector2(1, 0)
D_ES = Vector2(1, 1)
D_S = Vector2(0, 1)
D_WS = Vector2(-1, 1)
D_W = Vector2(-1, 0)
D_WN = Vector2(-1, -1)
DIRECTION = (D_N, D_EN, D_E, D_ES, D_S, D_WS, D_W, D_WN)
# 智能体棋手类
class PlayerAgent(GameEntity):
def __init__(self, world, box_situations, chess_image, no=1, opponent=0):
GameEntity.__init__(self, world, "PlayerAgent")
self.no = no #自己
self.opponent = opponent #对手
self.box_situations = box_situations
self.chess_image = chess_image
self.drop_points = [] # 可选的将要下的棋子位点
self.points_weight = 0 # drop_points里的点的权重(里面所有点权重相同)
wait_state = PlayerAgentStateWait(self)
drop_state = PlayerAgentStateDrop(self)
self.brain.add_state(drop_state)
self.brain.add_state(wait_state)
# 更新下棋点集
def update_drop_points(self, location, weight):
if self.points_weight < weight:
self.drop_points.clear()
self.drop_points.append(location)
self.points_weight = weight
elif self.points_weight == weight:
self.drop_points.append(location)
# 决策(获取下棋位置)
def decision_making(self):
self.points_weight = 0
self.drop_points.clear()
filter_point = []
# 棋盘上所有的有棋子的点
for point in self.box_situations.situations:
# 获取该点的相邻八个点的空位点
for DIR in DIRECTION:
cur_point = point+DIR
x, y = cur_point
if self.box_situations.get_state((x, y)) is None:
if cu