习题描述
狐狸、兔子都有年龄;
到达一定年龄上限会自然死亡;
狐狸随机吃掉周围一只兔子;
狐狸、兔子可以随机生一只小的放在旁边格子;
如果不吃不生,狐狸、兔子可以随机向旁边格子移一步会随机吃掉
Animal抽象类
animal抽象类是fox,rabbit的父类:
属性:ageLimit(生存时间),breedableAge(生育年龄),age(现年龄),isAlive;
方法:
**构造方法:**生存时间、生育年龄;
**简单方法:**获取年龄、年龄百分比、成长(到年龄死亡)、见耶稣、确定没死、确定能生、寿命增长的方法;
**抽象方法:**生育;
移动方法:
传入周围空cell坐标,返回其中一个空cell坐标。
**Animal返回值方法:**进食
package animal;
import java.util.ArrayList;
import field.Location;
public abstract class Animal{
private int ageLimit;
private int breedableAge;
private int age;
private boolean isAlive = true;
public Animal(int ageLimit, int breedableAge){
this.ageLimit = ageLimit;
this.breedableAge = breedableAge;
}
protected int getAge(){
return age;
}
protected double getAgePercent(){
return (double)age/ageLimit;
}
public abstract Animal breed();
public void grow(){
age++;
if(age > ageLimit){
die();
}
}
private void die() {
isAlive = false;
}
public boolean isAlive(){
return isAlive;
}
public boolean isBreedable(){
return age >breedableAge;
}
public Location move(Location[] freeAdj){
Location ret = null;
if( freeAdj.length > 0 && Math.random() < 0.02 ){
ret = freeAdj[(int)(Math.random()*freeAdj.length)];
}
return ret;
}
@Override
public String toString(){
return " "+age+":"+(isAlive?"live":"dead");
}
public Animal feed(ArrayList<Animal> neighbour){
return null;
}
protected void longerlife( int addage ){
ageLimit += addage;
}
}
Fox类:继承animal,cell
构造方法:生存时间20,生育年龄4;
重写抽象方法:animal的 生育、进食;
生育:5%概率生育,返回 Animal;
进食:返回cell(传入附近兔子数组),被吃掉概率0.2,可通过cell是否为null判断给否被吃掉;
重写接口cell方法:draw,传入cell 图,坐标,大小;
package animal;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import cell.Cell;
public class Fox extends Animal implements Cell{
public Fox(){
super(20,4); //最大年龄,生育年龄
}
@Override
public void draw( Graphics g, int x, int y, int size ){
int alpha = (int)((1-getAgePercent())*255);
g.setColor(new Color(0,0,0,alpha));
g.fillRect(x, y, size, size);
}
@Override
public Animal breed() {
Animal ret = null;
if( isBreedable() && Math.random() < 0.05 ){ //5%的几率breed
ret = new Fox();
}
return ret;
}
@Override
public String toString(){
return "Fox:"+super.toString();
}
@Override
public Animal feed(ArrayList<Animal> neighbour){ //返回被吃的兔子
Animal ret = null;
if( Math.random() < 0.2 ){
ret = neighbour.get((int)(Math.random()*neighbour.size()));
longerlife(2);
}
return ret;
}
}
Rabbit类:继承animal,cell
构造方法:生存时间10,生育年龄2;
重写抽象方法:animal的 生育、进食;
生育:12%概率生育,返回 Animal;
重写接口cell方法:draw,传入cell 图,坐标,大小;
package animal;
import java.awt.Color;
import java.awt.Graphics;
import cell.Cell;
public class Rabbit extends Animal implements Cell{
public Rabbit() {
super(10, 2);
}
@Override
public void draw(Graphics g, int x, int y, int size) {
int alpha = (int)((1-getAgePercent())*255);
g.setColor(new Color(255,0,0,alpha));
g.fillRect(x, y, size, size);
}
@Override
public Animal breed() {
Animal ret = null;
if( isBreedable() && Math.random() < 0.12 ){ //12%的几率breed
ret = new Rabbit();
}
return ret;
}
@Override
public String toString(){
return "Rabbit:"+super.toString();
}
}
Cell接口:
package cell;
import java.awt.Graphics;
public interface Cell {
void draw ( Graphics g, int x, int y, int size );
}
Location类:
用于定位,返回所要cell位置
package field;
public class Location{
private int row;
private int col;
public Location( int row, int col ){
this.col = col;
this.row = row;
}
public int getRow(){
return row;
}
public int getCol() {
return col;
}
}
Field类:
属性:长、宽、cell二维数组;
构造方法:生成指定大小cell二维数组;
简单方法:获取长、宽、指定cell;
获取周围细胞方法:输入现在细胞坐标,返回周围细胞数组;
获取周围空cell数组:输入现在细胞坐标,返回空cell坐标数组;
在周围空cell里放置一个cell:
输入现在细胞坐标 和 放入的cell;返回是否成功放入cell进field;
根据坐标删除cell:输入坐标,删除cell(置field数组指空),返回删除;
根据细胞删除cell:输入细胞,细胞删除(此处可以优化);
clear方法:删除所有细胞;
move方法:细胞移动;
package field;
import java.util.ArrayList;
import cell.Cell;
public class Field {
// 这段代码没用到过
// private static final Location[] adjacent = {
// new Location(-1,-1),new Location(-1,0),new Location(-1,1),
// new Location(0,-1) ,new Location(0,0) ,new Location(0,-1),
// new Location(1,-1) ,new Location(1,-1),new Location(1,-1),
// };
private int width;
private int height;
private Cell[][] field;
public Field(int width, int height){
this.height = height;
this.width = width;
field = new Cell[height][width];
}
public int getWidth(){ return width; }
public int getHeight(){ return height; }
public Cell get(int row, int col){
return field[row][col];
}
public Cell[] getNeighbour(int row, int col) {
ArrayList<Cell> list = new ArrayList<Cell>();
for( int i = -1; i<2; i++ ) {
for( int j = -1; j<2; j++ ) {
int r = row+i;
int c = col+j;
if( r>-1 && r<height && c>-1 && c<width && !(r == row && c == col)) {
list.add(field[r][c]);
}
}
}
return list.toArray(new Cell[list.size()]);
}
//列出周围空cell的数组
public Location[] getFreeNeighbour(int row, int col) {
ArrayList<Location> list = new ArrayList<Location>();
for( int i = -1; i<2; i++ ) {
for( int j = -1; j<2; j++ ) {
int r = row+i;
int c = col+j;
if( r>-1 && r<height && c>-1 && c<width && field[r][c] == null ) {
list.add(new Location(r, c));
}
}
}
return list.toArray(new Location[list.size()]);
}
public boolean placeRandomAdj( int row, int col, Cell cell ){
boolean ret = false;
Location[] FreeAdj = getFreeNeighbour(row, col);
if( FreeAdj.length > 0 ){
int idx = (int)(Math.random()*FreeAdj.length);
field[FreeAdj[idx].getRow()][FreeAdj[idx].getCol()] = cell;
ret = true;
}
return ret;
}
public Cell remove( int row, int col ){
Cell ret = field[row][col];
field[row][col] = null;
return ret;
}
public void remove( Cell cell ){
for( int row = 0; row < height; row++ ){
for( int col = 0; col <width; col++ ){
if( field[row][col] == cell ){
field[row][col] = null;
break;
}
}
}
}
public void clear(){
for( int i = 0; i < height; i++){
for( int j = 0; j < width; j++){
field[i][j] = null;
}
}
}
public void move(int row, int col, Location loc){
field[loc.getRow()][loc.getCol()] = field[row][col];
remove(row,col);
}
public Cell place(int row, int col, Cell c) {
Cell ret = field[row][col];
field[row][col] = c;
return ret;
}
}
view类:
继承自JPanel面板
重写的方法:paint,设置刚好的尺寸;
package field;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import cell.Cell;
public class View extends JPanel{
private static final long serialVersionUID = -2417015700213488315L;
private static final int GRID_SIZE = 16;
private Field thefield;
public View (Field field){
thefield = field;
}
@Override
public void paint( Graphics g ){
super.paint(g);
g.setColor(Color.gray);
for( int row = 0; row < thefield.getHeight(); row++ ){
g.drawLine(0, row*GRID_SIZE, thefield.getWidth()*GRID_SIZE, row*GRID_SIZE);
}
for( int col = 0; col < thefield.getHeight(); col++ ){
g.drawLine(col*GRID_SIZE, 0, col*GRID_SIZE, thefield.getHeight()*GRID_SIZE);
}
for( int row = 0; row < thefield.getHeight(); row++){
for( int col = 0; col < thefield.getWidth(); col++){
Cell cell = thefield.get(row, col);
if( cell != null ){
cell.draw( g, col*GRID_SIZE, row*GRID_SIZE, GRID_SIZE);
}
}
}
}
@Override
public Dimension getPreferredSize(){
return new Dimension(thefield.getWidth()*GRID_SIZE+1, thefield.getHeight()*GRID_SIZE+1);
}
}
FoxAndRabbit程序执行入口:
主要思想:两层for循环,挨个cell执行移动、进食、生育;每次循环结束后repaint view;
package FoxAndRabbit;
import field.Field;
import field.View;
import field.Location;
import java.util.ArrayList;
import javax.swing.JFrame;
import animal.Fox;
import animal.Rabbit;
import animal.Animal;
import cell.Cell;
public class FoxAndRabbit{
private Field thefield;
private View theview;
public FoxAndRabbit( int size ){
thefield = new Field(size, size);
for( int row = 0; row <thefield.getHeight(); row++ ){
for( int col = 0; col < thefield.getWidth(); col++ ){
double probability = Math.random();
if( probability <0.05 ){
thefield.place( row, col, new Fox());
}else if( probability < 0.15 ){
thefield.place( row, col, new Rabbit());
}
}
}
theview = new View(thefield);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle("FoxAndRabbit");
frame.add(theview);
frame.pack();
frame.setVisible(true);
}
public void step(){
for( int row = 0; row < thefield.getHeight(); row++ ){
for( int col = 0; col < thefield.getWidth(); col++ ){
Cell cell = thefield.get(row, col);
if( cell != null ){
Animal animal = (Animal)cell;
animal.grow();
if( animal.isAlive()){
//move
Location loc = animal.move(thefield.getFreeNeighbour(row, col));
if( loc != null ){
thefield.move(row, col, loc);
}
//eat animal.eat(thefield);
if( animal instanceof Fox){
Cell[] neighbour = thefield.getNeighbour(row, col);
ArrayList<Animal> listRabbit = new ArrayList<Animal>();
for( Cell an : neighbour ){
if( an instanceof Rabbit ){
listRabbit.add( (Rabbit)an );
}
}
if( !listRabbit.isEmpty() ){
Animal fed = animal.feed(listRabbit);
if( fed != null ){
thefield.remove((Cell)fed);
}
}
}
//breed
Animal baby = animal.breed();
if( baby != null ){
thefield.placeRandomAdj(row, col, (Cell)baby);
}
}else{
thefield.remove(row, col);
}
}
}
}
}
public void start( int steps ){
for( int i = 0; i < steps; i++){
step();
theview.repaint();
try{
Thread.sleep(200);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
FoxAndRabbit fnr = new FoxAndRabbit(30);
fnr.start(10);
}
}