Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS17.DOC
Скачиваний:
44
Добавлен:
16.04.2013
Размер:
151.55 Кб
Скачать

В файле predator.Cpp

//Модель хищник–добыча с использованием класса living

const int N = 40; // размер квадратного поля

//состояние клетки: пусто, трава, кролик, трава, кролик, лиса

//STATES – количество различных состояний

enum state { EMPERTY, GRASS, RABBIT, FOX, STATES };

const int DRAB = 3, DFOX = 6; CYCLES = 5;

class living; //предварительное объявление

typedef living* world[N] [N]; //мир

class living { //что живет на свете

public:

virtual state who() = 0; //выяснение состояния (кто?)

virtual living* next(world w) = 0; //что дальше?

protected:

int row, column; //координаты поля

void sums(world w, int sm[];

};

void living::sums(world w, int sm[];

{

int i, j;

sm[EMPERTY] = sm[GRASS] = sm[RABBIT]= sm[FOX] = 0;

for ( i =-1; i<= 1; ++i)

for ( j =-1; j<= 1; ++j)

sm[w[row + i][column +j] -> who() ++;

}

Здесь две чисто виртуальных функции и одна обычная функция-член – sums(). Виртуальные функции влекут небольшие дополнительные издержки на этапе выполнения по сравнению с обычными функциями-членами. Поэтому мы используем их в наших реализациях, только когда это необходимо. В модели предусмотрены правила для определения того, кто продолжит существование в следующем цикле, в зависимости от популяций по соседству с заданным квадратом. Эти популяции вычисляются с помощью sums().Все напоминает «Жизнь» Конвея.

Иерархия наследования будет одноуровневой:

//здесь – хищник(лиса)

class fox : public living {

public:

fox(int r, int c, int a = 0) : age(a)

{ row = r; column = c; }

state whj() { return FOX; } //отложенный метод для лис

living* next(world w);

protected:

int age; //возраст

};

//здесь – добыча (кролик)

class rabbit : public living {

public:

rabbit(int r, int c, int a = 0) : age(a)

{ row = r; column = c; }

state who() { return RABBIT; }

living* next(world w);

protected:

int age;

};

//здесь – растительная жизнь (трава)

class grass : public living {

public:

grass(int r, int c) { row = r; column = c; }

syate who() {return GRASS;}

living* next(world w);

};

//здесь нет жизни (пусто)

class empty : public living {

public:

empty (int r, int c) { row = r; column = c; }

syate who() {return EMPTY;}

living* next(world w);

};

Обратите внимание, что данная схема позволяет с помощью последующих уровней наследования разрабатывать другие формы хищников, добычи и растительной жизни. Характеристики того, как каждая форма жизни будет себя вести, сосредоточены в принадлежащей ей next().

Трава может поедаться кроликами. Если на соседних квадратах травы больше, чем кроликов, трава останется, в противном случае ее съедают (можете заменить это правило своими собственными, поскольку оно уж слишком ограниченно и искусственно):

living* grass::next(world w);

{

int sum[STATES];

sums(w,sum);

if (sum[GRASS] > sum[RABBIT]) //едим траву

return (new grass(row, column));

else

return (new empty(row, column));

}

Кролики умирают от старости, если их возраст превышает некий определенный предел DRAB, или их съедают, если по соседству имеется достаточное количество лис.

living* rabbit::next(world w);

{

int sum[STATES];

sums(w,sum);

if (sum[FOX] >= sum[RABBIT] ) //едим кроликов

return (new empty(row, column));

else if (age > DRAB)

return (new empty(row, column));

else

return (new rabbit(row, column, age + 1));

}

Лисы же умирают от перенаселения или от старости:

living* fox::next(world w);

{

int sum[STATES];

sums (w, sum);

if (sum [FOX] >5) // ну и лис развелось!

return (new empty (row, column));

else if (age > DFOX) // лиса состарилась

return (new empty (row, column));

else

return (new fox( row, column, age = 1));

}

За пустые квадраты конкурируют разные формы жизни:

//как заполнить пустой квадрат

living* empty::next( word w0

[

int sum [STATES];

sums(w, sum);

if (sum[FOX] >1)

return (new fox(row, column));

else if (sum[RABBIT] >1)

return (new rabbit(row, column));

else if (sum[GRASS])

return (new grass(row, column));

else

return (new empty(row, column));

}

Правила в различных версиях next() задают сложный вариант (в разумных пределах) набор взаимодействий. Конечно, чтобы сделать мир более интересным, можно смоделировать другие варианты поведения, такие как половое размножение, когда животные имеют пол и могут спариваться.

Тип массива world является контейнером для жизни. Контейнер отвечает за свое текущее состояние. Он должен иметь «право собственности» на объекты living, чтобы размещать новые и уничтожать старые:

// начало: мир пуст

void invit (word w)

{

int I, j;

for (I = 0; I<N; ++i)

for (j = 0; j<N; ++i)

w[I][j] = new empty (i,j);

}

//новый мир w_new вычисляется из старого w_old

void update(world w_new, world_old)

{

int i, j;

for (i = 1; i<N – 1; ++i) //за границы нельзя

for (j = 1; j<N – 1; ++j)

w-new [i][j] -> next(w_old);

}

// очистка мира

void dele(word w0

[

int i, j;

for (i=1; I<N – 1; ++i)

for (j = 1; j<N – 1; ++j)

delete(w([i][j]);

}

Модель имеет миры even и odd (четный и нечетный), которые чередуются в качестве базиса для вычислений следующего цикла:

Int main()

{

world odd, even;

int i;

init(odd); init(even);

even(even): //генерирует начальный мир – рай

pr_state(even); //выводит состояние райского сада

for (i = 0; i<CYCLES; ++I) { //моделирование

if (I % 2) {

update(even, odd);

pr_state9even);

dele(odd);

}

else {

update9odd, even);

pr_state(odd);

dele9even);

}

}

}

Соседние файлы в папке Лекции