Скачиваний:
5
Добавлен:
01.05.2014
Размер:
29.97 Кб
Скачать
%Общие функции
%Логическое не
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),
create_gnoms(7), process_cycles(3).
Соседние файлы в папке Моделирование объекта гномы