Created
April 17, 2011 14:04
-
-
Save Joelbyte/924052 to your computer and use it in GitHub Desktop.
Bacchus-Bosch - Part 5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(builder). | |
:- info([ | |
version is 1.0, | |
author is 'Victor Lagerkvist', | |
date is 2011/04/14, | |
comment is 'The object that builds the entities of Bacchus-Bosch.']). | |
:- public(build/5). | |
:- public(build/4). | |
:- public(build/3). | |
build(final_state, F) :- | |
Ps = [printable_property - State], | |
State = "Congratulations! A winner is you!\n (No, you can't quit. Stop trying.)\n", | |
entity::new(Ps, final_state, F). | |
build(world, Id, Rooms, Player, World) :- | |
Ps = [map_property-State], | |
build(final_state, F), | |
map_property::new([[F|Rooms], Player], State), | |
entity::new(Ps, Id, World). | |
build(room, Id, Description, Room) :- | |
Ps = [container_property - State1, | |
printable_property - State2], | |
container_property::new([], State1), | |
printable_property::new([Description], State2), | |
entity::new(Ps, Id, Room). | |
build(key, Id, Description, Key) :- | |
Ps = [key_property-State1, | |
printable_property-State2, | |
carriable_property-State3], | |
key_property::new([Id], State1), | |
printable_property::new([Description], State2), | |
carriable_property::new([], State3), | |
entity::new(Ps, Id, Key). | |
build(door, Id, Description, Door) :- | |
Ps = [openable_property-State1, | |
printable_property-State2, | |
entrance_property-State3], | |
openable_property::new([], State1), | |
printable_property::new([Description], State2), | |
entrance_property::new([void], State3), | |
entity::new(Ps, Id, Door). | |
build(generic_entity, Id, Description, E) :- | |
Ps = [printable_property-State], | |
printable_property::new([Description], State), | |
entity::new(Ps, Id, E). | |
build(lock, Id, Lock) :- | |
Ps = [lock_property-State], | |
lock_property::new([], State), | |
entity::new(Ps, Id, Lock). | |
build(player, Id, Player) :- | |
Ps = [player_property-State1, | |
inventory_property-State2, | |
health_property-State3, | |
movable_property-State4], | |
player_property::new([], State1), | |
inventory_property::new([], State2), | |
health_property::new([], State3), | |
movable_property::new([void], State4), | |
entity::new(Ps, Id, Player). | |
:- end_object. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(entity). | |
:- info([ | |
version is 1.0, | |
author is 'Victor Lagerkvist', | |
date is 2011/03/18, | |
comment is 'The entity operations of Bacchus-Bosch.']). | |
:- public(new/3). | |
:- public(update/2). | |
:- public(action/4). | |
:- public(get_property/2). | |
:- public(select_property/3). | |
:- public(add_property/3). | |
:- public(add_properties/3). | |
:- public(update_property/5). | |
%% We might as well abstract this since it will make it easier to | |
%% change the representation of identities later on. | |
new(Ps, Id, [identity_property-Id|Ps]). | |
update(E0, E) :- | |
update(E0, E0, E). | |
update(E, [], E). | |
update(E0, [P|Ps], E) :- | |
P = Name - _, | |
Name::update(E0, E1), | |
update(E1, Ps, E). | |
action(A, Args, E0, E) :- | |
%% Select a property from the list such that the action A can | |
%% be performed with the arguments Args. | |
list::select(P, E0, E1), | |
P = PropertyName - State, | |
PropertyName::action(A, Args, E1, State, E2, State1), | |
%% Add the property with the updated state to E2. | |
P1 = PropertyName - State1, | |
E = [P1|E2]. | |
get_property(E, P) :- | |
list::member(P, E). | |
select_property(P, E, E1) :- | |
list::select(P, E, E1). | |
add_property(P, E, [P|E]). | |
add_properties(E0, Ps, E) :- | |
list::append(Ps, E0, E). | |
update_property(Name, E0, S0, S, [Name-S|E]) :- | |
list::select(Name-S0, E0, E). | |
:- end_object. | |
:- object(property). | |
:- info([ | |
version is 1.0, | |
author is 'Victor Lagerkvist', | |
date is 2011/03/19, | |
comment is 'A property constitutes the basic behaviours of the objects in Bacchus-Bosch.']). | |
:- public(update/2). | |
:- mode(update(+entity, -entity), zero_or_more). | |
:- info(update/2, [ | |
comment is 'Update the entity to which the property belong.', | |
argnames is ['Entity', 'Entity1']]). | |
:- public(action/6). | |
:- mode(action(+atom, +list, +entity, +state, -state, -entity), zero_or_more). | |
:- info(action/6, [ | |
comment is 'Execute the action Name with respects to Args, State and Entity, and store the resulting new state and entity in State1 and Entity1.', | |
argnames is ['Name', 'Args', 'Entity', 'State', 'Entity1', 'State1']]). | |
:- public(new/2). | |
:- mode(new(+list, -term), zero_or_more). | |
:- info(new/2, [ | |
comment is 'Unify State with the initial state of the property, with respect to Args', | |
argnames is ['Args', 'State']]). | |
%% Basic definition: do nothing! | |
update(E, E). | |
%% Basic definition, overloaded in almost every descendant | |
%% prototype. | |
new([], void). | |
:- end_object. | |
:- object(identity_property, | |
extends(property)). | |
new([Id], Id). | |
:- end_object. | |
:- object(player_property, | |
extends(property)). | |
:- end_object. | |
:- object(container_property, | |
extends(property)). | |
new([], []). | |
update(E0, E) :- | |
entity::select_property(container_property-Items, E0, E1), | |
update_children(Items, Items1), | |
E = [container_property-Items1|E1]. | |
update_children([], []). | |
update_children([E|Es], [E1|E1s]) :- | |
entity::update(E, E1), | |
update_children(Es, E1s). | |
action(add_item, [E], Owner, Items, Owner, [E|Items]). | |
action(select_item, [P, E], Owner, Items, Owner, Items1) :- | |
list::select(E, Items, Items1), | |
entity::get_property(E, P). | |
action(update_item, [P, Old, New], Owner, Items, Owner, [New|Items1]) :- | |
list::select(Old, Items, Items1), | |
entity::get_property(Old, P). | |
action(select_items, [P, Es], Owner, Items, Owner, Items1) :- | |
meta::partition([E] >> (entity::get_property(E, P)), Items, Es, Items1). | |
action(get_item, [P, E], Owner, Items, Owner, Items) :- | |
list::member(E, Items), | |
entity::get_property(E, P). | |
action(print_children, Args, Owner, Items, Owner, Items) :- | |
meta::include([E] >> | |
(entity::action(print, Args, E, _)), | |
Items, | |
_). | |
:- end_object. | |
:- object(inventory_property, | |
extends(container_property)). | |
new([], []). | |
update(E0, E) :- | |
entity::select_property(inventory_property-Items, E0, E1), | |
update_children(Items, Items1), | |
E = [inventory_property-Items1|E1]. | |
update_children([], []). | |
update_children([E|Es], [E1|E1s]) :- | |
entity::update(E, E1), | |
update_children(Es, E1s). | |
valid_item(E) :- | |
entity::get_property(E, carriable_property-_). | |
action(add_item, [E], Owner, Items, Owner, [E|Items]) :- | |
valid_item(E). | |
action(select_item, [P, Item], Owner, Items, Owner, Items1) :- | |
list::select(Item, Items, Items1), | |
entity::get_property(Item, P). | |
action(get_item, [P, E], Owner, Items, Owner, Items) :- | |
list::member(E, Items), | |
entity::get_property(E, P). | |
action(print_children, Args, Owner, Items, Owner, Items) :- | |
meta::include([E] >> | |
(entity::action(print, Args, E, _)), | |
Items, | |
_). | |
:- end_object. | |
:- object(carriable_property, | |
extends(property)). | |
%% Perhaps not the most interesting property in the game. | |
:- end_object. | |
:- object(health_property, | |
extends(property)). | |
new([], 10). | |
new([Health], Health). | |
action(decrease_health, [], Owner, H0, Owner, H) :- | |
H is H0 - 1. | |
action(increase_health, [], Owner, H0, Owner, H) :- | |
H is H0 + 1. | |
:- end_object. | |
:- object(key_property, | |
extends(property)). | |
%% The default key. | |
new([], key). | |
new([Id], Id). | |
:- end_object. | |
:- object(lock_property, | |
extends(property)). | |
%% The (default) key that opens the lock. | |
new([], Key-locked) :- | |
key_property::new([], Key). | |
new([Key, State], Key-State). | |
valid_key(E, Key) :- | |
entity::get_property(E, key_property-Key). | |
action(lock, [Entity], Owner, Key-_, Owner, Key-locked) :- | |
valid_key(Entity, Key). | |
action(unlock, [Entity], Owner, Key-_, Owner, Key-unlocked) :- | |
valid_key(Entity, Key). | |
action(unlocked, [], Owner, Key-unlocked, Owner, Key-unlocked). | |
action(set_key, [Key], Owner, _-State, Owner, Key-State). | |
:- end_object. | |
:- object(openable_property, | |
extends(property)). | |
new([], closed-Lock) :- | |
lock_property::new([], LP), | |
entity::new(LP, lock, Lock). | |
new([State, Lock], State-Lock). | |
action(open, [], Owner, _-Lock, Owner, open-Lock) :- | |
entity::action(unlocked, [], Lock, Lock). | |
action(close, [], Owner, _-Lock, Owner, closed-Lock) :- | |
entity::action(unlocked, [], Lock, Lock). | |
action(unlock, Key, Owner, State-Lock, Owner, State-Lock1) :- | |
entity::action(unlock, Key, Lock, Lock1). | |
action(lock, Key, Owner, State-Lock, Owner, State-Lock1) :- | |
entity::action(lock, Key, Lock, Lock1). | |
action(set_lock, [Lock], Owner, State-_, Owner, State-Lock) :- | |
entity::get_property(Lock, lock_property-_). | |
action(set_state, [State], Owner, _-Lock, Owner, State-Lock) :- | |
State = open ; State = closed. | |
:- end_object. | |
:- object(entrance_property, | |
extends(property)). | |
new([Id], Id). | |
action(get_location, [Location], Owner, Location, Owner, Location). | |
action(set_location, [Location], Owner, _, Owner, Location). | |
:- end_object. | |
:- object(on_fire_property, | |
extends(property)). | |
update(E0, E) :- | |
entity::action(decrease_health, [], E0, E). | |
:- end_object. | |
:- object(printable_property, | |
extends(property)). | |
new([Description], Description). | |
action(print, [], Owner, Description, Owner, Description) :- | |
format(Description). | |
:- end_object. | |
:- object(fruit_property, | |
extends(property)). | |
action(dissolve, [E0, E], Owner, State, Owner, State) :- | |
entity::action(increase_health, [], E0, E). | |
:- end_object. | |
:- object(magic_fruit_property, | |
extends(fruit_property)). | |
action(dissolve, [E0, E], Owner, State, Owner, State) :- | |
entity::action(set_location, [final_state], E0, E). | |
:- end_object. | |
:- object(map_property, | |
extends(property)). | |
new([], []-[]). | |
new([Rooms, Player], Rooms-Player). | |
update(E0, E) :- | |
entity::update_property(map_property, E0, Rooms0-P0, Rooms-P, E), | |
entity::update(P0, P), | |
update_rooms(Rooms0, Rooms). | |
update_rooms([], []). | |
update_rooms([R0|R0s], [R|Rs]) :- | |
entity::update(R0, R), | |
update_rooms(R0s, Rs). | |
action(add_rooms, [Rooms1], Owner, Rooms2-P, Owner, Rooms-P) :- | |
list::append(Rooms1, Rooms2, Rooms). | |
action(get_room, [Property, R], Owner, Rooms-P, Owner, Rooms-P) :- | |
list::member(R, Rooms), | |
entity::get_property(R, Property). | |
action(select_room, [Property, R], Owner, Rooms-P, Owner, Rooms1-P) :- | |
list::select(R, Rooms, Rooms1), | |
entity::get_property(R, Property). | |
action(update_room, [Old, New], Owner, Rooms-P, Owner, [New|Rooms1]-P) :- | |
list::select(Old, Rooms, Rooms1). | |
action(print, [], Owner, Rooms-P, Owner, Rooms-P) :- | |
action(current_room, [Room], Owner, Rooms-P, _, _), | |
entity::action(print, [], Room, _). | |
action(current_room, [Current], Owner, Rooms-P, Owner, Rooms-P) :- | |
entity::action(get_location, [Id], P, _), | |
list::member(Current, Rooms), | |
entity::get_property(Current, identity_property-Id). | |
action(update_current_room, [Current0, Current], | |
Owner, Rooms-P, Owner, [Current|Rooms1]-P) :- | |
entity::action(get_location, [Id], P, _), | |
list::select(Current0, Rooms, Rooms1), | |
entity::get_property(Current0, identity_property-Id). | |
action(update_player, [P0, P], Owner, Rooms-P0, Owner, Rooms-P). | |
action(get_player, [P], Owner, Rooms-P, Owner, Rooms-P). | |
action(set_player, [P], Owner, Rooms-_, Owner, Rooms-P) :- | |
entity::get_property(P, player_property-_). | |
:- end_object. | |
:- object(movable_property, | |
extends(property)). | |
new([Id], Id). | |
action(get_location, [Room], Owner, Room, Owner, Room). | |
action(set_location, [Location], Owner, _, Owner, Location). | |
:- end_object. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(example_game). | |
:- public(entity/1). | |
:- public(add_property/1). | |
:- public(action/1). | |
:- public(connect/1). | |
begin entities. | |
build(room, room1, "A rather unremarkable room.\n"). | |
build(room, room2, "A room almost identical to the previous one. What on earth is going on!?\n"). | |
build(door, door, "A wooden door with a small and rusty lock.\n"). | |
build(lock, lock). | |
build(key, key, "A slightly bent key.\n"). | |
build(generic_entity, apple, "An apple! \n"). | |
build(generic_entity, banana, "A yellow banana. Hot diggity dog!\n"). | |
build(player, player). | |
end entities. | |
begin properties. | |
add_property(fruit_property, apple). | |
add_property(carriable_property, apple). | |
add_property(magic_fruit_property, banana). | |
add_property(carriable_property, banana). | |
end properties. | |
begin relations. | |
action(set_key, lock, $ key). | |
action(set_lock, door, lock). | |
action(set_state, door, $ closed). | |
action(add_item, room1, apple). | |
action(add_item, room1, key). | |
action(add_item, room2, banana). | |
action(set_location, player, $ room1). | |
connect(room1, room2, door). | |
end relations. | |
:- end_object. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(game). | |
:- info([ | |
version is 1.0, | |
author is 'Victor Lagerkvist', | |
date is 2011/03/20, | |
comment is 'The core functionality of Bacchus-Bosch.']). | |
:- public(init/1). | |
init(Game) :- | |
write('Welcome to Bacchus-Bosch!'), nl, | |
current_input(S), | |
script_interpreter::interpret_game(Game, World), | |
repl(S, [], World). | |
repl(S, History, World0) :- | |
entity::update(World0, World1), | |
entity::action(print, [], World1, _), | |
write('> '), | |
nlp::parse_line(S, Atoms), | |
write('The input is: '), | |
meta::map([X] >> (write(X), write(' ')), Atoms), nl, | |
nlp::tag_atoms(Atoms, AtomTags), | |
write('The tagged input is: '), | |
meta::map([X] >> (write(X), write(' ')), AtomTags), nl, | |
( eval(History, AtomTags, World1, World) -> | |
true | |
; write('no.'), | |
nl, | |
World = World1 | |
), | |
write('-------------------'), nl, | |
repl(S, AtomTags, World). | |
eval(History, AtomTags, World, World1) :- | |
nlp::resolve_pronouns(History, AtomTags, AtomTags1), | |
nlp::parse_atoms(AtomTags1, _, Commands), | |
eval_commands(Commands, World, World1). | |
eval_commands([], World, World). | |
eval_commands([C|Cs], World0, World) :- | |
write('The command is: '), write(C), nl, | |
eval_command(C, World0, World1), | |
eval_commands(Cs, World1, World). | |
eval_command(take-[Id], World0, World) :- | |
entity::action(update_current_room, [R0, R], World0, World1), | |
entity::action(update_player, [P0, P], World1, World), | |
entity::action(select_item, [identity_property-Id, Item], R0, R), | |
entity::action(add_item, [Item], P0, P). | |
eval_command(look-[], World, World) :- | |
entity::action(current_room, [Room], World, _), | |
write('You see: '), nl, | |
entity::action(print_children, [], Room, _). | |
eval_command(look-[inventory], World, World) :- | |
entity::action(get_player, [P], World, _), | |
write('Your inventory consists of: '), nl, | |
entity::action(print_children, [], P, _). | |
eval_command(open-[Id], World0, World) :- | |
entity::action(update_current_room, [Room0, Room], World0, World), | |
entity::action(update_item, [identity_property-Id, Door0, Door], | |
Room0, Room), | |
entity::action(open, [], Door0, Door). | |
eval_command(close-[Id], World0, World) :- | |
entity::action(update_current_room, [Room0, Room], World0, World), | |
entity::action(update_item, [identity_property-Id, Door0, Door], | |
Room0, Room), | |
entity::action(close, [], Door0, Door). | |
eval_command(C-[Id1, Id2], World0, World) :- | |
( C = lock | |
; C = unlock | |
), | |
entity::action(update_current_room, [Room0, Room], World0, World), | |
entity::action(get_player, [P], World, _), | |
entity::action(update_item, [identity_property-Id1, Door0, Door], | |
Room0, Room), | |
entity::action(get_item, [identity_property-Id2, Key], P, _), | |
entity::action(C, [Key], Door0, Door). | |
eval_command(move-[Id], World0, World) :- | |
entity::action(current_room, [Room], World0, _), | |
entity::action(update_player, [P0, P], World0, World), | |
entity::action(get_item, [identity_property-Id, Entrance], | |
Room, _), | |
entity::action(open, [], Entrance, _), | |
entity::action(get_location, [Location], Entrance, _), | |
entity::action(set_location, [Location], P0, P). | |
eval_command(eat-[Id], World0, World) :- | |
entity::action(update_player, [P0, P], World0, World), | |
entity::action(select_item, [identity_property-Id, Item], P0, P1), | |
entity::action(dissolve, [P1, P], Item, _). | |
:- end_object. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- op(900, fx, begin). | |
:- op(900, fx, end). | |
:- op(900, fx, $). | |
:- initialization(( | |
logtalk_load(library(metapredicates_loader)), | |
logtalk_load(library(types_loader)), | |
logtalk_load(entity), | |
logtalk_load(game_logic), | |
logtalk_load(builder), | |
logtalk_load(nlp), | |
logtalk_load(game), | |
logtalk_load(script_expansion), | |
logtalk_load(script_interpreter), | |
logtalk_load(example_game, [hook(script_expansion)]), | |
game::init(example_game))). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(script_expansion, | |
implements(expanding)). | |
term_expansion((begin _), []). | |
term_expansion((end _), []). | |
term_expansion((build(Type, Id, Description)), entity(E)) :- | |
builder::build(Type, Id, Description, E). | |
term_expansion((build(Type, Id)), entity(E)) :- | |
builder::build(Type, Id, E). | |
%% Just make the job slightly easier in the interpreter. | |
term_expansion((add_property(P, Id)), add_property(t(P, Id))). | |
term_expansion((action(M, Id1, Id2)), action(t(M, Id1, Id2))). | |
term_expansion((connect(Id1, Id2, Id3)), connect(t(Id1, Id2, Id3))). | |
:- end_object. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
:- object(script_interpreter). | |
:- public(interpret_game/2). | |
interpret_game(DB, World) :- | |
findall(E, DB::entity(E), Es0), | |
findall(P, DB::add_property(P), Ps), | |
findall(A, DB::action(A), As), | |
findall(C, DB::connect(C), Cs), | |
interpret_properties(Ps, Es0, Es1), | |
interpret_actions(As, Es1, Es2), | |
interpret_connectors(Cs, Es2, Es), | |
get_rooms(Es, Rooms), | |
get_player(Es, Player), | |
builder::build(world, world1, Rooms, Player, World). | |
%% Find the rooms that shall be part of the game map. This is a | |
%% hack since it means that no other objects than rooms can | |
%% have the property of being a container. To solve this we | |
%% could e.g. create a new property with the name | |
%% room_property. | |
get_rooms(Es, Rooms) :- | |
meta::include([E] >> | |
(entity::get_property(E, container_property-_)), | |
Es, | |
Rooms). | |
%% Yet another hack. We should really look for an entity that | |
%% has the player_property, and not assume that the player is | |
%% always named 'player'. | |
get_player(Es, Player) :- | |
list::member(Player, Es), | |
entity::get_property(Player, player_property-_). | |
interpret_properties([], Es, Es). | |
interpret_properties([t(P, Id)|Ps], Es0, Es) :- | |
select_entity(Id, Es0, E0, Es1), | |
P::new([], State), | |
entity::add_property(P-State, E0, E), | |
interpret_properties(Ps, [E|Es1], Es). | |
interpret_actions([], Es, Es). | |
interpret_actions([t(M, Id1, Id2)|As], Es0, Es) :- | |
select_entity(Id1, Es0, E0, Es1), | |
lookup_argument(Id2, Es0, Arg), | |
entity::action(M, [Arg], E0, E), | |
interpret_actions(As, [E|Es1], Es). | |
interpret_connectors([], Es, Es). | |
interpret_connectors([t(Id1, Id2, Id3)|Cs], Es0, Es) :- | |
select_entity(Id1, Es0, Room1, Es1), | |
select_entity(Id2, Es1, Room2, Es2), | |
select_entity(Id3, Es2, Door, Es3), | |
connect(Room1, Room2, Door, Room3, Room4), | |
interpret_connectors(Cs, [Room3, Room4|Es3], Es). | |
lookup_argument(Id, Es, Arg) :- | |
( Id = $(Symbol) -> | |
Arg = Symbol | |
; lookup_entity(Id, Es, Arg) | |
). | |
select_entity(Id, Es, E, Es1) :- | |
%% This is quite terrible and yet another reason why it would | |
%% be better to store the identity as a unique property! | |
list::select(E, Es, Es1), | |
entity::get_property(E, identity_property-Id). | |
lookup_entity(Id, Es, E) :- | |
%% This is quite terrible and yet another reason why it would | |
%% be better to store the identity as a unique property! | |
list::member(E, Es), | |
entity::get_property(E, identity_property-Id). | |
%% Connect Room1 with Room2 with Door. We don't have to return a | |
%% new door since it is contained in the rooms. | |
connect(Room1, Room2, Door, Room3, Room4) :- | |
entity::get_property(Room1, identity_property-Id1), | |
entity::get_property(Room2, identity_property-Id2), | |
entity::action(set_location, [Id2], Door, Door1), | |
entity::action(set_location, [Id1], Door, Door2), | |
entity::action(add_item, [Door1], Room1, Room3), | |
entity::action(add_item, [Door2], Room2, Room4). | |
:- end_object. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment