Скачиваний:
8
Добавлен:
01.05.2014
Размер:
140.8 Кб
Скачать

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ

САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ ЭЛЕКТРОТЕХНИЧЕСКИЙ

УНИВЕРСИТЕТ «ЛЭТИ»

Кафедра МОЭВМ

ОТЧЕТ

по дисциплине «Логическое программирование»

по лабораторным работам №1 – 3

Выполнили:

Азаров А. С. Петров А. Г.

Группа

2304

Руководитель:

Беляев С. А.

Санкт-Петербург

2005

ПОСТАНОВКА ЗАДАЧИ

  1. Описать объектов, имеющий свойства и действия (атрибуты и методы).

  2. Реализовать «жизнь» объекта: ввести приоритеты, в соответствии с которыми он «выбирает», какой атрибут предпочтительнее изменить.

  3. Реализовать «эффект толпы»: в «толпе» отдельный объект может сменить свой приоритет в соответствии с приоритетами других объектов.

ОПИСАНИЕ ОБЪЕКТА

Объектом является гном.

Свойства гномов:

  1. Идентификатор (уникальный номер объекта).

  2. Список характера, в который входят свойства: 1) Лидерство (чем больше значение этого свойства, тем меньше влияние толпы) 2) Везение (увеличение всех положительных вероятностей) 3) Моральные качества (чем больше значение этого свойства, тем меньше вероятность совершения гномом поступков с низкой моральной оценкой).

  3. Список состояний, содержащий: 1) Энергия; 2) Деньги; 3) Счастье; 4) Сытость; 5) Здоровье.

  4. Место, в котором гном в данный момент находится (дом, бар, шахта).

Метод создания гномов.

Объект создаётся методом add_new_gnom /1 с параметром, в котором возвращается идентификатор создаваемого объекта.

Методы воздействия на гнома.

  1. update_gnom(P_ID, P_PLACE, P_L_C, P_L_S) Метод, задающий новые значения для всех атрибутов гнома.

  2. gnom_move(P_ID, P_DEST_PLACE) Метод, моделирующий перемещение гнома из одного места в другое. При выполнении этого метода рассчитывается и отнимается количество энергии, необходимое на переход из места, в котором гном находится в данный момент в место назначения.

  3. execute_gnom_cycle_des(P_ID) Метод, отвечающий за выполнение намеченного действия для гнома с идентификатором P_ID. В ходе выполнения этого метода рассчитывается вероятность выполнения действия (за счёт сравнения свойства гнома «везение» с вычисляемым произвольно шансом выполнения действия); если действие можно выполнить, оно выполняется. После «выполнения» действия вызывается метод update_gnom, который и приводит к изменениям свойств объекта.

ВЫБОР ДЕЙСТВИЯ

Действия намечаются на каждом шаге жизненного цикла гномов (для всех гномов) в зависимости от мест, в которых гномы находятся, их характеров и потребностей.

Алгоритм выбора действия:

  1. Заполнение массива потребностей всех гномов.

  2. Заполнение массива принятых решений на основе массива потребностей (для всех гномов).

  3. Вычисление эффекта толпы для всех гномов.

//Этот алгоритм реализован в предикате calc_cycle.

Потребности гномов вычисляются следующим образом:

(цикл для каждого свойства состояния гнома)

  1. В массиве состояний ищется данное свойство состояния.

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

//Этот алгоритм реализован в предикате fill_gnoms_cycle_demands.

Алгоритм принятия решения:

  1. Поиск возможностей.

  2. Получение ранее построенного массива потребностей.

  3. «Вычисление» действия для текущего шага жизненного цикла: 1) Вычисление произвольной потребности с учетом ее веса; 2) Поиск действия (по свойству состояния) с лучшим исходом; 3) Проверка выбранного действия (если не нашлось действия, которое можно выполнить на основании текущей потребности, запуск «вычисления» действия по другому критерию).

//Этот алгоритм реализован в предикате fill_gnoms_cycle_des.

Описание контекста вохможностей:

Каждое дествие требует некоторых затрат, все затраты описываются списком из 12 элементов:

  1. Первый элемент – вероятность положительного исхода;

  2. Второй элемент – оценка нравственности (от 0 до 10);

  3. Остальные 10 – по 2 на каждое свойство гнома – описаны в следующей последовательности: энергия, деньги, счастье, еда, здоровье, где первый элемент – эффект при отрицательном исходе, а второй – при положительном.

//Это описание реализовано в системе предикатов map_places_abilities/3, где //первым параметром является место, в котором возможно данное действие, //вторым – список контекста возможности, описанный выше //и третьим – описание действия.

МОДЕЛИРОВАНИЕ ПОВЕДЕНИЯ В «ТОЛПЕ»

«Толпа» есть совокупность нескольких гномов. При создании гнома его идентификатор заносится в массив гномов, возвращаемый предикатом array_gnoms.

Алгоритм вычисления «эффекта толпы» для гнома:

(цикл для каждого гнома)

  1. Сравнение данного гнома с гномом, выбираемым из списка гномов: в случае совпадения, эффект не рассчитывается, т.к. гном не может повлиять сам на себя.

  2. Сравнение места данного гнома с местом, в котором находится гном из списка: в случае несовпадения эффект также не рассчитывается, т.к. гномы, удалённые друг от друга друг на друга, соответственно, не влияют.

  3. Сравнение свойств характеров гномов «лидерство». Если лидерство данного гнома больше, то он может повлиять на гнома из списка описанным далее образом. Из списка потребностей гнома-лидера (данного гнома) выбирается потребность с наибольшим значением. Та же потребность выбирается из списка потребностей гнома, «находящегося под влиянием», и её увеличивается на разницу в «лидерстве» двух рассматриваемых гномов (т.е. чем меньше «лидерство» гнома из списка по сравнению с данным гномом, тем больше будет на него влияние), умноженную на коэффициент эффекта толпы, возвращаемый предикатом crowd_effect_mult.

