Моделирование объекта гномы / Отчёт
.docМИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ ЭЛЕКТРОТЕХНИЧЕСКИЙ
УНИВЕРСИТЕТ «ЛЭТИ»
Кафедра МОЭВМ
ОТЧЕТ
по дисциплине «Логическое программирование»
по лабораторным работам №1 – 3
Выполнили:
Азаров А. С. Петров А. Г.
Группа
2304
Руководитель:
Беляев С. А.
Санкт-Петербург
2005
ПОСТАНОВКА ЗАДАЧИ
-
Описать объектов, имеющий свойства и действия (атрибуты и методы).
-
Реализовать «жизнь» объекта: ввести приоритеты, в соответствии с которыми он «выбирает», какой атрибут предпочтительнее изменить.
-
Реализовать «эффект толпы»: в «толпе» отдельный объект может сменить свой приоритет в соответствии с приоритетами других объектов.
ОПИСАНИЕ ОБЪЕКТА
Объектом является гном.
Свойства гномов:
-
Идентификатор (уникальный номер объекта).
-
Список характера, в который входят свойства: 1) Лидерство (чем больше значение этого свойства, тем меньше влияние толпы) 2) Везение (увеличение всех положительных вероятностей) 3) Моральные качества (чем больше значение этого свойства, тем меньше вероятность совершения гномом поступков с низкой моральной оценкой).
-
Список состояний, содержащий: 1) Энергия; 2) Деньги; 3) Счастье; 4) Сытость; 5) Здоровье.
-
Место, в котором гном в данный момент находится (дом, бар, шахта).
Метод создания гномов.
Объект создаётся методом add_new_gnom /1 с параметром, в котором возвращается идентификатор создаваемого объекта.
Методы воздействия на гнома.
-
update_gnom(P_ID, P_PLACE, P_L_C, P_L_S) Метод, задающий новые значения для всех атрибутов гнома.
-
gnom_move(P_ID, P_DEST_PLACE) Метод, моделирующий перемещение гнома из одного места в другое. При выполнении этого метода рассчитывается и отнимается количество энергии, необходимое на переход из места, в котором гном находится в данный момент в место назначения.
-
execute_gnom_cycle_des(P_ID) Метод, отвечающий за выполнение намеченного действия для гнома с идентификатором P_ID. В ходе выполнения этого метода рассчитывается вероятность выполнения действия (за счёт сравнения свойства гнома «везение» с вычисляемым произвольно шансом выполнения действия); если действие можно выполнить, оно выполняется. После «выполнения» действия вызывается метод update_gnom, который и приводит к изменениям свойств объекта.
ВЫБОР ДЕЙСТВИЯ
Действия намечаются на каждом шаге жизненного цикла гномов (для всех гномов) в зависимости от мест, в которых гномы находятся, их характеров и потребностей.
Алгоритм выбора действия:
-
Заполнение массива потребностей всех гномов.
-
Заполнение массива принятых решений на основе массива потребностей (для всех гномов).
-
Вычисление эффекта толпы для всех гномов.
//Этот алгоритм реализован в предикате calc_cycle.
Потребности гномов вычисляются следующим образом:
(цикл для каждого свойства состояния гнома)
-
В массиве состояний ищется данное свойство состояния.
-
Текущее состояние сравнивается с нормальным и критическим; вычисляется приоритет состояния (из массива приоритетов состояний). Если текущее состояние лучше нормального, ему присваивается небольшая потребность, если не хуже нормального и лучше критического, то средняя, а если не лучше критического – то очень большая. Присваиваемая потребность есть потребность гнома в улучшении данного свойства состояния.
//Этот алгоритм реализован в предикате fill_gnoms_cycle_demands.
Алгоритм принятия решения:
-
Поиск возможностей.
-
Получение ранее построенного массива потребностей.
-
«Вычисление» действия для текущего шага жизненного цикла: 1) Вычисление произвольной потребности с учетом ее веса; 2) Поиск действия (по свойству состояния) с лучшим исходом; 3) Проверка выбранного действия (если не нашлось действия, которое можно выполнить на основании текущей потребности, запуск «вычисления» действия по другому критерию).
//Этот алгоритм реализован в предикате fill_gnoms_cycle_des.
Описание контекста вохможностей:
Каждое дествие требует некоторых затрат, все затраты описываются списком из 12 элементов:
-
Первый элемент – вероятность положительного исхода;
-
Второй элемент – оценка нравственности (от 0 до 10);
-
Остальные 10 – по 2 на каждое свойство гнома – описаны в следующей последовательности: энергия, деньги, счастье, еда, здоровье, где первый элемент – эффект при отрицательном исходе, а второй – при положительном.
//Это описание реализовано в системе предикатов map_places_abilities/3, где //первым параметром является место, в котором возможно данное действие, //вторым – список контекста возможности, описанный выше //и третьим – описание действия.
МОДЕЛИРОВАНИЕ ПОВЕДЕНИЯ В «ТОЛПЕ»
«Толпа» есть совокупность нескольких гномов. При создании гнома его идентификатор заносится в массив гномов, возвращаемый предикатом array_gnoms.
Алгоритм вычисления «эффекта толпы» для гнома:
(цикл для каждого гнома)
-
Сравнение данного гнома с гномом, выбираемым из списка гномов: в случае совпадения, эффект не рассчитывается, т.к. гном не может повлиять сам на себя.
-
Сравнение места данного гнома с местом, в котором находится гном из списка: в случае несовпадения эффект также не рассчитывается, т.к. гномы, удалённые друг от друга друг на друга, соответственно, не влияют.
-
Сравнение свойств характеров гномов «лидерство». Если лидерство данного гнома больше, то он может повлиять на гнома из списка описанным далее образом. Из списка потребностей гнома-лидера (данного гнома) выбирается потребность с наибольшим значением. Та же потребность выбирается из списка потребностей гнома, «находящегося под влиянием», и её увеличивается на разницу в «лидерстве» двух рассматриваемых гномов (т.е. чем меньше «лидерство» гнома из списка по сравнению с данным гномом, тем больше будет на него влияние), умноженную на коэффициент эффекта толпы, возвращаемый предикатом 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),