<div class="notebook"> <div class="nb-cell program" name="p1"> generate_story(Input, Story) :- initialize(Input, Curr, Target), generate_opener(Curr, Target, Opener), get_actions(Curr, Target, Actions), execute_actions(Curr, Target, Actions, Descriptions), format('Descriptions: ~w~n~n', [Descriptions]), concatenate(Descriptions, ActionStrings), string_concat(Opener, ActionStrings, StoryWithOpener), generate_closer(Curr, Target, Closer), string_concat(StoryWithOpener, Closer, Story), !. :- dynamic name/1. :- dynamic pronoun/1. :- dynamic possessive/1. initialize(Input, Curr, Target) :- Input = _{name:Name, gender:Gender}, asserta(name(Name)), assert_pronouns(Gender), Curr = [hungry], Target = [happy]. assert_pronouns(male) :- asserta(pronoun(he)), asserta(possessive(his)). assert_pronouns(female) :- asserta(pronoun(she)), asserta(possessive(her)). generate_opener(_Curr, _Target, Opener) :- name(Name), pronoun(Pronoun), first_char_uppercase(Pronoun, Upper), atomics_to_string(['One day, ',Name,' was in the kitchen and ',Pronoun,' was hungry. ',Upper,' decided to make a BLT sandwich. '], Opener). % https://stackoverflow.com/questions/20297765/converting-1st-letter-of-atom-in-prolog first_char_uppercase(WordLC, WordUC) :- atom_chars(WordLC, [FirstChLow|LWordLC]), atom_chars(FirstLow, [FirstChLow]), upcase_atom(FirstLow, FirstUpp), atom_chars(FirstUpp, [FirstChUpp]), atom_chars(WordUC, [FirstChUpp|LWordLC]). generate_closer(_Curr, _Target, Closer) :- name(Name), possessive(Possessive), atomics_to_string(['With a full belly, ',Name,' could now get on with the rest of ',Possessive,' day. THE END'], Closer). get_actions(Curr, Target, Actions) :- length(Actions, _L), phrase(plan(Curr, Target), Actions), !. plan(Curr, Target) --> {subset(Target, Curr)}, !. plan(Curr, Target) --> {action(Curr, Next, Action)}, [Action], plan(Next, Target). execute_actions(Curr, Target, Actions, Final) :- execute_actions(Curr, Target, Actions, [], Final). execute_actions(_, _, [], Accumulator, Final) :- format('no more actions!~n'), Accumulator = Final. execute_actions(Curr, Target, [A|As], Accumulator, Final) :- random(1, 11, R), try_action(R, A, Curr, Next, Target, TargetNew, Description, Success), append(Accumulator, [Description], NewAccumulator), ( ( Success = true, format('action succeeded! ~w~n', [A]), % execute next action execute_actions(Next, TargetNew, As, NewAccumulator, Final) ) ; ( Success = false, format('action failed! ~w~n', [A]), % replan and try again get_actions(Next, TargetNew, Actions), execute_actions(Next, TargetNew, Actions, NewAccumulator, Final) ) ), !. try_action(R, takeout(Item, Location), Curr, Next, Target, Target, Description, true) :- R =< 7, name(Name), qualifier(Item, Qualifier), atomics_to_string([Name,' took ',Qualifier,' ',Item,' out of the ',Location,'. '], Description), append(Curr, [holding(Item)], Next). try_action(R, takeout(Item, Location), Curr, Curr, Target, Target, Description, false) :- R =< 8, name(Name), qualifier(Item, Qualifier), atomics_to_string([Name,' went to take ',Qualifier,' ',Item,' out of the ',Location,', but dropped it on the floor. '], Description). try_action(_, takeout(Item, Location), Curr, Curr, Target, Target, Description, false) :- name(Name), qualifier(Item, Qualifier), atomics_to_string([Name,' took ',Qualifier,' ',Item,' out of the ',Location,', but it was moldy and spoiled. '], Description). try_action(_, make(Food, using(Ingredients)), Curr, Next, Target, Target, Description, true) :- pronoun(Pronoun), atoms_to_english_list(Ingredients, IngredientsString), atomics_to_string(['Then ',Pronoun,' used the ',IngredientsString,' to make a ',Food,'. '], Description), maplist(holding, Ingredients, HoldingIngredients), subtract(Curr, HoldingIngredients, CurrUsed), append(CurrUsed, [holding(Food)], Next). try_action(R, eat(Food), Curr, Next, Target, Target, Description, true) :- name(Name), possessive(Possessive), R =< 9, atomics_to_string(['Finally, careful not to drop anything on the floor, ',Name,' ate ',Possessive,' ',Food,' - the whole, entire thing. '], Description), subtract(Curr, [holding(Food), hungry], Curr2), append(Curr2, [happy], Next). try_action(_, eat(Food), Curr, Next, Target, Target, Description, false) :- name(Name), possessive(Possessive), pronoun(Pronoun), atomics_to_string([Name,' took a big bite out of ',Possessive,' ',Food,'. Too big. It slipped out of his hand onto the floor. Great. Now ',Pronoun, ' had to start all over. '], Description), subtract(Curr, [holding(Food)], Next). atoms_to_english_list(Atoms, String) :- last(Atoms, Last), atomics_to_string(['and ', Last], LastAnd), select(Last, Atoms, LastAnd, AtomsWithAnd), % replace last element with 'and last' atomic_list_concat(AtomsWithAnd, ', ', AtomList), atom_string(AtomList, String). % https://stackoverflow.com/a/33727012 concatenate(StringList, StringResult) :- maplist(atom_chars, StringList, Lists), append(Lists, List), atom_chars(StringResult, List). qualifier(tomato, a). qualifier(bacon, some). qualifier(lettuce, some). qualifier(bread, some). inside(fridge, tomato). inside(fridge, bacon). inside(fridge, lettuce). inside(pantry, bread). recipe(sandwich, [tomato,bacon,lettuce,bread]). eat(sandwich). holding(X, Y) :- Y = holding(X). % wrapper for maplist % generate takeout(Item, Location) action(Curr, Next, Action) :- inside(Location, Item), append(Curr, [holding(Item)], Next), Action = takeout(Item, Location). % generate make(Food, using(Ingredients)) action(Curr, Next, Action) :- recipe(Food, Ingredients), maplist(holding, Ingredients, HoldingIngredients), subset(HoldingIngredients, Curr), subtract(Curr, HoldingIngredients, CurrUsed), append(CurrUsed, [holding(Food)], Next), Action = make(Food, using(Ingredients)). % generate eat(Food) action(Curr, Next, Action) :- eat(Food), member(holding(Food), Curr), subtract(Curr, [holding(Food), hungry], Curr2), append(Curr2, [happy], Next), Action = eat(Food). </div> <div class="nb-cell query" name="q1"> generate_story(_{name:"John",gender:male}, Story). </div> </div>