在獨自看了Java兩個禮拜後,決定寫支程式來練習,遂想了一個模擬動物行為的程式.
原本是想以物件繼承的方式來寫,例如:獅子是一個物件,繼承自肉食動物,肉食動物
又繼承自動物,動物又繼承自生物,其物件關係如下:
生物<------動物<------肉食性動物<------獅子
(生長) | (移動) | (獵食)
(死亡) | (進食) |
(繁殖) | (睡眠) |
| ---草食性動物<------鹿
| (躲藏)
|
-----植物<------草
括號內是method
不過寫了一半就放棄以物件的方式來寫, 因為像移動,獵食,躲藏這些method,很抽象,不知如何實作.
如果以thread的方式來寫,不知行不行? 例如一隻獅子,一隻鹿就是一個thread.如可以,該如何寫呢?
本程式run到一半會停住,不知是何原因? 不曉得能否用exception來處理?
附source code 及 html 如下, 還望各位先進們不吝指教.
//
// SimAnimal ver 1.0 designed by Chen Jong-ming Dec. 21,1998
// 模擬動物程式 1.0版 設計者: 陳中明 1998年12月21日
// E-mail: vchen@iii.org.tw
//
//本程式模擬動物世界中的繁殖,死亡,弱肉強食.
//草食性動物只吃草,肉食性動物只吃肉,雜食性動物則都吃.
//動物走過的地方會留下氣味,過一段時間會長出草來.
//肉食動物藉由氣味,跟蹤弱小動物;弱小動物也會憑氣味遠離肉食動物.
//有些動物(如獅)速度雖快,耐力卻不夠,不能長時間追獵.
//有些動物(如鹿)速度雖不快,卻能持久,能長時間全速奔逃.
//正常體力的動物是黑色,當體力下降至非黑色時,才需覓食.
//動物只要有移動就會降低體力,移動愈快,體力遞減愈多,進食則可恢復體力.
//有些動物生育期很短(如兔),能在短時間,繁殖下一代.
//有些動物生育期很長(如熊),需較長時間,繁殖下一代.
//繁殖需在體力足夠時才可,即體力顏色在黑色及藍色時才可繁殖.
//每種動物壽命不一樣,時間一到,就會壽終正寢;體力耗盡也會死亡.
//
import java.applet.*;
import java.awt.*;
public class SimAnimal extends Applet
{
byte map[][][];
static final int xMin=10,xMax=740,yMin=50,yMax=340;//設定動物移動範圍
private Button createLion;
private Button createBear;
private Button createDeer;
private Button createHare;
private Button createGrass;
private Button SaveQuit;
private Button play;
byte animal=0; // 9=獅,6=熊,3=鹿,2=兔,-1=草,-98=play,-99=quit
int lapse=0;模擬時間
String ai=new String(". hd B L");// 動物圖示
int ac[][]= {// 特性 0<-速度,1<-耐力,2<-生育期,3<-壽命,4<-食性,5=居性
// 6<-現有數量,7<-死亡數量,8<-出生數量
// 0, 1, 2, 3, 4, 5, 6, 7, 8
// 速度,耐力,生育,壽命,食性,棲性,數量,死亡,出生
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//草
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//
{ 70, -5, 31, 80, 0, 0, 0, 0, 0},//兔,草食
{110, -1, 37, 100, 0, 0, 0, 0, 0},//鹿,草食
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//
{ 70, -5, 46, 110, 2, 0, 0, 0, 0},//熊,雜食
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//
{ 0, 0, 0, 0, 0, 0, 0, 0, 0},//
{120, -6, 41, 120, 1, 0, 0, 0, 0} //獅,肉食
};
public void init()
{
map=new byte[yMax][xMax][4];// 0<-動物,1<-體力,2<-速度,3<-壽命
createLion=new Button("L獅");
createBear=new Button("B熊");
createDeer=new Button("d鹿");
createHare=new Button("h兔");
createGrass=new Button(".草");
SaveQuit=new Button("Quit");
play=new Button("PLAY");
add(createLion);
add(createBear);
add(createDeer);
add(createHare);
add(createGrass);
add(SaveQuit);
add(play);
}
public void paint(Graphics g)
{
g.drawString("獅數量: "+ac[9][6],1,13);
g.drawString("熊數量: "+ac[6][6],100,13);
g.drawString("鹿數量: "+ac[3][6],550,13);
g.drawString("兔數量: "+ac[2][6],650,13);
g.drawString("死亡數: "+ac[9][7],1,27);
g.drawString("死亡數: "+ac[6][7],100,27);
g.drawString("死亡數: "+ac[3][7],550,27);
g.drawString("死亡數: "+ac[2][7],650,27);
g.drawString("出生數: "+ac[9][8],1,40);
g.drawString("出生數: "+ac[6][8],100,40);
g.drawString("出生數: "+ac[3][8],550,40);
g.drawString("出生數: "+ac[2][8],650,40);
for(int r=yMin;r<yMax;r++)//畫出動物
for(int c=xMin;c<xMax;c++)
{
if(map[r][c][0]!=0&&map[r][c][0]>-2)
{
if(map[r][c][0]==-1)
{
g.setColor(Color.green);//草
g.drawString(".",c,r);
}
else
if(map[r][c][0]>0)
{
if(map[r][c][1]<-50)g.setColor(Color.pink);
else if(map[r][c][1]<0)g.setColor(Color.orange);
else if(map[r][c][1]<50)g.setColor(Color.yellow);
else if(map[r][c][1]<100)g.setColor(Color.blue);
else g.setColor(Color.black);
g.drawString(""+ai.charAt(map[r][c][0]),c,r);
}
}
if(map[r][c][0]<-1&&lapse%10==0)
{
map[r][c][0]=-1;//氣味消失,草長出
map[r][c][3]=(byte)ac[0][3];
}
}
//獵食及逃脫
for(int r=yMin;r<yMax;r++)
for(int c=xMin;c<xMax;c++)
{
if(map[r][c][0]>0||map[r][c][0]==-1)
{ //動物或草
if((map[r][c][0]>0&&map[r][c][1]<-100)||(--map[r][c][3]<-110))
{ //壽終正寢或體力衰竭,死亡
if(map[r][c][0]>0)
{ //紀錄動物死亡
ac[map[r][c][0]][6]--;
ac[map[r][c][0]][7]++;
}
map[r][c][0]=0;
continue;
}
if(map[r][c][0]==-1)continue;
//該動物(位於r,c)要先觀察四週
byte smell=0;//0=觀察週遭,1=嗅氣味
boolean move=false;
do
{
for(int n=1;n<map[r][c][2]/4;n++)//n是觀察範圍,由近而遠
{
if(move)break;
for(int xx=c-n;xx<c+n;xx++)
{
if(move)break;
if(xx<xMin||xx>xMax)continue;
for(int yy=r-n;yy<r+n;yy++)
{
if(yy<yMin||yy>yMax)continue;
//取動物代號之絕對值,如獅是9;獅的氣味-9,abs值是9
byte mm=(byte)Math.abs(map[yy][xx][0]);
// 鄰近的動物比自身強悍 || 聞到動物氣味
if(map[yy][xx][0]>map[r][c][0]||(smell==1&&map[yy][xx][0]<-1))
{
int acc=ac[mm][4];
//非草食&&比自身強悍
if(acc>0&&mm>map[r][c][0])
{ //該處(xx,yy)有獵食動物,準備脫逃
int ex=c+(c>xx?1:-1)*map[r][c][2]/10;//X軸逃脫位移;
int ey=r+(r>yy?1:-1)*map[r][c][2]/10;//Y軸逃脫位移;
if(Math.abs(map[ey][ex][0])<2&&ex>xMin&&ex<xMax&&ey>yMin&&ey<yMax)
{ //要落腳的地方沒其他動物
for(int z=0;z<4;z++)
map[ey][ex][z]=map[r][c][z];//動物移位
map[r][c][0]=(byte)(-map[r][c][0]);//清除動物先前位置,留下氣味
map[ey][ex][1]-=Math.abs(ey+ex-r-c)/5;//體力遞減
//速度-耐力
map[ey][ex][2]=(byte)(map[ey][ex][2]+ac[map[ey][ex][0]][1]);
if(map[ey][ex][2]<ac[map[ey][ex][0]][0]*0.5)
//當速度降至50%以下時,再恢復原速
map[ey][ex][2]=(byte)ac[map[ey][ex][0]][0];
}
move=true;//動物有移動
break;
}
}
else if(map[r][c][1]<100&&mm<map[r][c][0])
// 聞到動物氣味 || 草 || 動物
if((smell==1&&map[yy][xx][0]<-1)||map[yy][xx][0]==-1||map[yy][xx][0]>0)
{ //當體力降至100以下,就要獵食,獵物在(yy,xx)
int hy=yy,hx=xx,range=map[r][c][2]/10;
if(Math.abs(yy-r)<=range&&Math.abs(xx-c)<=range&&smell==0)
{ //獵物在速度範圍內,吃掉獵物
if(ac[map[r][c][0]][4]!=1&&map[yy][xx][0]==-1)
map[r][c][1]++;//非肉食動物,吃草後體力加1
else
if(map[yy][xx][0]>0)
{ //非草食動物
ac[map[yy][xx][0]][6]--;//獵物現有數量減1
ac[map[yy][xx][0]][7]++;//獵物死亡數量加1
//獵食後,體力增加,速度恢復原速
map[r][c][1]=(byte)(map[r][c][1]+map[yy][xx][0]*10);
map[r][c][2]=(byte)ac[map[r][c][0]][0];
}
else continue;//沒有吃到任何東西,掃描下個位置
}
else
{ //追趕獵物
hx=c+(c>xx?1:-1)*range;//X軸追趕位移;
hy=r+(r>yy?1:-1)*range;//Y軸追趕位移;
if(hx<xMin||hx>xMax||hy<yMin||hy>yMax)continue;
}
for(int z=0;z<4;z++)
map[hy][hx][z]=map[r][c][z];//動物移位
map[r][c][0]=(byte)(-map[r][c][0]);//清除動物先前位置,留下氣味
//速度-耐力
map[hy][hx][2]=(byte)(map[hy][hx][2]+ac[map[hy][hx][0]][1]);
if(map[hy][hx][2]<ac[map[hy][hx][0]][0]*0.5)
//當速度降至50%以下時,再恢復原速
map[hy][hx][2]=(byte)ac[map[hy][hx][0]][0];
move=true;//動物有移動
break;
}
}//for yy
}//for xx
}//for nn
}while(!move&&(++smell<2));
if(!move)
{ //沒有進食,也沒有脫逃,就亂數漫遊
int rr=(int)((1-2*Math.random())*map[r][c][2]/20);
int cc=(int)((1-2*Math.random())*map[r][c][2]/20);
int ex=c+cc,ey=r+rr;
if((rr!=0||cc!=0)&&ex>xMin&&ex<xMax&&ey>yMin&&ey<yMax)
{
map[r][c][1]--;//體力遞減
for(int z=0;z<4;z++)
map[ey][ex][z]=map[r][c][z];//動物移位
map[r][c][0]=(byte)(-map[r][c][0]);//清除動物先前位置,留下氣味
int age=ac[map[ey][ex][0]][3]-map[ey][ex][3];
int birth=(age%ac[map[ey][ex][0]][2]);
if(map[ey][ex][1]>50&&birth==0&&age>0)
{ //體力足又到生育年齡就生下一代
byte ani=map[ey][ex][0];
map[r][c][0]=ani;//生出幼子
map[r][c][1]=127;//給定幼子體力,127是最大值
map[r][c][2]=(byte)ac[ani][0];//給定幼子速度
map[r][c][3]=(byte)ac[ani][3];//給定幼子壽命
ac[ani][6]++;//增加現有數量
ac[ani][8]++;//增加出生數量
}
}
}
}//if map[r][c][0]
}//for c
if(animal==-98)
{
repaint();
for(int delay=0;delay<5000;delay++)
g.drawString(""+delay,200,15);
}
showStatus("模擬時間: "+lapse++);
}
//選擇動物產生的地點
public boolean mouseDown(Event e,int x,int y)
{
if(animal==-98)return true;
showStatus("mouse"+x+" "+y);
if(x<xMin||x>xMax||y<yMin||y>yMax)
{
showStatus("超出範圍");
return true;
}
if(map[y][x][0]==0||map[y][x][0]==-1)
{
byte ani=animal;
map[y][x][0]=animal;
if(animal==-1)ani=0;
map[y][x][1]=127;//體力,127是最大值
map[y][x][2]=(byte)ac[ani][0];//速度
map[y][x][3]=(byte)ac[ani][3];//壽命
ac[ani][6]++;//增加現有數量
repaint();
}
else showStatus("該位置有其他動物");
return true;
}
//選擇要產生的動物
public boolean action(Event e,Object o)
{
if(e.target==play)
{
animal=-98;
repaint();
}
if(e.target==createLion)animal=9;
if(e.target==createBear)animal=6;
if(e.target==createDeer)animal=3;
if(e.target==createHare)animal=2;
if(e.target==createGrass)animal=-1;
if(e.target==SaveQuit)animal=-99;
showStatus("移動滑鼠到你想要產生動物的地方");
return true;
}
}
<html>
<head>
<title>SimAnimal</title>
</head>
<body>
<hr>
<applet
code=SimAnimal
width=750
height=350>
</applet>
<hr>
</body>
</html>
--=Smart Mailvchen@iii.org.tw-Thu-Dec-24-14-33-57=--
--
* Origin: ★ 交通大學資訊科學系 BBS ★ <bbs.cis.nctu.edu.tw: 140.113.23.3>