# 面向对象程序设计 **Repository Path**: ssred/object-oriented-programming ## Basic Information - **Project Name**: 面向对象程序设计 - **Description**: 姓名:王旭 - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-09-23 - **Last Updated**: 2021-01-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 面向对象程序设计 #### 介绍 姓名:王旭 选题:文明5外交AI #### 一、前言 1. AI代替玩家操作:
五子棋AI: 在程序设计基础c语言的课程中我们的期末大作业是完成一个支持AI的五子棋程序。五子棋是两个玩家对弈的游戏,双方依次选择位置落子直到游戏胜利,而AI的作用是代替玩家选择落子位置。作为程序编写者,AI片段的接口实际上是将需要获取玩家输入的代码根据模式做一个选择,AI模式则调用相关函数得到返回值模拟玩家的输入即落子。 ![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/114915_7e224586_8092880.png "屏幕截图.png")
如图,这是我的AI后手模式回合轮询代码片段,end==1意味着游戏结束。huihe1()代表着玩家落子,huihe2_ai()代表ai落子,这里封装的并不好,理想的情况应该将落子作为一个函数,落子位置(x,y)作为该函数的输入,而ai模式通过search得分表得到落子位置,玩家通过scanf函数输入落子位置。 2. AI和玩家处于同一层面:
  由以上例子不难发现从代码角度分析游戏AI仅仅是玩家操作的替换,但是从对象(玩家)的角度出发来看的话,AI也是一个虚拟玩家虽然它的编写者大概率也是游戏开发者本身,所以要注意游戏机制部分并不应该和AI混淆在一块即编写AI者尽量将自己当成一个玩家而不是游戏的开发者否则会造成一定的问题。
  就比如在本学期的操作系统研讨课中我们设计的简易kernel代码中分为内核态和用户态,内核态是操作系统的核心机制,用户态是用户进程,但是一个特殊的用户进程shell即终端也是操作系统的开发者设计的,而由于设计者本人也作为用户“知道的太多”,一不小心就调用了内核的函数和变量造成功能的混乱且在开启虚拟内存后带来大量的bug。
  举一个不好的例子:早在2003年发行的《魔兽争霸3:冰封王座》由于其特有的开源且功能丰富的地图编辑器保持了长久的活力。大量的玩家自制地图中多数是多人对抗游戏,种类丰富的地图就有种类丰富的AI。在一个朋友(真的存在)开发的地图中发现AI的钱似乎是花不光的,面向代码搞了半天才发现他的AI直接是一个特权阶层。造兵的逻辑是选择兵营、选择兵种、请求训练(花费资源、开始训练),其实在玩家看来就是点了一下小兵的图标,然而在该地图的AI中直接是选择兵营、选择兵种、开始训练。请求训练是开放给玩家的接口,而开始训练显然是高权限的操作。在此例子中,AI使用了不属于玩家的操作权限,两者没有严格处于同一层面。
  回到文明5的AI。文明5的AI是满足以上两要素的:AI代替玩家操作与AI和玩家处于同一层面。 ### 二、功能分析与建模 1.功能分析
  由前言的要素:AI代替玩家操作。分析AI功能实际上只需要分析玩家需要进行哪些操作即可。 玩家的操作可以简单分为查看和行为。类比于内存的读写,读操作不改变内存的值而写操作会。查看只是游戏内部数据的读取,行为会改变游戏状态。所以AI功能分析等同于玩家需要进行哪些行为。
从一个简单例子入手。
  选择文明设置游戏参数后经过一段不长的加载游戏终于开始了。开局有一个移民以及一个勇士。让移民花费一点行动力移动一格到相邻的平原上建立城市。我们让勇士移动两个清除一些迷雾。选择首都选择建造纪念碑,选择研究科技家畜训养并结束回合。几个回合后勇士探索到一处遗迹获得20点文化值,超过政策阈值要选择一个政策了。选择传统理念。之后遇到一个新的文明德国,对方发来外交请求进行交易:对方获得:于我方文明设置大使馆;我方获得:每回合1金币30回合。可以选择接收或者拒绝,或者提出其他交易要求。建造新的移民,建立新的城市后收到警告,可以选择承诺不再开拓或者强硬回复,选择强硬回复。不久后遭到对方宣战,消灭对方3个勇士后对方发来和平请求,对方获得:和平;我方获得:30回合奢侈品象牙。接收和平。
  上述例子中涉及到很多文明5的行动,有单位的移动、巡逻、待命,城市的建造,文明研究科技、选择政策或者对其他文明的外交行动。外交AI的行动层面都是在文明层次的。主要包含交易、战争、和平、相关外交接触。