//Этот алгоритм реализован в предикате сalc_gnom_cycle_crowd_effect.

ТЕКСТ ПРОГРАММЫ

%Общие функции

%Логическое не

not(X):- ;(->(X, fail), true).

%Произвольное число от 0 до 100

get_random100(X) :- random(0, 101, X).

%Произвольное число от 0 до MAX

get_random(MAX, X) :- N_MAX is MAX + 1, random(0, N_MAX, X).

% Количество элементов в списке

list_len([], 0).

list_len([_|T], N):- !, list_len(T, M), N is M + 1.

list_compare([], []).

list_compare([P_LH1 | P_LT1], [P_LH2 | P_LT2]) :-

!, P_LH1 = P_LH2, list_compare(P_LT1, P_LT2).

%проверка листа на наличие элемента

list_check(P_ELEM, [P_L_H | P_L_T]) :- P_ELEM = P_L_H, !; list_check(P_ELEM, P_L_T).

add_element(P_ELEM, P_LT, [R_LH | R_LT]) :- !,

R_LH = P_ELEM, list_compare(R_LT, P_LT).

get_element(P_NUM, P_LIST, R_ELEM) :- get_element(P_NUM, P_LIST, R_ELEM, 0).

get_element(_, [], _, _).

get_element(P_NUM, [P_LIST_H | P_LIST_T], R_ELEM, P_CUR) :-

P_CUR = P_NUM, R_ELEM = P_LIST_H, !; N_CUR is P_CUR + 1, get_element(P_NUM, P_LIST_T, R_ELEM, N_CUR).

set_element(_, _, [], [], _).

set_element(P_NUM, P_ELEMENT, [P_LIST_H | P_LIST_T] , [R_LIST_H | R_LIST_T], P_CUR) :-

P_NUM = P_CUR,! , R_LIST_H = P_ELEMENT, R_LIST_T = P_LIST_T

;

!, N_NUM is P_CUR + 1, R_LIST_H = P_LIST_H, set_element(P_NUM, P_ELEMENT, P_LIST_T, R_LIST_T, N_NUM).

set_element(P_NUM, P_ELEMENT, P_LIST, R_LIST) :- !,

set_element(P_NUM, P_ELEMENT, P_LIST, R_LIST, 0).

list_write([]).

list_write([P_LIST_H | P_LIST_T]) :- !, write(P_LIST_H), list_write(P_LIST_T).

get_first_sub_list(0, _, []).

%Первые P_LEN элементов списка

get_first_sub_list(P_LEN, [P_L_H | P_L_T], [R_L_H | R_L_T]) :- !,

R_L_H = P_L_H, N_LEN is P_LEN - 1, get_first_sub_list(N_LEN, P_L_T, R_L_T).

get_list_sub_list(P_START, P_LEN, [_ | P_L_T], R_L, P_CUR) :-

P_CUR = P_START, !, N_CUR is P_CUR + 1, get_first_sub_list(P_LEN, P_L_T, R_L)

;

!, P_CUR < P_START, N_CUR is P_CUR + 1, get_list_sub_list(P_START, P_LEN, P_L_T, R_L, N_CUR).

%P_LEN элементов списка начиная с P_START

get_list_sub_list(P_START, P_LEN, P_L, R_L) :-

P_START = 0, !, get_first_sub_list(P_LEN, P_L, R_L)

;

!, get_list_sub_list(P_START, P_LEN, P_L, R_L, 1).

%удаление элемента по значению

remove_element(P_NUMBER, [P_L_H | P_L_T], R_L) :-

P_NUMBER = 0, !, R_L = P_L_T

;

!, N_NUMBER is P_NUMBER - 1, remove_element(N_NUMBER, P_L_T, N_L), R_L = [P_L_H | N_L].

remove_element(_, [], []).

%максимальное значение в листе

list_max([P_L_H | P_L_T], R_MAX) :- !, list_max(P_L_T, P_L_H, R_MAX).

list_max([], P_MAX, R_MAX) :- R_MAX is P_MAX.

list_max([P_L_H | P_L_T], P_MAX, R_MAX) :-

P_L_H > P_MAX,!, N_MAX is P_L_H, list_max(P_L_T, N_MAX, R_MAX)

;

list_max(P_L_T, P_MAX, R_MAX).

%номер максимального элемента

list_max_element([P_L_H | P_L_T], R_MAX_NUMBER) :- !,

list_max_element(P_L_T, 1, 0, P_L_H, R_MAX_NUMBER).

list_max_element([], _, P_MAX_ELEMENT, _, R_MAX_NUMBER) :- R_MAX_NUMBER = P_MAX_ELEMENT.

list_max_element([P_L_H | P_L_T], P_CUR, P_MAX_ELEMENT, P_MAX, R_MAX_NUMBER) :-

P_MAX < P_L_H, !, N_CUR is P_CUR + 1, list_max_element(P_L_T, N_CUR, P_CUR, P_L_H, R_MAX_NUMBER)

;

!, N_CUR is P_CUR + 1, list_max_element(P_L_T, N_CUR, P_MAX_ELEMENT, P_MAX, R_MAX_NUMBER).

%Сумма всех элементов

list_sum([], 0).

list_sum([L_H | L_T], R_V) :-

list_sum(L_T, V), nonvar(L_H), !, R_V is V + L_H

;

list_sum(L_T, V), var(L_H), !, R_V is V.

%вычисление произвольного номера с учетом веса

