友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第110部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
applet。start();
aFrame。setVisible(true);
}
}
class StripQualifiers {
private StreamTokenizer st;
public StripQualifiers(String qualified) {
st = new StreamTokenizer(
new StringReader(qualified));
st。ordinaryChar(' ');
}
public String getNext() {
String s = null;
try {
if(st。nextToken() !=
StreamTokenizer。TT_EOF) {
switch(st。ttype) {
case StreamTokenizer。TT_EOL:
s = null;
break;
case StreamTokenizer。TT_NUMBER:
s = Double。toString(st。nval);
break;
case StreamTokenizer。TT_WORD:
s = new String(st。sval);
break;
default: // single character in ttype
s = String。valueOf((char)st。ttype);
}
}
} catch(IOException e) {
System。out。println(e);
}
return s;
}
public static String strip(String qualified) {
StripQualifiers sq =
new StripQualifiers(qualified);
String s = 〃〃; si;
while((si = sq。getNext()) != null) {
int lastDot = si。lastIndexOf('。');
if(lastDot != …1)
si = si。substring(lastDot + 1);
s += si;
}
return s;
}
} ///:~
642
…………………………………………………………Page 644……………………………………………………………
程序中的有些东西已在以前见识过了。和本书的许多GUI 程序一样,这既可作为一个独立的应用程序使用,
亦可作为一个程序片(Applet)使用。此外,StripQualifiers 类与它在第 11 章的表现是完全一样的。
GUI 包含了一个名为name 的“文本字段”(TextField),或在其中输入想查找的类名;还包含了另一个文
本字段,名为 searchFor,可选择性地在其中输入一定的文字,希望在方法列表中查找那些文字。Checkbox
(复选框)允许我们指出最终希望在输出中使用完整的名字,还是将前面的各种限定信息删去。最后,结果
显示于一个“文本区域”(TextArea )中。
大家会注意到这个程序未使用任何按钮或其他组件,不能用它们开始一次搜索。这是由于无论文本字段还是
复选框都会受到它们的“侦听者(Listener )对象的监视。只要作出一项改变,结果列表便会立即更新。若
改变了name 字段中的文字,新的文字就会在 NameL 类中捕获。若文字不为空,则在Class。forName()中用于
尝试查找类。当然,在文字键入期间,名字可能会变得不完整,而Class。forName()会失败,这意味着它会
“掷”出一个违例。该违例会被捕获,TextArea 会随之设为“Nomatch”(没有相符)。但只要键入了一个
正确的名字(大小写也算在内),Class。forName()就会成功,而 getMethods()和 getConstructors()会分别
返回由Method 和 Constructor 对象构成的一个数组。这些数组中的每个对象都会通过toString()转变成一
个字串(这样便产生了完整的方法或构建器签名),而且两个列表都会合并到 n 中——一个独立的字串数
组。数组n 属于DisplayMethods 类的一名成员,并在调用reDisplay()时用于显示的更新。
若改变了Checkbox 或 searchFor 组件,它们的“侦听者”会简单地调用reDisplay()。reDisplay()会创建
一个临时数组,其中包含了名为rs 的字串(rs 代表“结果集”——Result Set)。结果集要么直接从n 复
制(没有find 关键字),要么选择性地从包含了 find 关键字的n 中的字串复制。最后会检查strip
Checkbox,看看用户是不是希望将名字中多余的部分删除(默认为“是”)。若答案是肯定的,则用
StripQualifiers。strip()做这件事情;反之,就将列表简单地显示出来。
在 init()中,大家也许认为在设置布局时需要进行大量繁重的工作。事实上,组件的布置完全可能只需要极
少的工作。但象这样使用BorderLayout 的好处是它允许用户改变窗口的大小,并特别能使 TextArea (文本
区域)更大一些,这意味着我们可以改变大小,以便毋需滚动即可看到更长的名字。
编程时,大家会发现特别有必要让这个工具处于运行状态,因为在试图判断要调用什么方法的时候,它提供
了最好的方法之一。
17。3 复杂性理论
下面要介绍的程序的前身是由Larry O'Brien 原创的一些代码,并以由 Craig Reynolds 于 1986 年编制的
“Boids”程序为基础,当时是为了演示复杂性理论的一个特殊问题,名为“凸显”(Emergence)。
这儿要达到的目标是通过为每种动物都规定少许简单的规则,从而逼真地再现动物的群聚行为。每个动物都
能看到看到整个环境以及环境中的其他动物,但它只与一系列附近的“群聚伙伴”打交道。动物的移动基于
三个简单的引导行为:
(1) 分隔:避免本地群聚伙伴过于拥挤。
(2) 方向:遵从本地群聚伙伴的普遍方向。
(3) 聚合:朝本地群聚伙伴组的中心移动。
更复杂的模型甚至可以包括障碍物的因素,动物能预知和避免与障碍冲突的能力,所以它们能围绕环境中的
固定物体自由活动。除此以外,动物也可能有自己的特殊目标,这也许会造成群体按特定的路径前进。为简
化讨论,避免障碍以及目标搜寻的因素并未包括到这里建立的模型中。
尽管计算机本身比较简陋,而且采用的规则也相当简单,但结果看起来是真实的。也就是说,相当逼真的行
为从这个简单的模型中“凸显”出来了。
程序以合成到一起的应用程序/程序片的形式提供:
//: FieldOBeasts。java
// Demonstration of plexity theory; simulates
// herding behavior in animals。 Adapted from
// a program by Larry O'Brien lobrien@msn。
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
import java。util。*;
class Beast {
643
…………………………………………………………Page 645……………………………………………………………
int
x; y; // Screen position
currentSpeed; // Pixels per second
float currentDirection; // Radians
Color color; // Fill color
FieldOBeasts field; // Where the Beast roams
static final int GSIZE = 10; // Graphic size
public Beast(FieldOBeasts f; int x; int y;
float cD; int cS; Color c) {
field = f;
this。x = x;
this。y = y;
currentDirection = cD;
currentSpeed = cS;
color = c;
}
public void step() {
// You move based on those within your sight:
Vector seen = field。beastListInSector(this);
// If you're not out in front
if(seen。size() 》 0) {
// Gather data on those you see
int totalSpeed = 0;
float totalBearing = 0。0f ;
float distanceToNearest = 100000。0f;
Beast nearestBeast =
(Beast)seen。elementAt(0);
Enumeration e = seen。elements();
while(e。hasMoreElements()) {
Beast aBeast = (Beast) e。nextElement();
totalSpeed += aBeast。currentSpeed;
float bearing =
aBeast。bearingFromPointAlongAxis(
x; y; currentDirection);
totalBearing += bearing;
float distanceToBeast =
aBeast。distanceFromPoint(x; y);
if(distanceToBeast 《 distanceToNearest) {
nearestBeast = aBeast;
distanceToNearest = distanceToBeast;
}
}
// Rule 1: Match average speed of those
// in the list:
currentSpeed = totalSpeed / seen。size();
// Rule 2: Move towards the perceived
// center of gravity of the herd:
currentDirection =
totalBearing / seen。size();
// Rule 3: Maintain a minimum distance
// from those around you:
644
…………………………………………………………Page 646……………………………………………………………
if(distanceToNearest field。maxSpeed) {
currentSpeed = field。maxSpeed;
}
}
}
else { // You are in front; so slow down
currentSpeed =
(int)(currentSpeed * field。decayRate);
}
// Make the beast move:
x += (int)(Math。cos(currentDirection)
* currentSpeed);
y += (int)(Math。sin(currentDirection)
* currentSpeed);
x %= field。xExtent;
y %= field。yExtent;
if(x 《 0)
x += field。xExtent;
if(y 《 0)
y += field。yExtent;
}
public float bearingFromPointAlongAxis (
int originX; int originY; float axis) {
// Returns bearing angle of the current Beast
// in the world coordiante system
try {
double bearingInRadians =
Math。atan(
(this。y originY) /
(this。x originX));
// Inverse tan has two solutions; so you
// have to correct for other quarters:
if(x 《 originX) {
if(y 《 originY) {
bearingInRadians += (float)Math。PI;
}
else {
bearingInRadians =
(float)Math。PI bearingInRadians;
}
}
// Just subtract the axis (in radians):
return (float) (axis bearingInRadians);
} catch(ArithmeticException aE) {
// Divide by 0 error possible on this
if(x 》 originX) {
return 0;
645
…………………………………………………………Page 647……………………………………………………………
}
else
return (float) Math。PI;
}
}
public float distanceFromPoint(int x1; int y1){
return (float) Math。sqrt(
Math。pow(x1 x; 2) +
Math。pow(y1 y; 2));
}
public Point position() {
return new Point(x; y);
}
// Beasts know how to draw themselves:
public void draw(Graphics g) {
g。setColor(color);
int directionInDegrees = (int)(
(currentDirection * 360) / (2 * Math。PI));
int startAngle = directionInDegrees
FieldOBeasts。halfFieldOfView;
int endAngle = 90;
g。fillArc(x; y; GSIZE; GSIZE;
startAngle; endAngle);
}
}
public class FieldOBeasts extends Applet
implements Runnable {
private Vector beasts;
static float
fieldOfView =
(float) (Math。PI / 4); // In radians
// Deceleration % per second:
decayRate = 1。0f;
minimumDistance = 10f; // In pixels
static int
halfFieldOfView = (int)(
(fieldOfView * 360) / (2 * Math。PI));
xExtent = 0;
yExtent = 0;
numBeasts = 50;
maxSpeed = 20; // Pixels/second
boolean uniqueColors = true;
Thread thisThread;
int delay = 25;
public void init() {
if (xExtent == 0 && yExtent == 0) {
xExtent = Integer。parseInt(
getParameter(〃xExtent〃));
yExtent = Integer。parseInt(
getParameter(〃yExtent〃));
}
646
…………………………………………………………Page 648……………………………………………………………
beasts =
makeBeastVector(numBeasts; uniqueColors);
// Now start the beasts a…rovin':
thisThread = new Thread(this);
thisThread。start();
}
public void run() {
while(true) {
for(int i = 0; i 《 beasts。size(); i++){
Beast b = (Beast) beasts。elementAt(i);
b。step();
}
try {
thisThread。sleep(delay);
} catch(InterruptedException ex){}
repaint(); // Otherwise it won't update
}
}
Vector makeBeastVector(
int quantity; boolean uniqueColors) {
Vector newBeasts = new Vector();
Random generator = new Random();
// Used only if uniqueColors is on:
double cubeRootOfBeastNumber =
Math。pow((double)numBeasts; 1。0 / 3。0);
float colorCubeStepSize =
(float) (1。0 / cubeRootOfBeastNumber);
float r = 0。0f;
float g = 0。0f;
float b = 0。0f;
for(int i = 0; i 《 quantity; i++) {
int x =
(int) (generator。nextFloat() * xExtent);
if(x 》 xExtent Beast。GSIZE)
x …= Beast。GSIZE;
int y =
(int) (generator。nextFloat() * yExtent);
if(y 》 yExtent Beast。GSIZE)
y …= Beast。GSIZE;
float direction = (float)(
generator。nextFloat() * 2 * Math。PI);
int speed = (int)(
generator。nextFloat() * (float)maxSpeed);
if(uniqueColors) {
r += colorCubeStepSize;
if(r 》 1。0) {
r …= 1。0f;
g += colorCubeStepSize;
if( g 》 1。0) {
g …= 1。0f;
b += colorCubeStepSize;
if(b 》 1。0)
647
…………………………………………………………Page 649……………………………………………………………
b …= 1。0f;
}
}
}
newBeasts。addElement(
new Beast(this; x; y; direction; speed;
new Color(r;g;b)));
}
return newBeasts;
}
public Vector beastListInSector(Beast viewer) {
Vector output = new Vector();
Enumeration e = beasts。elements();
Beast aBeast = (Beast)beasts。elementAt(0);
int counter = 0;
while(e。hasMoreElements()) {
aBeast = (Beast) e。nextElement();
if(aBeast != viewer) {
Point p = aBeast。position();
Point v = viewer。position();
float bearing =
aBeast。bearingFromPointAlongAxis(
v。x; v。y; viewer。currentDirection);
if(Math。abs(bearing) 《 fieldOfView / 2)
output。addElement(aBeast);
}
}
return output;
}
public void paint(Graphics g) {
Enumeration e = beasts。elements();
while(e。hasMoreElements()) {
((Beast)e。nextElement())。draw(g);
}
}
public static void main(String'' args) {
FieldOBeasts field = new FieldOBeasts();
field。xExtent = 640;
field。yExtent = 480;
Frame frame = new Frame(〃Field 'O Beasts〃);
// Optionally use a mand…line argument
// for the sleep time:
if(args。length 》= 1)
field。delay = Integer。parseInt(args'0');
frame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
frame。add(field; BorderLayout。CENTER);
frame。setSize(640;480);
648
…………………………………………………………Page 650……………………………………………………………
field。init();
field。start();
frame。setVisible(true);
}
} ///:~
尽管这并非对Craig Reynold 的“Boids”例子中的行为完美重现,但它却展现出了自己独有的迷人之外。通
过对数字进行调整,即可进行全面的修改。至于与这种群聚行为有关的更多的情况,大家可以访问Craig
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!