Имеется поле определённого размера, оно разбивается на равные клеточки. В каждой клеточке может либо ничего не находиться, либо лежать кучка зерна, либо сидеть мышь, либо - лиса. Причём они располагаются с определённой вероятностью, суммарная вероятность равна 1. Лиса может съесть мышь, мышь – зерно.

Мы просматриваем все клетки, в которых сидят хищники (мышь и лиса) и просматриваем окрестности этих клеток.

8 4 5

3 хищник 1

7 2 6

Если хищник видит свою жертву в клетках 1-8, то он может её съесть и вернуться обратно, тогда его жизненный тонус повысится, причём вероятность съесть жертву в клетках 1-4 больше, чем в 5-8. Клетка, в которой сидела жертва и если её съели становится пустой. Так мы просматриваем все клетки с хищниками, каждый хищник за ход может съесть только одну жертву. После того, как все пообедали, начинается второй уровень.

Происходит перемещение хищников и их еды. Количество пустых клеток, количество зерна, мышей и лис остаётся таким же, как после первого уровня. И так происходит либо до определённого количества шагов, либо пока все звери не умрут. Если хищник долго не ест, то он умирает. Причём лиса не может есть лису, мышь – мышь (даже если будут очень голодные). Вот такая вот игрушка.

Программа в итоге должна показывать, наверное, положение пустоты, зерна, мышей и лис в начале и в конце каждого уровня и график, как умирали звери.

Класс животных должен быть реализован примерно так(похожая программка)

10.5. Абстрактные базовые классы

иерархия типов обычно имеет корневой класс, содержащий некоторое число вирту-1льных функций. Виртуальные функции обеспечивают динамическую типизацию. Виртуальные функции корневого класса часто являются фиктивными функциями. Эни имеют пустое тело в корневом классе, но в производных классах им будет при-ISLH конкретный смысл. В C++ для этих целей введена чисто виртуальная функция pure virtual function). Чисто виртуальная функция — это виртуальная функция, ^ело которой не определено. Она объявляется внутри класса следующим образом:

virtual прототип_функции = 0;

^исто виртуальная функция используется для того, чтобы отложить выбор реализа¬ции функции. В терминологии ООП это называется отложенным методом (deferred nethod).

Кл'асс, имеющий хотя бы одну чисто виртуальную функцию, называется абстрак-пным классом (abstract class). Полезно, чтобы корневой тип в иерархии классов был 1бстрактным классом. Он должен иметь основные общие свойства со своими произ-юдными классами, но сам не может использоваться для объявления объектов. Вмес-'о этого он используется для объявления указателей, которые могут иметь доступ к юдобъектам, произведенным из абстрактного класса.

Объясним эти идеи, разработав упрощенный вариант экологической модели. Из-[ачально ООП разрабатывалось как методика моделирования с помощью языка мо-(елирования Simula 67. Поэтому многие концепции ООП можно воспринимать как юпытку смоделировать конкретную реальность.

Мир в нашем примере включает разные взаимодействующие формы жизни. Абст->актным базовым классом будет 1 iving (жизнь). Его интерфейс будет наследовать-я разными формами жизни. В качестве архетипического хищника у нас будет высту-[ать лиса, добычей ее будут кролики. Сами кролики питаются травой.

$ файле predator.cpp

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

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

//состояние клетки: пусто, трава, кролик, лиса //STATES — количество различных состояний (пока их 4)

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

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

clas,s 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[EMPTY] = smfGRASS] = sm[RABBIT] = sm[FOX] = 0; for (i = -1; i

for ( j = -1; j

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

}

[есь две чисто виртуальных функции и одна обычная функция-член — sums ( фтуальные функции влекут небольшие дополнительные издержки на этапе вь лнения по сравнению с обычными функциями-членами. Поэтому мы использ^

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

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

//здесь — хищник (лиса) class fox : public living { public:

fox(int r, int c, int a = 0) : age(a) { row = r; column = c; }

state who () { 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; }

state who() {return GRASS;}

10.5. Абстрактные базовые классы 295

living* next(world w); };

//здесь нет жизни (пусто) class empty : public living { public:

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

state 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 emptyfrow, 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];

296

Глава 10. Наследование

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(world w)

{

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 является контейнером для форм жизни. Контейнер отвечает за свое текущее состояние. Он должен иметь «право собственности» на объекты 1 i ving, чтобы размещать новые и уничтожать старые:

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

void init(world w)

{

int i, j;

for (i =0; i

for (j = 0; j

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

//новый мир w_new вычисляется из старого w_old void update(world w_new, world w_old)

{

int i, j;

for. (i = 1; i

for (j = 1; j

w_new[j] = w_old [j] -> next(w_old) ; }

//очистка мира void dele(world w)

{

int i , j ;

for (i = 1; i

delete(w[j]);

}

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

int main()

{

world odd, even;

int i;

init(odd); init(even);

eden(even); //генерирует начальный мир — рай

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

for (i =0; i

update(even, odd) ;

pr_state(even);

dele(odd);

}

else {

update(odd, even);

pr_state(odd); dele(even);

} .

} }

Написание функций pr_state () и eden() оставим для упражнений (см. упражне¬ние 16, на стр. 310).

17 лет назад
Oksana2001
Оксана 
36 лет
17 лет в сервисе
Был
17 лет назад

Выбранный исполнитель

Rondmeo
40 лет
18 лет в сервисе
Был
3 года назад
17 лет назад

Заявки фрилансеров

Rondmeo
40 лет
18 лет в сервисе
Был
3 года назад
17 лет назад