random_list_number_by_part(P_L, P_NUM) :- !, list_sum(P_L, SUM), get_random(SUM, RND), random_list_number_by_part(P_L, RND, 0, 0, P_NUM).

random_list_number_by_part([P_L_H | P_L_T], P_MAX_SUM, P_CUR_SUM, P_CUR_NUM, P_NUM) :-

N_CUR_SUM is P_CUR_SUM + P_L_H, N_CUR_SUM >= P_MAX_SUM, P_CUR_SUM =< P_MAX_SUM , P_NUM = P_CUR_NUM, !

;

N_CUR_NUM is P_CUR_NUM + 1, N_CUR_SUM is P_CUR_SUM + P_L_H, !, random_list_number_by_part(P_L_T, P_MAX_SUM, N_CUR_SUM, N_CUR_NUM, P_NUM).

%Метонахождения

%Описание всех место

map_places(house, 'Houses').

map_places(bar, 'Tavern').

map_places(mine, 'Mine').

map_places(nothing, 'Nothing').

%Длина пути между местами

map_places_route(house, bar, 2).

map_places_route(house, mine, 4).

map_places_route(bar, mine, 4).

map_places_route(bar, house, 2).

map_places_route(mine, bar, 3).

map_places_route(mine, house, 3).

%Описание контекста вохможности

%Каждое дествие требует некоторых затрат, все затраты описываются списком из 12 элементов

%Первый элемент - вероятность положительного исхода

%Следующий элемент - оценка нравственности (на работу ходить хорошо, пить в баре плохо)

%Остальные 10 - по 2 на каждое свойство гнома - описаны в следующей последовательности:

%[энергия, деньги, счастье, еда, здоровье], где

%Первый элемент - эффект при отрицательном исходе,

%Второй элемент - эффект при положительном исходе.

%смещение статусов в описаний мест

map_places_abilities_status_offset(2).

map_places_abilities_status_len(2).

map_places_abilities_morale_offset(1).

map_places_abilities_luck_end_offset(0).

%Описание возможностей для мест вер. нр. энергия денг. счаст. еда. здрв.

map_places_abilities(house, [90, 10, 10, 30, -1, -1, 5, 20, -10, -10, 0, 10 ], 'Sleep at home').

map_places_abilities(house, [50, 10, -1, 10, -5, -5, -2, 10, 4, 15, 0, 5 ], 'Eat from supermarket').

map_places_abilities(house, [60, 5 , -1, 0, -5, -5, -2, 30, -1, -1, -1, -5 ], 'Drink alcohol from supermarket').

map_places_abilities(house, [60, 10, -20, -20, -10, -10, 10, 50, 5, 5, 0, 0 ], 'Met Girlfriend').

map_places_abilities(house, [30, 0, -20, -20, 2, 20, -10, 0, -5, -5, -20, 0 ], 'Steal money').

map_places_abilities(bar, [50, 4 , 5, 20, 0, 0, -2, 10, -15, -15, -1, -1 ], 'Sleep in bar').

map_places_abilities(bar, [90, 8 , 0, 10, -10, -10, 0, 5, 10, 30, 0, 10 ], 'Eat complex lunch').

map_places_abilities(bar, [90, 5 , 5, 5, -10, -10, 10, 20, -1, 5, -5, -5 ], 'Drink beer').

map_places_abilities(bar, [90, 3 , -5, -5, -10, -10, 10, 30, -2, 0, -10, -10 ], 'Drink vodra').

map_places_abilities(bar, [30, 5 , 0, 0, -5, 20, -2, 5, -1, -1, -1, -1 ], 'Play cards').

map_places_abilities(bar, [90, 2 , -5, -5, -30, -30, 10, 50, -1, -1, -1, -1 ], 'Take woman').

map_places_abilities(bar, [50, 1, -25, -25, 1, 30, -10, 10, -10, -10, -40, 0 ], 'Steal money').

map_places_abilities(mine, [90, 10, -50, -50, 25, 30, -10, -5, -10, -15, -30, -30 ], 'Work in mine').

map_places_abilities(mine, [40, 6, 10, 15, 0, 0, 0, 5, -10, -10, -1, -1 ], 'Sleep in mine').

%Действие "ничего не делать"

map_places_nothing_ability(nothing, [100, 5, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1 ], 'Do nothing').

get_all_places(R) :- R = [house, mine, bar].

get_all_place_abilities(R_ABILITIES) :- findall([X, Y, Z], map_places_abilities(X, Y, Z), R_ABILITIES).

get_place_luck_end([_, P_PLACE_CONTEXT, _], R) :-

map_places_abilities_luck_end_offset(OFFSET), get_element(OFFSET, P_PLACE_CONTEXT, R).

%Гномы

%сиквенс идентификаторов

dynamic(gnom_id_seq, 1).

get_next_gnom_id(X) :- gnom_id_seq(X), Y is X + 1, retract(gnom_id_seq(_)), assertz(gnom_id_seq(Y)).

%объект гнома, имеет три свойства: идентификатор, список характера, список состояний

% + место, где гном находится

%Характер: лидерство (чем больше, тем меньше влияние толпы), везение (увеличение всех положительных вероятностей).

dynamic(gnom, 4).

%контейнер всех идентификаторов объектов гномов.

dynamic(array_gnoms, 1).

%add_new_gnom(ListSet, ListStatus) :- get_next_gnom_id.

%Работа с характеристиками

%Генерация произвольных характеристик

gen_gnom_charact([LeaderShip , Luck , Moral]) :-

get_random(10, LS), LeaderShip is LS, get_random(20, LU), Luck is LU - 10, get_random(10, M), Moral is M + 3.

%Генерация стандартного состояния

