《游戏人工智能编程》感想一

书名《游戏人工智能编程》作者mat buckland

里面讲了一个west world项目。这是一个简单的玩具教学项目,为了让读者能够实现一个稍微具有智能的智能体。游戏的内容是

1一个矿工在挖金矿,会随机得到金矿,放入背包

2背包的容量有限,背包满则一定要去卖掉

3矿工有体力值,体力为0要休息。

ps,书中有口渴值的存在。但是口渴饥饿什么的都是一种“疲劳值”引入游戏就是为了增加限制条件和增加程序的复杂度。所以对于新手(我)来说还是尽量减少程序复杂度好。

实现方法:

作者谈到可以用有限状态机来实现这个矿工。矿工有3中状态

a在矿洞内

b在买金子的地方

c在家

三种状态会根据一定的条件互相转换。如a因为背包满而到b。a,b会因为没有疲劳值转到c。等等。。

我们可以定义三个类表示三种状态,可以把这三种类实现为单模式,有助于避免重复构建对象而带来的损失。为了实现多态,可以对三个状态定义一个共同的抽象基类叫state。这里的exec代表着每个状态应该执行的动作。比如在矿洞要挖矿,家就要恢复体力值,其参数body就是代表着矿工(因为这里只有一个矿工),body用于读取矿工的数据比如疲劳,如果需要改变矿工的状态。把每种状态的动作抽象到类里面这样最大的好处是便于每个状态下的修改和增加状态(比如我想增加一个口渴)。这种编程方式是状态驱动编程(估计是作者起的名字)。几个状态的编程方式你可能感觉到奇怪,构造函数被声明为私有的,因为这是为了实现单例而不得不采取的方式。这种实现方式在多线程下是不行的,但是本游戏只有一个线程,所以完全满足要求,关于多线程单例的实现自行百度(这个面试经常出现)。

public abstract class State {

	abstract public void exec(Enity body);

}

file2(onminejava)

import java.util.Random;

public class OnMine extends State {

	private static OnMine OnlyOne=null;
	Random gener=new Random();
	private OnMine()
	{

	}

	public static  OnMine getInstance()
	{
		if(OnlyOne==null)
		{
			OnlyOne=new OnMine();
		}
		return OnlyOne;
	}

	@Override
	public void exec(Enity body) {
		// TODO Auto-generated method stub

		if(body instanceof Man)
		{
			Man toOperate=(Man) body;
			if(toOperate.getState()!=OnMine.getInstance())
			{
				System.out.println("The man walk to mine");
				toOperate.changeState(OnMine.getInstance());

			}
			if(toOperate.getCurrentPower()==0)
			{
				System.out.println("man's pow is too low,he should sleep");
				toOperate.changeState(Tired.getInstance());
				return;
			}
			//work to get gold has 1/3 property to get the gold
			if(gener.nextInt(3)==2)
			{
				int getGold=gener.nextInt(toOperate.getMaxCapacity());
				if(toOperate.getCurrentCapacity()+getGold>toOperate.getMaxCapacity())
				{
					System.out.println("Gread have find gold but too much("+getGold+"), man should go to store");
					toOperate.addToCurrentCapacity(toOperate.getMaxCapacity()-toOperate.getCurrentCapacity());

				}
				else
				{

					toOperate.addToCurrentCapacity(getGold);
					System.out.println("Man get the gold "+getGold+"there captity is "+toOperate.getCurrentCapacity());
				}

			}
			else
			{
				System.out.println("man don't have good luck,nothing get");
			}
			toOperate.decreasePower();

			System.out.println("man have power:"+toOperate.getCurrentPower());
			if(toOperate.getCurrentPower()==0)
			{
				System.out.println("man's pow is too low,he should sleep");
				toOperate.changeState(Tired.getInstance());
				return;
			}
			if(toOperate.getCurrentCapacity()==toOperate.getMaxCapacity())
			{
				System.out.println("man's bag if full and he should go to change it");
				toOperate.changeState(BagFull.getInstance());
			}

		}

	}

}

file3(bagfull.java)

import java.util.Scanner;

public class BagFull extends State {

	private static BagFull OnlyOne=null;

	private BagFull()
	{

	}

	public static BagFull getInstance()
	{
		if(OnlyOne==null)
		{
			OnlyOne=new BagFull();
		}
		return OnlyOne;
	}
	@Override
	public void exec(Enity body) {
		// TODO Auto-generated method stub
		if(body instanceof Man)
		{
			Man toOperate=(Man) body;
			if(toOperate.getCurrentCapacity()!=toOperate.getMaxCapacity())
			{
				System.out.println("error in bagfull beacause bag is not full");
				new Scanner(System.in).nextLine();//system("pause")
			}

			System.out.println("man go to bank put the gold for money and he is very happy");
			toOperate.addMoney(toOperate.getCurrentCapacity()*10);
			System.out.println("man have money"+toOperate.getMoney());
			toOperate.setCurrentCapacity(0);

			toOperate.decreasePower();

			if(toOperate.getState()!=OnMine.getInstance())
			{
				System.out.println("man should move to the mine");
				toOperate.changeState(OnMine.getInstance());
			}
		}

	}

}

