创建简单的二维“捕食者-被捕食者”模拟程序。被捕食者是蚂蚁(ant),捕食者是狮蚁(doodlebug)。这些小生物生活在20×20的网格世界中。每个单元格每次只能由一个个体占据。网格是封闭的,所以个体不允许离开网格世界边缘。时间以time step为单位,个体在每个time step里面都要采取某项行动。具体规则如下:
1. 建立蚂蚁的行为规则模型。
(1)Move(移动):在每个time step中,都随机向上、向下、向左或者向右移动。假如所选方向上的邻居单元格被占据,或者会造成蚂蚁移动到网格的边缘之外,那么蚂蚁就停留在当前的单元格中。
(2)Breed(繁殖):如果一只蚂蚁在3个time step中保存存活,在第3个time step结束之后(也就是在移动之后),该蚂蚁会繁殖。为了模拟繁殖,需要在相邻(上、下、左或者右)的一个空单元格中创建一只新蚂蚁。没有可用的空单元格,就不会繁殖。一旦成功繁殖出后代,除非再次经历3个time step,否则不能繁殖另一个后代。
2. 建立狮蚁的行为规则模型。
(1)Move(移动):在每个time step中,假如有一只相邻的蚂蚁(上、下、左或者右),就移动到那个单元格,吃掉蚂蚁。否则,狮蚁就按照和蚂蚁相同的规则移动。注意,狮蚁不能吃掉狮蚁。
(2)Breed(繁殖):假如一只狮蚁在8个time step中保持存活,在第8个time step结束之后,会按照与蚂蚁相同的方式繁殖出一只新狮蚁。
(3)Starve(饥饿):假如一只狮蚁在连续3个time step中没有吃掉一只蚂蚁,在第3个time step结束之后,它会感到饥饿并死亡。该狮蚁应从网格中拿掉。
(4)在一轮中,所有狮蚁都应该先于蚂蚁移动。
3. 编写主程序来模拟“捕食者-被捕食者”游戏。
(1)使用ASCII字符“o”表示蚂蚁,“x”表示狮蚁。创建名为Organism(有机生物)的类,它封装了通用于蚂蚁和狮蚁的基本数据。该类应该有一个名为Move的virtual函数,它要在派生类Ant和Doodlebug中进行具体的定义。可能需要额外的数据结构来跟踪已移动的生物。
(2)使用5只狮蚁和100只蚂蚁初始化这个网格世界。在每个time step后,都提示用户按Enter键移动到下一个time step。应该看到狮蚁和蚂蚁数量的循环变化——虽然一些随机性的混乱可能造成一种或两种生物的毁灭。
#include "pch.h"//编译环境为Visual Studio 2017
#include
#include
#include
using namespace std;
class Organism
{
public:
Organism(int xx, int yy) :x(xx), y(yy) {}
virtual void Move() = 0;
virtual ~Organism() {}
int x, y;
int move = 0;
int time_step = 0;
};
class Ant :public Organism
{
public:
Ant(int x1 = 0, int y1 = 0) :Organism(x1, y1) {}
virtual void Move();
void Breed();
virtual ~Ant() {}
};
class Doodlebug :public Organism
{
public:
Doodlebug(int x2 = 0, int y2 = 0) :Organism(x2, y2) {}
virtual void Move();
void Breed();
int Starve();
virtual ~Doodlebug() {};
int step_conti = 0;
};
struct grid
{
Organism *p = NULL;
char flag = ' ';
};
grid a[20][20];
void rands();
void display();
void show_number(int k1, int k2);
int main()
{
int number1 = 0;
int number2 = 0;
rands();
display();
cout << "初始化已完成......" << endl;
show_number(100, 5);
cout << "请按下Enter键移动到下一个time step" << endl;
char ch = getchar();
while (ch == '\n')
{
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (a[i][j].flag == 'x'&&a[i][j].p->move == 0)
{
(a[i][j].p)->Move();
}
}
}
cout << "狮蚁的移动已完成......" << endl;
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (a[i][j].flag == 'o' && (a[i][j].p)->move == 0)
{
(a[i][j].p)->Move();
}
}
}
cout << "蚂蚁的移动已完成......" << endl;
system("cls");
display();
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (a[i][j].flag == 'o')
{
number1++; (a[i][j].p)->move = 0;
}
if (a[i][j].flag == 'x')
{
number2++; (a[i][j].p)->move = 0;
}
}
}
show_number(number1, number2);
number1 = number2 = 0;
cout << endl << "请按下Enter键移动到下一个time step" << endl;
ch = getchar();
}
return 0;
}
void Ant::Move()
{
int m;
int mark = 0;
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
while (mark == 0)
{
if ((x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ')||( x - 1 < 0 && y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ')||(x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 <0&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ')|| (x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 >= 20 &&y + 1 < 20 && a[x][y + 1].flag != ' ')|| (x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 >= 20))
{
mark = 1;
break;
}
srand(time(NULL));
m = rand() % 4;
switch (m)
{
case 0:
{
if (c1 != 0)
{
break;
}
else
{
if (x - 1 >= 0 && a[x - 1][y].flag == ' ')
{
a[x][y].flag = ' ';
x = x - 1;
a[x][y].flag = 'o';
a[x][y].p = a[x + 1][y].p;
a[x + 1][y].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c1 = 1;
break;
}
}
case 1:
{
if (c2 != 0)
{
break;
}
else
{
if (x + 1 < 20 && a[x + 1][y].flag == ' ')
{
a[x][y].flag = ' ';
x = x + 1;
a[x][y].flag = 'o';
a[x][y].p = a[x - 1][y].p;
a[x - 1][y].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c2 = 1;
break;
}
}
case 2:
{
if (c3 != 0)
{
break;
}
else
{
if (y - 1 >= 0 && a[x][y - 1].flag == ' ')
{
a[x][y].flag = ' ';
y = y - 1;
a[x][y].flag = 'o';
a[x][y].p = a[x][y + 1].p;
a[x][y + 1].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c3 = 1;
break;
}
}
case 3:
{
if (c4 != 0)
{
break;
}
else
{
if (y + 1 < 20 && a[x][y + 1].flag == ' ')
{
a[x][y].flag = ' ';
y = y + 1;
a[x][y].flag = 'o';
a[x][y].p = a[x][y - 1].p;
a[x][y - 1].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c4 = 1;
break;
}
}
}
if (c1 != 0 && c2 != 0 && c3 != 0 && c4 != 0)
mark = 1;
}
Breed();
}
void Doodlebug::Move()
{
if (x - 1 >= 0 && a[x - 1][y].flag == 'o')
{
delete a[x - 1][y].p;
a[x][y].flag = ' ';
x = x - 1;
a[x][y].flag = 'x';
a[x][y].p = a[x + 1][y].p;
a[x + 1][y].p = NULL;
time_step++;
move = 1;
step_conti = 0;
}
else if (x + 1 < 20 && a[x + 1][y].flag == 'o')
{
delete a[x + 1][y].p;
a[x][y].flag = ' ';
x = x + 1;
a[x][y].flag = 'x';
a[x][y].p = a[x - 1][y].p;
a[x - 1][y].p = NULL;
time_step++;
move = 1;
step_conti = 0;
}
else if (y - 1 >= 0 && a[x][y - 1].flag == 'o')
{
delete a[x][y - 1].p;
a[x][y].flag = ' ';
y = y - 1;
a[x][y].flag = 'x';
a[x][y].p = a[x][y + 1].p;
a[x][y + 1].p = NULL;
time_step++;
move = 1;
step_conti = 0;
}
else if (y + 1 < 20 && a[x][y + 1].flag == 'o')
{
delete a[x][y + 1].p;
a[x][y].flag = ' ';
y = y + 1;
a[x][y].flag = 'x';
a[x][y].p = a[x][y - 1].p;
a[x][y - 1].p = NULL;
time_step++;
move = 1;
step_conti = 0;
}
else
{
step_conti++;
int m;
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
int mark = 0;
while (mark == 0)
{
srand(time(NULL));
m = rand() % 4;
if ((x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ') || (x - 1 < 0 && y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ') || (x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 < 0 && x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 < 20 && a[x][y + 1].flag != ' ') || (x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 >= 20 && y + 1 < 20 && a[x][y + 1].flag != ' ') || (x - 1 >= 0 && a[x - 1][y].flag != ' ' &&y - 1 >= 0 && a[x][y - 1].flag != ' '&&x + 1 < 20 && a[x + 1][y].flag != ' '&&y + 1 >= 20))
{
mark = 1;
break;
}
switch (m)
{
case 0:
{
if (c1 != 0)
{
break;
}
else
{
if (x - 1 >= 0 && a[x - 1][y].flag == ' ')
{
a[x][y].flag = ' ';
x = x - 1;
a[x][y].flag = 'x';
a[x][y].p = a[x + 1][y].p;
a[x + 1][y].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c1 = 1;
break;
}
}
case 1:
{
if (c2 != 0)
{
break;
}
else
{
if (x + 1 < 20 && a[x + 1][y].flag == ' ')
{
a[x][y].flag = ' ';
x = x + 1;
a[x][y].flag = 'x';
a[x][y].p = a[x - 1][y].p;
a[x - 1][y].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c2 = 1;
break;
}
}
case 2:
{
if (c3 != 0)
{
break;
}
else
{
if (y - 1 >= 0 && a[x][y - 1].flag == ' ')
{
a[x][y].flag = ' ';
y = y - 1;
a[x][y].flag = 'x';
a[x][y].p = a[x][y + 1].p;
a[x][y + 1].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c3 = 1;
break;
}
}
case 3:
{
if (c4 != 0)
{
break;
}
else
{
if (y + 1 < 20 && a[x][y + 1].flag == ' ')
{
a[x][y].flag = ' ';
y = y + 1;
a[x][y].flag = 'x';
a[x][y].p = a[x][y - 1].p;
a[x][y - 1].p = NULL;
time_step++;
mark = 1;
move = 1;
}
c4 = 1;
break;
}
}
}
if (c1 != 0 && c2 != 0 && c3 != 0 && c4 != 0)
mark = 1;
}
}
if (Starve() == 0)
Breed();
}
void Ant::Breed()
{
if (time_step == 3)
{
if (x - 1 >= 0 && a[x - 1][y].flag == ' ')
{
a[x - 1][y].flag = 'o';
a[x - 1][y].p = new Ant();
a[x - 1][y].p->x = x - 1;
a[x - 1][y].p->y = y;
}
else if (x + 1 < 20 && a[x + 1][y].flag == ' ')
{
a[x + 1][y].flag = 'o';
a[x + 1][y].p = new Ant();
a[x + 1][y].p->x = x + 1;
a[x + 1][y].p->y = y;
}
else if (y - 1 >= 0 && a[x][y - 1].flag == ' ')
{
a[x][y - 1].flag = 'o';
a[x][y - 1].p = new Ant();
a[x][y - 1].p->x = x;
a[x][y - 1].p->y = y - 1;
}
else if (y + 1 < 20 && a[x][y + 1].flag == ' ')
{
a[x][y + 1].flag = 'o';
a[x][y + 1].p = new Ant();
(a[x][y + 1].p)->x = x;
(a[x][y + 1].p)->y = y + 1;
}
time_step = 0;
}
}
void Doodlebug::Breed()
{
if (time_step == 8)
{
if (x - 1 >= 0 && a[x - 1][y].flag == ' ')
{
a[x - 1][y].flag = 'x';
a[x - 1][y].p = new Doodlebug();
a[x - 1][y].p->x = x - 1;
a[x - 1][y].p->y = y;
}
else if (x + 1 < 20 && a[x + 1][y].flag == ' ')
{
a[x + 1][y].flag = 'x';
a[x + 1][y].p = new Doodlebug();
a[x + 1][y].p->x = x + 1;
a[x + 1][y].p->y = y;
}
else if (y - 1 >= 0 && a[x][y - 1].flag == ' ')
{
a[x][y - 1].flag = 'x';
a[x][y - 1].p = new Doodlebug();
a[x][y - 1].p->x = x;
a[x][y - 1].p->y = y - 1;
}
else if (y + 1 < 20 && a[x][y + 1].flag == ' ')
{
a[x][y + 1].flag = 'x';
a[x][y + 1].p = new Doodlebug();
a[x][y + 1].p->x = x;
a[x][y + 1].p->y = y + 1;
}
time_step = 0;
}
}
void del(int x, int y)
{
delete a[x][y].p;
a[x][y].p = NULL;
a[x][y].flag = ' ';
}
int Doodlebug::Starve()
{
if (step_conti == 3)
{
del(x, y);
return 1;
}
return 0;
}
void rands()
{
int x, y;
time_t t;
srand((unsigned)time(&t));
for (int i = 0; i < 5; i++)
{
x = rand() % 20;
y = rand() % 20;
if (a[x][y].flag == ' ')
{
a[x][y].flag = 'x';
a[x][y].p = new Doodlebug();
a[x][y].p->x = x;
a[x][y].p->y = y;
}
else
i--;
}
for (int i = 0; i < 100; i++)
{
x = rand() % 20;
y = rand() % 20;
if (a[x][y].flag == ' ')
{
a[x][y].flag = 'o';
a[x][y].p = new Ant();
a[x][y].p->x = x;
a[x][y].p->y = y;
}
else
i--;
}
}
void display()
{
cout << "**************************************************************" << endl;
cout << " 二维“捕食者 - 被捕食者”模拟程序" << endl;
cout << "**************************************************************" << endl;
for (int i = 0; i < 20; i++)
{
cout << "*";
for (int j = 0; j < 20; j++)
{
if (a[i][j].flag == 'x')
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
else if (a[i][j].flag == 'o')
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
}
cout << " " << a[i][j].flag << " ";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
}
cout << "*";
cout << endl;
}
cout << "**************************************************************" << endl;
}
void show_number(int k1, int k2)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
cout << "被捕食者——蚂蚁数量: " << k1 << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
cout << "捕食者 ——狮蚁数量: " << k2 << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
}