gen_gnom_status([Energ , Money , Happy , Eat , Health]) :-

Energ is 80, Money is 30, Happy is 40, Eat is 100, Health is 100.

%Добавление нового гнома

add_new_gnom(R_ID) :-

get_next_gnom_id(R_ID), gen_gnom_charact(C), gen_gnom_status(S), assertz(gnom(R_ID, house, C, S)), add_gnom_id(R_ID).

add_gnom_id(P_ID) :-

array_gnoms(GLIST), retract(array_gnoms(_)), add_element(P_ID, GLIST, N_G_LIST), assertz(array_gnoms(N_G_LIST)).

update_gnom(P_ID, P_PLACE, P_L_C, P_L_S) :- retract(gnom(P_ID, _, _, _)), assertz(gnom(P_ID, P_PLACE, P_L_C, P_L_S)), !.

%Передвижения

%идти на место

gnom_move(P_ID, P_DEST_PLACE) :-

P_DEST_PLACE = nothing, true

;

gnom(P_ID, PLACE, _, _),

PLACE = P_DEST_PLACE

;

gnom(P_ID, PLACE, L_C, L_S),

map_places_route(PLACE, P_DEST_PLACE, LEN),

update_gnom(P_ID, P_DEST_PLACE, L_C, L_S), gnom_move_energy_lost(P_ID, LEN).

%логика изменения состония

%массив посчитаных дейтсвий для каждого гнома

dynamic(gnoms_cycle_demands, 2).

%массив принятого решения для каждого гнома

dynamic(gnoms_cycle_des, 3).

%формирование первичных потребностей всех гномов

build_status_demand(P_TYPE, P_STATUSES, R_DEMAND) :-

get_status_value(P_TYPE, P_STATUSES, V),

standard_status(P_TYPE, STANDARD_VALUE),

STANDARD_VALUE < V, !,

status_prior(P_TYPE, SP),

success_status_prior(P),

R_DEMAND is P * SP, true

;

get_status_value(P_TYPE, P_STATUSES, V),

standard_status(P_TYPE, STANDARD_VALUE),

critical_status(P_TYPE, CRITICAL_VALUE),

STANDARD_VALUE >= V, CRITICAL_VALUE < V, !,

status_prior(P_TYPE, SP),

standard_status_prior(P),

R_DEMAND is (STANDARD_VALUE - V + 1) * P * SP, true

;

get_status_value(P_TYPE, P_STATUSES, V),

critical_status(P_TYPE, CRITICAL_VALUE),

CRITICAL_VALUE >= V, !,

status_prior(P_TYPE, SP),

critical_status_prior(P),

R_DEMAND is (CRITICAL_VALUE - V + 1) * P * SP, true.

fill_demands_lists([], _, _, _).

fill_demands_lists([P_L_STATUSTYPE_H | P_L_STATUSTYPE_T], P_STATUSES, [R_L_DEMAND_H | R_L_DEMAND_T], NUM) :-

build_status_demand(P_L_STATUSTYPE_H, P_STATUSES, R_L_DEMAND_H), NNUM is NUM + 1, fill_demands_lists(P_L_STATUSTYPE_T, P_STATUSES, R_L_DEMAND_T, NNUM).

build_gnom_cycle_demans(P_ID) :-

gnom(P_ID, _, _, L_S), get_all_statuses(L_STATUS_TYPES),

fill_demands_lists(L_STATUS_TYPES, L_S, DEMANDS, 0),

assertz(gnoms_cycle_demands(P_ID, DEMANDS)).

clear_gnoms_cycle_demands :-

->( clause(gnoms_cycle_demands(_, _), true), (retract(gnoms_cycle_demands(_, _) ),

clear_gnoms_cycle_demands)); true.

fill_gnoms_cycle_demands([]).

fill_gnoms_cycle_demands([H | T]) :- build_gnom_cycle_demans(H), fill_gnoms_cycle_demands(T).

fill_gnoms_cycle_demands :- clear_gnoms_cycle_demands, array_gnoms(X), fill_gnoms_cycle_demands(X).

%%

%затрата энергии на путь

gnom_move_energy_lost(P_ID, P_LEN) :-

gnom(P_ID, PLACE, L_C, L_S),

ENERG_LOST is P_LEN * (-2),

update_status_value(energy, L_S, ENERG_LOST, NL_S),

update_gnom(P_ID, PLACE, L_C, NL_S).

%Номера ячеек состояний в листе

status_list_cell(energy, 0).

status_list_cell(money, 1).

status_list_cell(happy, 2).

status_list_cell(eat, 3).

status_list_cell(health, 4).

%Номера ячеек характеристик в листе

charact_list_cell(leader, 0).

charact_list_cell(luck, 1).

charact_list_cell(moral, 2).

%окрестность нравстености. Гном может делать вещи которые будут от Morale - Len до Morale + Len.

%Т.о. гном с низкими моральными принципами будет зарабатывать деньги, играя в карты и грабя, и не может работать в шахте.

%С высокими мормальными принципами не может играть в карты и пить крепкое спиртное.

charact_moral_ability_len(5).

%взять значение состояния

get_status_value(TYPE, P_LIST, R) :- status_list_cell(TYPE, NUM), get_element(NUM, P_LIST, R).

%взять значение характеристики

get_charact_value(TYPE, P_LIST, R) :- charact_list_cell(TYPE, NUM), get_element(NUM, P_LIST, R).

%изменить (увеличить) значение состояния на P_MOD_VALUE

update_status_value(TYPE, P_LIST, P_MOD_VALUE, R_LIST) :-

status_list_cell(TYPE, NUM), get_element(NUM, P_LIST, V), NV is V + P_MOD_VALUE, set_element(NUM, NV, P_LIST, R_LIST).