file4(tired.java)

import java.util.Scanner;

public class Tired extends State {

	private static Tired OnlyOne=null;
	private Tired()
	{

	}

	public static Tired getInstance()
	{
		if(OnlyOne==null)
		{
			OnlyOne=new Tired();
		}
		return OnlyOne;
	}

	@Override
	public void exec(Enity body) {
		// TODO Auto-generated method stub
		if(body instanceof Man)
		{
			Man toOperate=(Man) body;
			if(toOperate.getCurrentPower()!=0)
			{
				System.out.println("there is some problem in Tired currentpow is not 0");
				new Scanner(System.in).nextLine();//system("pause")
			}
			System.out.println("man is tired and should sleep a while");

			toOperate.recorverPower();
			if(toOperate.getCurrentCapacity()==toOperate.getMaxCapacity())
			{
				System.out.println("man find his bag is full after sleep,he should go to store it ");
				toOperate.changeState(BagFull.getInstance());
			}
			else
			{
				System.out.println("man is ready .and go to mine");
				toOperate.changeState(OnMine.getInstance());
			}
		}
	}

}

状态定义过后就需要实现游戏的主角了。矿工类。为了便于多态我们需要建立一个抽象基类enity类(这个单词有错误)。建立这个类的目的是为了方便以后把统一处理游戏中的NPC。但是本游戏只有一个矿工,所以意义不大。man类中有一个函数叫做update。这个函数用于更新每一步的状态。update会调用矿工状态的exec函数。这样就实现了矿工的自动化。于是又一个吴桂的故事开始了,因为这个游戏根本没有结束,也十分乏味,你要做的就是不听的按回车键。

file   enity.java

public abstract class Enity {

}

file man.java

public class Man extends Enity {
	private int maxCapacity;
	private int currentCapacity;
	private int maxPower;
	private int currentPower;
	private int money;
	private State preState;
	private State state;

	public Man()
	{
		maxCapacity=100;
		currentCapacity=0;
		maxPower=10;
		currentPower=maxPower;
		money=0;
		preState=null;
		state=OnMine.getInstance();
	}
	public void update()
	{
		state.exec(this);

	}
	public void changeState(State toState)
	{
		preState=state;
		state=toState;
	}

	public State getState()
	{
		return state;
	}

	public int getCurrentCapacity()
	{
		return currentCapacity;
	}
	public int getMaxCapacity()
	{
		return maxCapacity;
	}

	public void addToCurrentCapacity(int src)
	{
		if(src<0||currentCapacity+src>maxCapacity)
		{
			System.out.println("addtoCurrentcapacity error src negative or capacity overflow");
		}
		this.currentCapacity+=src;
	}

	public void setCurrentCapacity(int src)
	{
		currentCapacity=src;
	}

	public void decreasePower()
	{
		this.currentPower--;
		if(currentPower==0)
		{
			changeState(Tired.getInstance());
		}

	}

	public int getMoney()
	{
		return money;
	}

	public void addMoney(int src)
	{
		money+=src;
	}

	public void setMoney(int src)
	{
		money=src;
	}

	public int getCurrentPower()
	{
		return currentPower;
	}

	public void recorverPower()
	{
		currentPower=maxPower;
	}
}

在编程的过程中,我发现一个问题就是这样的编程虽然便于状态的扩展,但是每个状态的逻辑非常复杂,比如在每个状态减掉体力值后,一定要首先判断体力值是不是0,然后才能继续判断其他的事情。我想到的改进方法就是把所有状态改变都放到一个控制类里面,由控制类完成状态的改变。这样可以避免多次判断体力值的问题。我不知道作者在之后会不会改进这个类。为了方便大家,我把这个游戏的代码也放到了gitoschina上。地址在这里点击打开链接

时间: 2024-08-01 16:43:14

《游戏人工智能编程》感想一的相关文章

《游戏人工智能编程案例精粹》读书笔记&mdash;状态驱动智能体设计

一个有限状态机是一个设备,或是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得从一个状态变换到另一个状态,或者是促使一个输出或者一种行为的发生.一个有限状态机在任何瞬间只能处于一种状态. 状态变换表 状态变换表是一个条件和那些条件导致的状态的表,这个表可以被智能体在规则的间隔内训问,使得它能基于从游戏环境中接收到刺激进行必须的状态转换. 内置的规则 每个状态模块依靠自身的逻辑来决定它是否应该运行自己变换到一个替代状态,智能体只向外部提供操作和获取自身属性的函数,状态

《游戏人工智能编程案例精粹》读书笔记—数学和物理学初探