2.需求建模
知道了外交AI的功能之后,我们来探讨这些功能的实现。
所有的外交行动都基于该AI文明已知的信息和其自身属性。
举几个例子面向代码来具体看看其他文明信息是怎样的数据结构且如何维护。
**其他文明信息**
外交AI的关键类
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115611_396f7911_8092880.png "屏幕截图.png")
部分属性
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115647_034ec688_8092880.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115656_810c0121_8092880.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115708_f14c58b7_8092880.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115713_a461a222_8092880.png "屏幕截图.png")
部分相关方法
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115736_266351be_8092880.png "屏幕截图.png")
  在CvDiplomacyAI此方法中有大量相关属性。其中用一个数组来存储每一个玩家和自己的军事力量对比,一个数组存储每个玩家和自己的经济力量对比,一个数组存储每一个玩家受到自己的战争破坏,以及一个二维数组存储各个玩家之间的相互战争破坏。

  战争破坏度衰减的逻辑为如果此回合的文明(Master)和其他的任意一个文明(Slave)处于和平,就降低1/20的破坏度。之后,对其他所有文明进行遍历,如果该两个文明和平,就降低其相互战争破坏度。<\p>
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115910_17383466_8092880.png "屏幕截图.png")
计算战争破坏度前先计算此回合文明的总军事实力。战争破坏度需要通过该文明军事计算相对破坏。
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115925_8c5fe769_8092880.png "屏幕截图.png")
其他文明的军事实力分为IMMENSE--极强的 POWERFUL--有力量的 STRONG--强AVERAGE--普通 POOR--稍弱 WEAK--虚弱 PATHETIC--可怜的
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/115946_f8345fb5_8092880.png "屏幕截图.png")
之后是对战争目标、和谈意愿等信息更新以及更新对其他玩家的信息。这里的对外信息都是估计值(Eestimate)。
**自身属性--性格**
这里的性格不是说互斥的,即某个文明的性格为忠诚某个为野蛮,表现在数据结构上就是int personality,1代表什么,2代表什么......;而是说该文明在以下属性的倾向程度,具体为数值。
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120124_824eb359_8092880.png "屏幕截图.png")
获得这些性格的方法:
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120146_50adf65b_8092880.png "屏幕截图.png")
性格解释
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120202_39afb614_8092880.png "屏幕截图.png")
网上大佬总结的性格表,可以看一下蛮有意思的。埃及、巴比伦、桑海的奇迹建造欲望最强,随便点一局游戏如果你最先抢一个大图书馆的话这些文明可能会来嘲讽你
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120244_6c8f267c_8092880.png "屏幕截图.png")
文明共有四套性格体系,分别为基础外交意愿,基础性格、军事偏好、内政偏好。后三种性格都是固定的属性不会更改。而基础外交意愿是会变动的,游戏开始时不同文明有不同的初始值.
从网上找到了对应性格的介绍可以看一下。
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120604_ccd80230_8092880.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120638_a4ab812e_8092880.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/120752_dde17b71_8092880.png "屏幕截图.png")
除了性格之外,另一个重要的属性的approach态度。态度决定AI对于贸易或者请求的答应倾向。approach是在与其他文明的接触中变化的。比如边界纠纷会降低态度。 ### 三、核心流程分析
由上一节可知,AI外交决策需要的是其他文明信息和本文明属性(性格等),此节具体探讨其决策流程。
  每个AI文明会首先将其他文明分为两类:Major(文明)和Minor(城邦)。名字有很大迷惑性,最开始我以为是判断文明的强弱。对文明有7个态度属性,对城邦有5个分别为WAR战争,HOSTILE敌视,DECEPTIVE虚伪,GUARDED提防,AFRAID畏惧,FRIENDLY友好,NEUTRAL中立;IGNORE忽略,FRIENDLY友好,PROTECTIV保护,CONQUEST征服,BULLY勒索。这些态度属性是会随着游戏的进行而改变的,每一个文明有一组态度属性初始值。这一组态度主要影响宣战和交易时的倾向。
主要讲讲CvDiplomacyAI类的方法DoTurn()流程
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/121034_a14b993b_8092880.png "屏幕截图.png")
纯粹外交部分的AI每回合基本只关注战争、议和、contact(贸易、条约啥的都叫contact)、RA(研究协定~~不知道为什么单独拎出来) ### 四、高级设计意图分析
先来看一个类图
![输入图片说明](https://images.gitee.com/uploads/images/2021/0114/121304_11db11b7_8092880.png "屏幕截图.png")
本来只打算画AI后缀的类,但是发现City和CvPlayer无法和他们分割就也加上了。
  所有的AI相关类几乎都被CvPlayer这个大类关联。而各个AI类之间基本相互独立,而且不同功能的AI划分很细致。除此之外,在上一节中展示了CvDiplomacyAI的DoTurn()方法,事实上EconomicAI,MilitaryAI,TacticalAI,HomelandAI,ArmyAI,MinorCivAI,CityStrategyAI都有同名方法DoTurn。也就是说每个回合AI的不同类型操作是完全独立的。
面向对象的设计原则: ### 单一职责原则
一个合理的类,应该仅有一个引起它变化的原因,即单一职责,就是设计的这个类功能应该只有一个
后缀AI的类划分十分细致,外交军事经济分开来不说,连城市建造单位、建造建筑、建造工程都分成了三个AI类。每个类的功能很单一。符合单一职责原则。
优点是消除耦合,减小因需求变化引起代码僵化。 ### 接口分离原则
本来整个AI也可以设计成一个类。但是文明5的AI是非常多的类。该设计符合接口分离原则的重要证据就是方法DoTurn()。这些AI类都有自己的同名方法DoTurn.可以看出这是对AI功能的切割。
优点是消除耦合
关于文明5的不同文明特色
  文明5本身不同文明的特质加成区别很有限(除了朝鲜和波兰),但是不同文明的发展情况是截然不同的。其中贡献主要为两点,其一为出生点匹配,就比如埃及出生在沙漠,阿兹特克出生在山区;其二就是AI玩法不同了。不同类型文明性格差距明显,于是蒙古就每次疯狂侵略,朝鲜就种田养生。
谈些题外话
  关于文明5和文明6的一些看法:文明6整体画风偏卡通,将文明和领袖区别开来(可能也是没办法,毕竟历史上有名的文明数量有限,如果一个文明选择不同的领袖就可以出更多DLC卖钱了,斜眼笑~)。除此之外,文明6的生产力提升更加困难,因为区域要占用单元格,另外货船的锤子加成太少。最难以接受的是奇迹机制的改变,奇迹要占用单元格对于单核城市文明打击是很大的。