%названия статусов

status_name(energy, 'energy').

status_name(money, 'money').

status_name(happy, 'happy').

status_name(eat, 'eat').

status_name(health, 'health').

status_name(nothing, 'nothing').

%стандартные нормы состояний (к ним стремятся гномы)

standard_status(energy, 100).

standard_status(money, 100).

standard_status(happy, 100).

standard_status(eat, 100).

standard_status(health, 100).

%критические нормы состояний

critical_status(energy, 5).

critical_status(money, 0).

critical_status(happy, 5).

critical_status(eat, 5).

critical_status(health, 20).

%приоритеты важности (чем больше, тем важнее)

status_prior(energy, 3).

status_prior(money, 1).

status_prior(happy, 2).

status_prior(eat, 4).

status_prior(health, 5).

critical_status_prior(3).

standard_status_prior(2).

success_status_prior(1).

%коэффициент эффекта толпы

crowd_effect_mult(20).

%массив всех состояний

get_all_statuses(X) :- X = [energy, money, happy, eat, health].

%get_all_statuses(X) :- X = [energy].

clear_gnoms_cycle_des :-

->( clause(gnoms_cycle_des(_, _, _), true), (retract(gnoms_cycle_des(_, _, _) ),

clear_gnoms_cycle_des)); true.

%заполнение массива действий для гномов на цикл

fill_gnoms_cycle_des :- clear_gnoms_cycle_des, array_gnoms(X), !, fill_gnoms_cycle_des(X).

fill_gnoms_cycle_des([]).

%Цикл заполнения массива действий для гномов с ID = P_L_H на цикл

fill_gnoms_cycle_des([P_L_H | P_L_T]) :- build_gnom_cycle_des(P_L_H),!, fill_gnoms_cycle_des(P_L_T).

%процедура заполнения действия на текущий цикл для гнома

build_gnom_cycle_des(P_ID) :-

build_available_abilities(P_ID, L_AVAIL_ABILIT), !,

gnoms_cycle_demands(P_ID, DEMANDS), !,

calculate_des(DEMANDS, L_AVAIL_ABILIT, DES, P_DEMAND), !,

%list_write(['ID = ', P_ID, ' Действие = ', DES]), nl,

assertz(gnoms_cycle_des(P_ID, DES, P_DEMAND))

;

write('oblom =(').

%вывести все возможные действия

write_abilities(P_ID, P_L_ABILIT) :-

list_len(P_L_ABILIT, X), X > 0,

list_write(['ID = ', P_ID, ' Действия: ']) , nl, write_abilities(P_L_ABILIT)

;

list_write(['ID = ', P_ID, ' Действий нету ']), nl.

write_abilities([]).

write_abilities([P_L_H | P_L_T]) :- list_write(P_L_H), nl, write_abilities(P_L_T).

%Вычисление действия для цикла

calculate_des(P_L_DEMAND, P_L_AVAIL, R_DES, R_DEMAND) :-

list_sum(P_L_DEMAND, SUM), SUM = 0, !, map_places_nothing_ability(PLACE, CONTEXT, NAME),

R_DES = [PLACE , CONTEXT , NAME], R_DEMAND = nothing

;

!, pop_random_status(P_L_DEMAND, STATUS_DEMAND, N_L_DEMAND), !,

find_best_ability_by_status(P_L_AVAIL, STATUS_DEMAND, N_DES),

check_calculated_des(N_L_DEMAND, P_L_AVAIL, N_DES, STATUS_DEMAND, R_DES, R_DEMAND).

%проверка посчитанного действия: если ничего не нашлось, то ищем по другому критерию

%(так как придыдущий критерий равен 0)

check_calculated_des(P_L_DEMAND, P_L_AVAIL, P_DES, P_DEMAND, R_DES, R_DEMAND) :-

P_DES = [], calculate_des(P_L_DEMAND, P_L_AVAIL, R_DES, R_DEMAND)

;

R_DES = P_DES, R_DEMAND = P_DEMAND.

%вычисляет произвольную потребность с учетом ее веса, возвращает и делает ее приоритет 0 в списке

pop_random_status(P_L, R_V, R_L) :- random_list_number_by_part(P_L, NUM),

status_list_cell(R_V, NUM), set_element(NUM, 0, P_L, R_L).

%%%%%%%%находит действие по критерию с лучшим исходом

find_best_ability_by_status(P_L_ABILITIES, P_STATUS, R_ABILITY) :-

find_best_ability_by_status(P_L_ABILITIES, P_STATUS, [], R_ABILITY, 0 ).

%Если возможных действий нет

find_best_ability_by_status([], _, _, R_ABILIRY, 0) :- R_ABILIRY = [].

%Дошли до конца списка

find_best_ability_by_status([], P_STATUS, P_ABILITY, R_ABILIRY, _) :-

get_places_status_values(P_STATUS, P_ABILITY, L_MAX_VALUES),

list_max(L_MAX_VALUES, MAX_VALUE),

MAX_VALUE > 0,

R_ABILIRY = P_ABILITY

;

R_ABILIRY = [].

find_best_ability_by_status([P_L_ABILITIES_H | P_L_ABILITIES_T], P_STATUS, P_ABILITY, R_ABILITY, P_DEEP) :-

P_DEEP = 0, !, N_ABILITY = P_L_ABILITIES_H, find_best_ability_by_status(P_L_ABILITIES_T, P_STATUS, N_ABILITY, R_ABILITY, 1)

;

get_places_status_values(P_STATUS, P_L_ABILITIES_H, L_VALUES),

get_places_status_values(P_STATUS, P_ABILITY, L_MAX_VALUES),