1.1.1 笛卡尔坐标系 在二维空间中,笛卡尔坐标系被定义成两个坐标轴成直角相交并且用单位长度标出.水平轴称为x 轴,而垂直轴称为y 轴,两个轴的交点称为原点,如图1.1 所示. 如图1.1所示,每个坐标轴端点的箭头表示它们在每个方向上无限延伸.假想有一张无限大的纸,上面有x 轴和y 轴,纸就表示 xy 平面,所有二维的笛卡尔坐标系中的点都可以给制在这个平面上.在2D 空间中的一个点可以用一对坐标(x,y) 表示.x 和y 的值代表沿着各自的轴上的距离. 为了表达三维空间,需要另外一个坐标轴z铀

c++游戏服务器编程学习笔记(一)

c++游戏服务器编程c++运行效率非常高TCP传输控制协议IP网际协议SocketLinux 乌班图开源第三方库BOOST80%游戏服务器端用C++工作量最大的地方是具体的游戏逻辑常见的游戏服务器框架和重点部分的实现IP网际协议详解OSI模型 开放系统的通信交互模型 学术性产物的应用层.表示层.会话层.传输层.网络层.链路层.物理层 IP模型产生于实践用于实践 成为标准 数据进入协议栈的封装以太网封装最小46字节,不足的用0最大1500个字节 IP协议特点:不可靠.无连接不能保证IP的数据报成功

《DirectX 9.0 3D游戏开发编程基础》 第一章 初始化Direct3D 读书笔记

REF设备 参考光栅设备,他能以软件计算方式完全支持Direct3D Api.借助Ref设备,可以在代码中使用那些不为当前硬件所支持的特性,并对这此特性进行测试. D3DDEVTYPE 在程序代码中,HAL设备用值D3DDEVTYPE_HAL来表示.该值是一个枚举变量.REF设备用D3DDEVTYPE_REF来表示.这种类型非常重要,你需要铭记,因为在创建设备的时候,我们必须指定使用哪种设备类型. COM(组件对象模型) 创建COM接口时不可以使用c++关键字new.此外使用完接口,应调用Rel

用Java开源项目JOONE实现人工智能编程

http://www.robotsky.com/ZhiN/MoS/2011-08-25/13142461416649.html http://www.robotsky.com  来源:网络  时间:2011-08-25   评论 0 条 (访问论坛) RobotSky恭候您的投稿>> 很少有程序员不对这里或者那里所包含的人工智能编程所吸引,然而,许多对AI感兴趣的程序员很快就因其中包含的算法的复杂性而退却.在本文中,我们将讨论一个能大大简化这种复杂性的Java开源工程. Java面向对象的神经

游戏网络编程(二)

游戏网络编程(二) 本篇介绍Socket编程,因为我觉得每个开始接触网络编程的人应该都是先从了解socket编程开始的吧.后面介绍的WebSocket也会和Socket编程的概念做比较,因此先介绍下Socket编程. 游戏网络编程二 什么是Socket 常用的Socket函数API WinSock CSocket Socket函数介绍 socket bind listen accept connect sendsendto recvrecvfrom select setsocketoptgets

初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程

详解游戏辅助编程 [目录] 1-什么是Windows API 2-Windows进程 3-Windows 的内存的运行原理 4-windows 中句柄的概念 5-Windows的变量类型 6-辅助实现的原理 7-编程实现游戏辅助 8-怎样查找内存地址 9-总结 准备软件:VC,CheatEngineer5.5 学习这部分内容,你必须要掌握C语言的基础知识,非常基础的语法就行了.这篇文章的内容适合刚开始接触编程的人,高手请飘过. [1]什么是windows API Windows API 中文翻译

关于游戏人工智能关键技能与应用的介绍

游戏人工智能集中体现了一款游戏的可玩性.随着智能技能的深入发展,游戏人工智能已成为提高一款游戏可玩性的技能核心,以及游戏推广的主要卖点,深化了游戏体验境界.因此,深入研讨分析游戏人工智能关键技能与应用具有极高的现实价值. [Abstract]The game artificial intelligence embodies a reflection of a game playability. With the further development of intelligent technol

硬核!奇点云一举斩获人工智能编程大赛一等奖、三等奖

10月30日,2019上海智慧城市建设「智慧工匠」选树暨软件开发与测试竞赛落幕,奇点云与来自云平台计算.人工智能编程等方向的学者同台竞技,共推人工智能及计算机视觉技术的交流与落地. ? 值得一提的是,奇点云算法工程师涉川.草窗以出色的专业成绩分别斩获本次人工智能赛事的一等奖.三等奖. (涉川.草窗现场领奖) 与往届相比,今年的赛事进一步聚焦云平台计算.人工智能等方向,以科技竞赛.创新方案等方式遴选出精英工程师,弘扬工匠精神. 开发者测试与人工智能编程竞赛是参赛者展示自身学术专业能力与创新技术沉淀