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