list_max(L_VALUES, VALUE),

list_max(L_MAX_VALUES, MAX_VALUE),

MAX_VALUE < VALUE, !,

% nl,nl, list_write(['demand = ', P_STATUS]), nl, list_write([L_VALUES, P_L_ABILITIES_H]), list_write([' max=', VALUE]), nl, list_write([L_MAX_VALUES, P_ABILITY]), list_write([' max=', MAX_VALUE]), nl, nl,

N_ABILITY = P_L_ABILITIES_H, N_DEEP is P_DEEP + 1, !,

find_best_ability_by_status(P_L_ABILITIES_T, P_STATUS, N_ABILITY, R_ABILITY, N_DEEP)

;

N_ABILITY = P_ABILITY, N_DEEP is P_DEEP + 1, !,

find_best_ability_by_status(P_L_ABILITIES_T, P_STATUS, N_ABILITY, R_ABILITY, N_DEEP).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%Выполнение намеченных действий для гономов

execute_gnoms_cycle_des :- print_gnoms_des_execution_caption, !, array_gnoms(L_GNOMS), !, execute_gnoms_cycle_des(L_GNOMS).

execute_gnoms_cycle_des([]).

execute_gnoms_cycle_des([L_H | L_T]) :- execute_gnoms_cycle_des(L_T), !, execute_gnom_cycle_des(L_H).

execute_gnom_cycle_des(P_ID) :-

gnoms_cycle_des(P_ID, DES, DEMAND), get_place_luck_end(DES, ABILIT_LUCK_END),

gnom(P_ID, GNOM_PLACE, GNOM_CHARACT, GNOM_STATUS),

get_charact_value(luck, GNOM_CHARACT, GNOM_LUCK),

DES_LUCK is ABILIT_LUCK_END + GNOM_LUCK, get_random100(RND), !,

execute_gnom_cycle_des(P_ID, DES_LUCK, RND, DES, DEMAND, GNOM_STATUS, N_GNOM_STATUS),

update_gnom(P_ID, GNOM_PLACE, GNOM_CHARACT, N_GNOM_STATUS),

[ABILIT_PLACE, _, _] = DES, !, gnom_move(P_ID, ABILIT_PLACE).

execute_gnom_cycle_des(P_ID, P_CUR_LUCK, P_LUCK_RES, P_ABILITY, P_DEMAND, P_STATUS, R_STATUS) :-

P_CUR_LUCK >= P_LUCK_RES, !, get_all_statuses(L_STATUSES),

apply_ability_to_gnom_status(L_STATUSES, 1, P_ABILITY, P_STATUS, R_STATUS),

print_gnom_des_execution(P_ID, P_ABILITY, P_DEMAND, true)

;

get_all_statuses(L_STATUSES),

apply_ability_to_gnom_status(L_STATUSES, 0, P_ABILITY, P_STATUS, R_STATUS),

print_gnom_des_execution(P_ID, P_ABILITY, P_DEMAND, false).

%вывод действия и его результата

print_gnom_des_execution(P_ID, P_ABILITY, P_DEMAND, P_RESULT) :-

show_gnoms_cycle_des_execution(true), !, nl, [PLACE, _, ACTION_NAME] = P_ABILITY, map_places(PLACE, PLACE_NAME), status_name(P_DEMAND, DEMAND_NAME), list_write(['ID = ', P_ID, '; demand: ', DEMAND_NAME, '; place: ', PLACE_NAME, '; action: ', ACTION_NAME ,'; result: ', P_RESULT]),

;((show_gnoms_cycle_des_execution_advanced(true), list_write([' ', ' Details: ' , P_ABILITY])), true)

;

true.

%вывод заголовка для вывода действий

print_gnoms_des_execution_caption :-

show_gnoms_cycle_des_execution(true), !, nl, write('Actions: ')

;

true.

apply_ability_to_gnom_status([], _, _, P_STATUS, R_STATUS) :- R_STATUS = P_STATUS.

apply_ability_to_gnom_status([L_STATUS_H | L_STATUS_T], P_OFFSET, P_ABILITY, P_STATUS, R_STATUS) :-

get_places_status_values(L_STATUS_H, P_ABILITY, L_VALUES),

get_element(P_OFFSET, L_VALUES, P_STATUS_MOD_VALUE),

update_status_value(L_STATUS_H, P_STATUS, P_STATUS_MOD_VALUE, N_STATUS),

apply_ability_to_gnom_status(L_STATUS_T, P_OFFSET, P_ABILITY, N_STATUS, R_STATUS).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%взять массив всех возможных действий

build_available_abilities(P_ID, R_L_ABILIT) :- get_all_place_abilities(PLACES_ABILITIES), !, fill_all_available_abilities(P_ID, PLACES_ABILITIES, R_L_ABILIT).

%%%%%%%%% Заполняет массив всех доступных действий

fill_all_available_abilities(_, [], _).

fill_all_available_abilities(P_ID, P_L_PLACES_ABILIT, R_AVAILABLE) :-

fill_all_available_abilities(P_ID, P_L_PLACES_ABILIT, [], R_AVAILABLE).

fill_all_available_abilities(_, [], P_AVAIL, R_AVAIL) :- R_AVAIL = P_AVAIL.

fill_all_available_abilities(P_ID, [P_L_PLACE_H | P_L_PLACE_T], P_AVAILABLE, R_AVAILABLE) :-

check_available_place(P_ID, P_L_PLACE_H, P_AVAILABLE, N_AVAIL), !, fill_all_available_abilities(P_ID, P_L_PLACE_T, N_AVAIL, R_AVAILABLE)

;

fill_all_available_abilities(P_ID, P_L_PLACE_T, P_AVAILABLE, R_AVAILABLE).

%%%%%%%%%%

%Проверка подходит ли дейсвия по возможностям и добавляет в список

check_available_place(P_ID, P_ABILIT, P_L_AVAILS, R_L_AVAILS) :- !,

get_all_statuses(L_STATUS_TYPES),

gnom(P_ID, _, P_CHARACT, P_STATUS),

check_place_by_status(L_STATUS_TYPES, P_STATUS, P_ABILIT),

check_place_by_charact(P_CHARACT, P_ABILIT), !,

add_element(P_ABILIT, P_L_AVAILS, R_L_AVAILS)

;

true.

check_place_by_status([], _, _).

%проверка, подходит ли место по возможностям состояния

check_place_by_status([P_TYPE_H | P_TYPE_T], P_STATUS ,P_PLACE_ABIL) :- !,

get_places_status_values(P_TYPE_H, P_PLACE_ABIL, STATUS_VALUES),

get_status_value(P_TYPE_H, P_STATUS, STATUS_VALUE),

check_status_array(STATUS_VALUE, STATUS_VALUES), check_place_by_status(P_TYPE_T, P_STATUS, P_PLACE_ABIL).

%проверка того, что все значения в сумме с перменой не отрицательны

check_status_array(_, []).

check_status_array(P_STATUS_VALUE, [P_L_H | P_L_T]) :- !,

nonvar(P_L_H), N_V is P_STATUS_VALUE + P_L_H, N_V >= 0, !,

check_status_array(P_STATUS_VALUE, P_L_T).

%проверка того, подходит ли место по характеру

check_place_by_charact(P_L_CHARACT, [_, P_PLACE_CONTEXT, _]) :-

get_charact_value(moral, P_L_CHARACT, MORAL),

map_places_abilities_morale_offset(MORAL_OFFSET),

charact_moral_ability_len(MORAL_LEN),

get_element(MORAL_OFFSET, P_PLACE_CONTEXT, ABILIT_MORAL),

MAX_MORAL is MORAL + MORAL_LEN, MIN_MORAL is MORAL - MORAL_LEN,

!,

ABILIT_MORAL >= MIN_MORAL, ABILIT_MORAL =< MAX_MORAL.

%берет требования для типа статуса

get_places_status_values(P_TYPE, [_, P_PLACE_CONTEXT, _], R_VALUES) :-

map_places_abilities_status_offset(OFFSET),

map_places_abilities_status_len(LEN),

status_list_cell(P_TYPE, STATUS_NUMBER),

PLACE_STATUS_OFFSET is OFFSET + STATUS_NUMBER * LEN,

get_list_sub_list(PLACE_STATUS_OFFSET, LEN, P_PLACE_CONTEXT, R_VALUES).

%Вычисление эффекта толпы для всех гномов

calc_gnoms_cycle_crowd_effect :- ;((show_gnoms_cycle_crowd_effect(true), nl, write('Crowd effect')), true), array_gnoms(X), calc_gnoms_cycle_crowd_effect(X).

calc_gnoms_cycle_crowd_effect([]).

calc_gnoms_cycle_crowd_effect([H | T]) :- calc_gnom_cycle_crowd_effect(H), calc_gnoms_cycle_crowd_effect(T).

%вычисление эффекта толпы для гнома

calc_gnom_cycle_crowd_effect(P_ID) :- array_gnoms(X), calc_gnom_cycle_crowd_effect(P_ID, X).

calc_gnom_cycle_crowd_effect(_, []).

calc_gnom_cycle_crowd_effect(P_ID, [P_GNOM_H | P_GNOM_L]) :-

P_ID = P_GNOM_H, calc_gnom_cycle_crowd_effect(P_ID, P_GNOM_L)

;

gnom(P_ID, LEAD_GNOM_PLACE, LEAD_CHARACT, _), gnom(P_GNOM_H, GNOM_PLACE, CHARACT, _),

LEAD_GNOM_PLACE = GNOM_PLACE,

get_charact_value(leader, LEAD_CHARACT, LEAD_LEADERSHIP),

get_charact_value(leader, CHARACT, GNOM_LEADERSHIP),

LEAD_LEADERSHIP > GNOM_LEADERSHIP, LEAD_DIF is LEAD_LEADERSHIP - GNOM_LEADERSHIP,

gnoms_cycle_demands(P_ID, LEAD_DEMAND), gnoms_cycle_demands(P_GNOM_H, GNOM_DEMAND),

list_max_element(LEAD_DEMAND, STATUS_NUMBER),

get_element(STATUS_NUMBER, GNOM_DEMAND, DEMAND_VALUE),

crowd_effect_mult(CROWD_MULT), MOD_VALUE is CROWD_MULT * LEAD_DIF,

N_DEMAND_VALUE is DEMAND_VALUE + MOD_VALUE, !,

status_list_cell(STATUS_TYPE, STATUS_NUMBER), status_name(STATUS_TYPE, STATUS_NAME),

set_element(STATUS_NUMBER, N_DEMAND_VALUE, GNOM_DEMAND, N_GNOM_DEMAND),

retract(gnoms_cycle_demands(P_GNOM_H, _)),

assertz(gnoms_cycle_demands(P_GNOM_H, N_GNOM_DEMAND)),

;((show_gnoms_cycle_crowd_effect(true), nl, list_write(['ID= ', P_ID, '; Affect ID = ', P_GNOM_H, '; ', STATUS_NAME, ' += ', MOD_VALUE])), true),

calc_gnom_cycle_crowd_effect(P_ID, P_GNOM_L)

;

calc_gnom_cycle_crowd_effect(P_ID, P_GNOM_L).

%Среда

%параметры среды при выполнении программы БЕЗ трассировки

%показывать ли информацию о гномах на каждом цикле

%show_gnoms_cycle_info(true).

%показывать ли информацию о действии гнома

%show_gnoms_cycle_des_execution(true).

%показывать ли информацию расширеную о действии гнома

%show_gnoms_cycle_des_execution_advanced(false).

%показывать ли информацию об эффекте толпы

%show_gnoms_cycle_crowd_effect(true).

%показывать ли информацию о гномах после создания

%show_gnoms_info(true).

%ждать ли нажатия эникея на каждом цикле

%read_keyboard_on_cycle(false).

%количество символов в форматированом числе

%format_number_digits(4).

%параметры среды при выполнении программы С трассировкой

%показывать ли информацию о гномах на каждом цикле

show_gnoms_cycle_info(false).

%показывать ли информацию о действии гнома

show_gnoms_cycle_des_execution(false).

%показывать ли информацию расширеную о действии гнома

show_gnoms_cycle_des_execution_advanced(false).

%показывать ли информацию об эффекте толпы

show_gnoms_cycle_crowd_effect(false).

%показывать ли информацию о гномах после создания

show_gnoms_info(false).

%ждать ли нажатия эникея на каждом цикле

read_keyboard_on_cycle(false).

%количество символов в форматированом числе

format_number_digits(4).

gen_char(P_CHAR, P_COUNT, R_RESULT) :-

P_COUNT > 0, N_COUNT = P_COUNT - 1, gen_char(P_CHAR, N_COUNT, S_RESULT), atom_concat(S_RESULT, P_CHAR, R_RESULT)

;

R_RESULT = ''.

format_number(P_NUM, R_ATOM) :-

number_atom(P_NUM, A), atom_length(A, L), format_number_digits(FL),

NL is FL - L, gen_char(' ', NL, SPACES), atom_concat(SPACES, A, R_ATOM).

%Показать инфо гнома.

print_gnom_info(P_ID) :- nl, !, get_all_statuses(STATUS_TYPES),

gnom(P_ID, PLACE, [LEAD ,LUCK ,MORALE], L_S),

list_write(['ID = ', P_ID, '; ']), print_statuses_array(STATUS_TYPES, L_S),

map_places(PLACE, PLACE_NAME), write('; place = '), write(PLACE_NAME),

nl, write(' '), list_write(['leadership = ', LEAD, '; luck = ' , LUCK, '; moral = ', MORALE]).

print_gnom_cycle_info(P_ID) :- !,

get_all_statuses(STATUS_TYPES),

gnom(P_ID, PLACE, _, L_S),

list_write(['Status: ID = ', P_ID, '; ']), print_statuses_array(STATUS_TYPES, L_S),

map_places(PLACE, PLACE_NAME), write('; place = '), write(PLACE_NAME),

nl, write('Demands: '), gnoms_cycle_demands(P_ID, DEMANDS), print_statuses_array(STATUS_TYPES, DEMANDS).

print_statuses_array([], _).

print_statuses_array([P_TYPE_H | P_TYPE_T ], P_STATUS) :-

status_name(P_TYPE_H, STATUS_NAME), get_status_value(P_TYPE_H, P_STATUS, V), format_number(V, FV), list_write([STATUS_NAME, ' = ']), write(FV), write('; '), print_statuses_array(P_TYPE_T, P_STATUS).

print_gnoms_info :-

show_gnoms_info(true), !, nl, write('Gnoms info: '), array_gnoms(X), print_gnoms_info(X)

;

true.

print_gnoms_info([]).

print_gnoms_info([P_LIST_H | P_LIST_T]) :-

print_gnoms_info(P_LIST_T), nl,

print_gnom_info(P_LIST_H) .

print_gnoms_cycle_info :-

show_gnoms_cycle_info(true), !, nl, write('Gnoms info: '), array_gnoms(X), print_gnoms_cycle_info(X)

;

true.

print_gnoms_cycle_info([]).

print_gnoms_cycle_info([P_LIST_H | P_LIST_T]) :-

print_gnoms_cycle_info(P_LIST_T), nl,

print_gnom_cycle_info(P_LIST_H).

%Инициализация среды

init :- assertz(gnom_id_seq(1)), randomize, assertz(array_gnoms([])).

process_cycles(P_LOOPS) :-

P_LOOPS = 0, !, nl, write('Жизненный цикл закончился');

NLOOPS is P_LOOPS - 1, calc_cycle, process_cycles(NLOOPS).

calc_cycle :- fill_gnoms_cycle_demands, !, fill_gnoms_cycle_des,!, calc_gnoms_cycle_crowd_effect, !, execute_gnoms_cycle_des, !, print_gnoms_cycle_info, nl, write('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'),nl, ;((read_keyboard_on_cycle(true), read_atom(_)) , true).

create_gnoms(0).

create_gnoms(P_NUM) :-

P_NUM > 0, N_NUM is P_NUM - 1, add_new_gnom(_), create_gnoms(N_NUM)

;

true.

%тестовое выполнение программы без трассировки

test :- init, create_gnoms(3), print_gnoms_info, nl, process_cycles(10).

%тестовое выполнение программы с трассировкой

test_trace :- init,

leash(loose),

spy(add_new_gnom/1),

%spy(gnom_move/2),

spy(fill_gnoms_cycle_demands/0),

spy(update_gnom/4),

spy(fill_gnom_cycle_des/1),

%spy(build_available_abilities/2),

%spy(calculate_des/4),

%spy(calc_gnoms_cycle_crowd_effect/1),

spy(calc_gnom_cycle_crowd_effect/1),

Соседние файлы в папке Моделирование объекта гномы