<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-6497377610042929535</id><updated>2008-04-30T12:38:16.676-04:00</updated><title type='text'>Joe's Landfill</title><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml'/><author><name>Joe Osborn</name></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-8467962807602666132</id><published>2008-04-29T09:00:00.000-04:00</published><updated>2008-04-29T09:01:07.619-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='thucydides'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Rock, Paper, Scissors</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Rewriting History series. Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; and &lt;a href="http://joe.garbagecollective.org/2008/03/rewriting-history.html"&gt;Rewriting History&lt;/a&gt; before proceeding.&lt;/p&gt;
  &lt;h2&gt;The challenge&lt;/h2&gt;
  &lt;p&gt;Show the causality features of Thucydides by designing a simulation that "runs itself" for a while after initial user interaction.  The simulation is a simple rock/paper/scissors military simulation in the style of &lt;a href="http://en.wikipedia.org/wiki/Fire_Emblem"&gt;Fire Emblem&lt;/a&gt;.  The player issues commands at the 0th hour of the day, and the enemy responds in kind.  The armies of the player and enemy clash hourly as long as daylight and their respective forces hold.  While I won't show the line-by-line Erlang code as before, I'll provide the &lt;a href="rps.erl"&gt;commented Erlang source code&lt;/a&gt; for the curious.&lt;/p&gt;
  &lt;h2&gt;A War of Attrition&lt;/h2&gt;
  &lt;p&gt;Since creating a full strategy game was beyond the scope of this exercise, I wanted to focus on two moderately tricky aspects:&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;Defining a fluent whose value is a function of its past value&lt;/li&gt;
   &lt;li&gt;Triggering events automatically&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;This essay will explore each in turn.  But first, the rules of the system must be described:&lt;/p&gt;
  &lt;ul&gt;
      &lt;li&gt;The player and enemy begin with the same number of troops in three categories: Swordsman, Spearman, and Axman.&lt;/li&gt;
      &lt;li&gt;The player's action at the beginning of each day is to choose how many of each type of unit to include in his advance for that day.  He is limited to 50 units per advance.&lt;/li&gt;
      &lt;li&gt;The enemy employs a psychic, but he is a poor strategist; so he'll send at you the worst possible counter to whatever you send at him, provided he has the troops available.&lt;/li&gt;
      &lt;li&gt;Once daylight comes (eight hours into the day), the two advances will meet and begin skirmishing.&lt;/li&gt;
      &lt;li&gt;The two forces will skirmish hourly until one or both sides drop, or until dusk falls.&lt;/li&gt;
      &lt;li&gt;Swords are strong against axes and weak against spears; axes are strong against spears and weak against swords; and spears are strong against swords and weak against axes.&lt;/li&gt;
      &lt;li&gt;Combat is resolved "simultaneously" — losses are not sustained until after the hour is over.&lt;/li&gt;
      &lt;li&gt;Units preferentially attack the units they're strong against, then their own unit type, then their weakness.&lt;/li&gt;
  &lt;/ul&gt;
&lt;a name="jump"&gt;&lt;/a&gt;
&lt;span class="fullpost"&gt;
  &lt;p&gt;Therefore, the units lost in an attack are both a function of one's own forces and the enemy's at the time of the attack.  Furthermore, losses occur simultaneously on both sides.  This complexity and interdependency has a significant consequence: There is a danger of mutually recursive fluent definitions.  Even if there's no infinite recursion, a trivial query might require massive fluent evaluation, as in this example of querying &lt;span class="fluent"&gt;{A, 2}&lt;/span&gt;:&lt;/p&gt;
  &lt;ol&gt;
   &lt;li&gt;Fluent A-0 queries {B, 0} and adds to it
   &lt;ol&gt;
    &lt;li&gt;Fluent B-0 returns a default value&lt;/li&gt;
   &lt;/ol&gt;
   &lt;/li&gt;
   &lt;li&gt;The result is added to: Fluent A-1 queries {B, 1} and adds to it
    &lt;ol&gt;
     &lt;li&gt;Fluent B-1 queries {A, 0} and adds to it
      &lt;ol&gt;
       &lt;li&gt;Fluent A-0 queries {B, 0} and adds to it
      &lt;ol&gt;
                          &lt;li&gt;Fluent B-0 returns a default value&lt;/li&gt;
      &lt;/ol&gt;
       &lt;/li&gt;
      &lt;/ol&gt;
     &lt;/li&gt;
    &lt;/ol&gt; 
   &lt;/li&gt;
   &lt;li&gt;The two results above are added to: Fluent A-2 queries {B, 2} and adds to it
  &lt;ol&gt;
   &lt;li&gt;Fluent B-2 queries {A, 1} and adds to it
    &lt;ol&gt;
     &lt;li&gt;Fluent A-1 queries {B, 1} and adds to it
      &lt;ol&gt;
         &lt;li&gt;Fluent B-1 queries {A, 0} and adds to it
          &lt;ol&gt;
           &lt;li&gt;Fluent A-0 queries {B, 0} and adds to it
            &lt;ol&gt;
             &lt;li&gt;Fluent B-0 returns a default value&lt;/li&gt;
            &lt;/ol&gt;
           &lt;/li&gt;
          &lt;/ol&gt;
         &lt;/li&gt;
        &lt;/ol&gt;
       &lt;/li&gt;
      &lt;/ol&gt;
     &lt;/li&gt;
    &lt;/ol&gt; 
   &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p&gt;While this might seem a problem solvable by some optimization or trick, those solutions are hacks — there's no way to support this generally.  Simulation designers must be wary of mutually dependent fluents like these.  There are two common solutions to this problem, and the correct one depends on your application:&lt;/p&gt;
  &lt;dl&gt;
   &lt;dt&gt;Introduce constants&lt;/dt&gt;
   &lt;dd&gt;Do the mutually dependent calculations in a separate History or in a function outside of Herodotus proper.  Then, create a new Fluent which, rather than calculating its value dynamically, returns a constant.  This is generally only usable if the past is immutable.&lt;/dd&gt;
   &lt;dt&gt;Combine fluents&lt;/dt&gt;
   &lt;dd&gt;Take the two (or more) mutually dependent Fluents and turn them into a single Fluent that returns the items' respective data.  One feature that might help is to use the arbitrary arguments feature to include an indicator of which data should be returned.  This is not always an applicable approach, but where it is usable it is very powerful.&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;p&gt;The latter approach was chosen for the RPS simulation because it is slightly harder to implement, and this simulation was designed to stress Herodotus/Thucydides.  All of the armies correspond to a single fluent selector, with losses being calculated for all three types on both sides in a single fluent which is triggered at each skirmish.&lt;/p&gt;
  &lt;h2&gt;Taking the (Battle)Field&lt;/h2&gt;
  &lt;p&gt;As in the other examples, we'll start by looking at nouns.  This simulation involves two &lt;span class="blank"&gt;Generals&lt;/span&gt; (the &lt;span class="filledblank"&gt;player&lt;/span&gt; and the &lt;span class="filledblank"&gt;enemy&lt;/span&gt;) and &lt;span class="filledblank"&gt;Armies&lt;/span&gt;, along with &lt;span class="filledblank"&gt;Daylight&lt;/span&gt;.  It's also important to track the time of the last &lt;span class="filledblank"&gt;Skirmish&lt;/span&gt;.  Finally, the armies have locations: in the &lt;span class="filledblank"&gt;Reserve&lt;/span&gt;, away from the battle; in the &lt;span class="filledblank"&gt;Field&lt;/span&gt;, at combat with the enemy; and in &lt;span class="filledblank"&gt;Transit&lt;/span&gt;, on the way there.&lt;/p&gt;
  &lt;p&gt;The last thing to consider is the set of verbs: advances, withdrawals, and skirmishes.  If skirmishes happen hourly, we'll want to track the time of the last skirmish; and if we want to prevent skirmishing during a withdrawal, we should note withdrawals when they happen.&lt;/p&gt;
  &lt;p&gt;The armies are expressed in a single Fluent, stored in one big list in the following way:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
[{General1Name, 
    [{UnitType1, count}, {UnitType2, count}, ...]
  }, 
 {General2Name, 
    [{UnitType1, count}, ...]
  },
  ...]&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;So, the fluent that sets up the armies looks like this:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
f init_armies:
&lt;span class="comment"&gt;%We'll express the place nouns as fluent types&lt;/span&gt;
  type reserve.
&lt;span class="comment"&gt;%Grab the army definition from the bindings&lt;/span&gt;
  value Armies.
&lt;span class="comment"&gt;%Use a special function to combine army values&lt;/span&gt;
  combine rps:add_armies(Net, Value).&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;We use &lt;code&gt;rps:add_armies&lt;/code&gt; because it handles all kinds of cases where the Net or the Value are undefined, where one or the other is a tuple and not a list, and so on.  &lt;code&gt;rps:add_armies&lt;/code&gt; is provided by the &lt;code&gt;rps.erl&lt;/code&gt; module, which the simulation writer provided alongside the &lt;code&gt;.tsdl&lt;/code&gt; file.  Thucydides clients (either remote or local) can supply arbitrary extra Erlang modules that are made available to &lt;code&gt;.hql&lt;/code&gt; and &lt;code&gt;.tsdl&lt;/code&gt; files.  It's up to a Thucydides provider to ensure that these are safe to execute.&lt;/p&gt;
  &lt;p&gt;The rest of the incident used to initialize the armies and the rest of the simulation follows:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
f initial_generals:
&lt;span class="comment"&gt;%"generals" as a fluent type is the list of generals in the fight&lt;/span&gt;
  type generals.
&lt;span class="comment"&gt;%capital-G Generals is a constant list defined in the bindings
%of the incident triggering this fluent.&lt;/span&gt;
  value Generals.

&lt;span class="comment"&gt;%field and transit are the other two army locations&lt;/span&gt;
f empty_places:
  type [field, transit].
&lt;span class="comment"&gt;%Of course erlang funs work in tsdl.&lt;/span&gt;
&lt;span class="comment"&gt;%This makes one empty army for each general in the bindings.&lt;/span&gt;
  value lists:map(fun(G) -&gt;
      {G, [{swords, 0}, {spears, 0}, {axes, 0}]}
    end, Generals)
  .

&lt;span class="comment"&gt;%"withdrawing" marks whether the given general is withdrawing.&lt;/span&gt;
f none_withdrawing:
  type {withdrawing, Generals}.
&lt;span class="comment"&gt;%"persist persist." can be abbreviated like so:&lt;/span&gt;
  persist.
  value false.

&lt;span class="comment"&gt;%"last_skirmish" marks the last time the given two generals sparred.&lt;/span&gt;
f no_prior_skirmish:
  type {last_skirmish, Generals, Generals}.
  persist.
&lt;span class="comment"&gt;%-24 just means "yesterday, before all this started".&lt;/span&gt;
  value -24.

&lt;span class="comment"&gt;%daylight is the current brightness of the battlefield&lt;/span&gt;
f daylight:
  type daylight.
&lt;span class="comment"&gt;%bring a 24-hour value into the 0 to 1 range
%0 means "pitch black"
%1 means "high noon"&lt;/span&gt;
  value (12 - abs(12 - (trunc(Now) rem 24))) / 12.0.

i init_rps(Generals, Armies):
&lt;span class="comment"&gt;%definitions can take lists like these, too!&lt;/span&gt;
  set [init_armies, initial_generals, empty_places,
       none_withdrawing, no_prior_skirmish, daylight].&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Triggering this initialization incident will look something like this to a local client (if the Thucydides process is called rps_sim):&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
Bindings = dict:store(
  "Armies",
  [{player, [{swords, 30}, {spears, 30}, {axes, 30}]},
   {enemy,  [{swords, 30}, {spears, 30}, {axes, 30}]}],
    dict:store(
    "Generals", 
    [player, enemy], 
    dict:new()
  )
),
thucydides:trigger(init_rps, Now, Bindings, rps_sim)&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;For a remote client, the same information is passed, but the dictionary specification is a little different.&lt;/p&gt;
  &lt;h2&gt;Advance Wars&lt;/h2&gt;
  &lt;p&gt;In the remainder of this blog post, we'll look at two uses of the "follow" semantic mentioned in the previous post.  A "follow" is a causal linkage from zero or more incidents and conditions to one or more incidents.  The structure of a follow is:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
follow a_follows_b_or_c_after_5_when_d:&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;These are (optional) "input event archetypes".  When these happen, this is triggered.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  in [b,c]&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Optionally, you can include requirements as in incident archetypes.  If these don't hold, it doesn't trigger, and the follow will try repeatedly to check them as time goes on.  Of course, there's no need to duplicate incident archetype preconditions.  The follow will keep trying until it meets the preconditions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  require d&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;The follow starts trying to trigger after the "delay" parameter, which defaults to "delay 0."&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  delay 5&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;It tries for a number of time units specified by the "duration" parameter, but will only happen once for each triggering incident.  If the conditions aren't met by the time (trigger_time + delay + duration), the trigger fails and the output events don't occur.  Duration defaults to "duration 0", meaning it will try only once.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  duration 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Out is a list of output incidents.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  out [a]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bindings are seeded based on the input archetype, if any.  After this seeding, they're run through the binder functions one at a time.  If all the bindings are defined by the time the binder functions are done, the requirements are checked and so on.  If there is no input archetype, the binder functions alone are used.  A binder function returns a list of {VarName(a string), [PossibleBindings]}.  Binder functions are called in-order and each is given all permutations of the possible bindings for the previous binder.  Bindings are referred to in the same way as requirements, etc.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  bind get_a_bindings.&lt;/pre&gt;&lt;/code&gt;
&lt;p&gt;Here's an inline binding function.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  bind get_more_a_bindings:
    FavoriteFood = q({{favorite_food, BPerson}, Time}),
    [{"FavoriteFood", [FavoriteFood]}]
    .&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;Let's presume that "advance" is an incident archetype with bindings for the &lt;var&gt;General&lt;/var&gt;, the number of Swordsmen (&lt;var&gt;NSw&lt;/var&gt;), the number of Spearmen (&lt;var&gt;NSp&lt;/var&gt;), and the number of Axmen (&lt;var&gt;NAx&lt;/var&gt;).  If a follow is defined in this way, we can express "the enemy advances as soon as the player advances" like this:&lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;
follow enemy_advance_follows_player_advance:
  in [advance].
  out [advance].
  bind new_army:
    EnemyNSw = NSp,
    EnemyNSp = NAx,
    EnemyNAx = NSw,
&lt;span class="comment"&gt;%"enemy" is hardcoded here, but it could certainly
%be the result of a fluent query or something.&lt;/span&gt;
    [{"General", [enemy]}, 
     {"OldGeneral", [General]}, 
     {"NSw", [EnemyNSw]}, 
     {"NSp", [EnemyNSp]}, 
     {"NAx", [EnemyNAx]}]
  .
  require advancer_is_player:
    check OldGeneral =:= player.
  require enemy_hasnt_advanced:
    type [transit, field].
    check 
      lists:all(fun({_, Amt}) -&gt;
        Amt =:= 0
      end, units(General, _Val))
    .&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Now, as soon as the client code triggers a player advance, the enemy advance will trigger automatically.  This works for instantaneous triggers, but what about delayed triggers?  For these, Thucydides's conception of time must come into play.&lt;/p&gt;
  &lt;p&gt;Thucydides stores the "current time" automatically, and can be asked for what it thinks the current time is.  The message "progress_time" can be sent to a Thucydides process remotely or locally.  This message takes a time delta and the resolution by which to step towards it ("progress_time_to" takes a destination time).  Thucydides does no interpolation; such interpolation could be costly since fluents can contain arbitrary code.  During progress_time, various follows might be triggered, and the result of the message is the list of incidents that were triggered during that time.  Here's an example:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%The time argument can be left out(it will use the current time)
%and so can the bindings, if they're empty.&lt;/span&gt;
thucydides:trigger(my_arc, my_sim),
&lt;span class="comment"&gt;%The default resolution is 1.0, but any number can be used&lt;/span&gt;
thucydides:progress_time(5, my_sim).&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;A more complicated case of following is our rule for saying that a skirmish happens whenever the two armies meet on the field.  We need to be careful here to prevent an unnecessary number of skirmishes.  This problem of potential duplicate skirmishes is why we introduced the "last_skirmish" fluent above (which is set to Time whenever a skirmish occurs) and the follow that expresses this case looks like this:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
follow skirmish_when_armies_meet:
  out [skirmish].
  require last_skirmish_yesterday:
    type {last_skirmish, [Attacker, Defender]}.
&lt;span class="comment"&gt;%'div' is integer division.  TSDL will automatically
%truncate both arguments.  In this case, we want to make sure that the
%previous skirmish was yesterday or earlier.&lt;/span&gt;
    check (Value div 24) &lt; (Time div 24).
&lt;span class="comment"&gt;%Follows with no input incidents should probably
%use infinite duration, otherwise they'll stop being checked
%and never start being checked again.&lt;/span&gt;
  duration infinity.
  bind all_general_combinations:
&lt;span class="comment"&gt;%Here's another invocation of a custom erlang function.&lt;/span&gt;
    {Atks, Defs} = 
      rps_lists:unzipped_combinations(q({generals, Time})),
    [{"Attacker", Atks}, {"Defender", Defs}]
  .&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;There's more to this simulation, including rules for skirmishes following other skirmishes after an hour, and withdrawals of each side occurring when one or both sides is defeated, or night falls.&lt;/p&gt;
  &lt;h2&gt;Moving On&lt;/h2&gt;
  &lt;p&gt;This ends the Rewriting History series of essays.  The switch to Erlang has empowered Herodotus, and the introduction of HQL/TSDL has empowered its users.  Many semantic changes have been made: matching is entirely new, follows have been introduced, and simulations now have a concept of the progression of time.  Thucydides can be used in whole or in part (with or without follows).  Two simulations have been written in Thucydides.&lt;/p&gt;
  &lt;p&gt;The next series of essays will discuss the development of a small web-based game that will take advantage of Herodotus's unique features.  In this game, the user will play as a Seer, using his supernatural powers to help or harm various political bodies by dispatching parties of heroes to fulfill or prevent prophecies, or to preserve or disrupt previous incidents.  The strengths of Herodotus will be shown in three ways: player planning will be based on past and possible future events; memories of party and Seer exploits will be held by NPCs; and the events chosen for the future will be a function of the ways that the player has acted and chosen in the past.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/04/rock-paper-scissors.html' title='Rock, Paper, Scissors'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=8467962807602666132' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/8467962807602666132'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/8467962807602666132'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-5941186789358090670</id><published>2008-04-24T23:35:00.002-04:00</published><updated>2008-04-30T12:35:17.488-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='thucydides'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Stepping Forward</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Rewriting History series. Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; and &lt;a href="http://joe.garbagecollective.org/2008/03/rewriting-history.html"&gt;Rewriting History&lt;/a&gt; before proceeding.  This is also a followup to &lt;a href="http://joe.garbagecollective.org/2008/04/stepping-back.html"&gt;Stepping Back&lt;/a&gt;&lt;/p&gt;
  &lt;h2&gt;The Challenge&lt;/h2&gt;
  &lt;p&gt;Create the Thucydides Simulation Definition Language, or TSDL: A language for defining Fluents, Cancels, and Incidents in their archetypal form, along with causal relationships between these archetypes.  Incident archetypes defined in such a way should be applicable to a Herodotus history via a Thucydides simulation.  This essay will pay special attention to the TADL subset, which doesn't include the aforementioned causal relationships support.&lt;/p&gt;
  &lt;h2&gt;Lingua Franca&lt;/h2&gt;
  &lt;p&gt;To recap, an Incident is a container for some Fluents and some Cancels, occurring at some time, with a given set of bindings.  It also has a "type".  Its archetype provides functions for defining some of these dynamically.  The way this looks in Herodotus is something like:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
FluentArcs = [Full, Poorer],
CancelArcs = [CancelDiets],
Requirements = [ReqEnoughMoney],
I = i_arc:new(
  eat_feast,
  main,
  FluentArcs,
  ["Owner", "MealCost"],
  [Requirements],
  [],&lt;span class="comment"&gt;%no extra input selectors&lt;/span&gt;
  CancelArcs
)&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;This isn't wholly unpleasant, but defining Fluents sort of is:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
Full = ?A_FLUENT(
  {me, hunger},
  _Time,
  _Time + 6, &lt;span class="comment"&gt;%I'm hungry four hours later&lt;/span&gt;
  1.0,
  (_Now - _Time) / 6.0,
  lists:max([0.0, _Net - _Value])
),
Tired = ?A_FLUENT(
  ... %more like the above
),
Happy = ?A_FLUENT(
  ... %more like the above
)&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;The irksome things about this &lt;code&gt;?A_FLUENT&lt;/code&gt; macro are that it's specific to the Erlang implementation, that it's order-dependent, and that it's ugly.  Let's try and find a way around using it and the other macros, and make it more readable in the process.&lt;/p&gt;
   &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%this defines a fluent "full", which decreases "hunger".&lt;/span&gt;
&lt;span class="comment"&gt;%We'll assume that hunger goes from 0 to 1 and is completely&lt;/span&gt;
&lt;span class="comment"&gt;%removed by the consumption of food.&lt;/span&gt;
&lt;span class="comment"&gt;%if this took an argument, it would be f full(Arg1, Arg2...)&lt;/span&gt;
f full:
&lt;span class="comment"&gt;%this is the fluent type.&lt;/span&gt;
&lt;span class="comment"&gt;%it gets the "Owner" variable from the bindings of the archetype&lt;/span&gt;
&lt;span class="comment"&gt;%in which it's triggered&lt;/span&gt;
  type {hunger, Owner}.
&lt;span class="comment"&gt;%it starts immediately, so the "start" line is omitted.&lt;/span&gt;
&lt;span class="comment"&gt;%it defaults to "start Time."&lt;/span&gt;
&lt;span class="comment"&gt;%it ends effectiveness in six hours. this could default to "end infinity."&lt;/span&gt;
  end Time + 6.
&lt;span class="comment"&gt;%it persists as 1.0. this could default to "persist undefined."&lt;/span&gt;
  persist 1.0.
&lt;span class="comment"&gt;%and its value is the portion remaining of the food at the given time.&lt;/span&gt;
&lt;span class="comment"&gt;%The default is "value true."&lt;/span&gt;
  value 
    (Now - Time) / 6.0
  .
&lt;span class="comment"&gt;%it combines by clipping Net - Value to [0, 1].&lt;/span&gt;
&lt;span class="comment"&gt;%the default is "combine Value."&lt;/span&gt;
  combine 
    lists:Max([0.0, Net - Value])
  .&lt;/code&gt;&lt;/pre&gt;
  &lt;span class="fullpost"&gt;&lt;a name="jump"&gt;&lt;/a&gt;
  &lt;p&gt;Note especially that the ugly &lt;var&gt;_&lt;/var&gt; variables are gone, bindings can be accessed just as if they were variables, and the syntax is a little cleaner overall.  Even better, a lot of the definition can be omitted in the common case.  Let's show another fluent, which reduces the money in the Owner's bank account:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
f poorer:
  type {money, Owner}.
  value
    MealCost
  .
  combine:
    Net - Value
  .&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Next, we'll examine the "cancel search", which finds a set of fluents and cancels them.  This is provided so that incident archetypes can cancel fluents without necessarily knowing exactly which ones they'll need to cancel beforehand.&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%c defines a cancel search
%which detects fluents and
%generates cancels for them.
%in this case, we cancel any diets the Owner is on.&lt;/span&gt;
c cancel_diet:
&lt;span class="comment"&gt;%this binding also comes from the enclosing incident.&lt;/span&gt;
  type {diet, Owner}.
&lt;span class="comment"&gt;%"start 0." and "end Time." are the default values,
%so we can omit them.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;A mere two lines, much reduced from the original.&lt;/p&gt;
  &lt;p&gt;Requirements are another feature provided by Thucydides:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%r defines a requirement - in this case, the Owner
%must have enough money to buy the feast&lt;/span&gt;
r req_money_for_feast:
&lt;span class="comment"&gt;%a "history main." line could be added here, but it's the default
%this gets bindings too.&lt;/span&gt;
  type {money, Owner}.
&lt;span class="comment"&gt;%"start 0." and "end Time." are the defaults.&lt;/span&gt;
&lt;span class="comment"&gt;%There could be an "args []." line in here, but we omit it
%since the list is empty.
%check is the value-checking function; it gets bindings, too.
%the default check function is "check Value == true."
%it's worth mentioning that type, start, and end will all be omitted,
%in which case only the check function will be used.  This is generally
%used to verify properties of the Bindings.&lt;/span&gt;
  check Value &gt; MealCost.&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;This is a sight better than a six-argument &lt;code&gt;?REQ&lt;/code&gt; macro, surely!&lt;/p&gt;
  &lt;p&gt;The next feature we'll examine is the final element in the TADL subset of TSDL, the Incident Archetype:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%this is an incident archetype definition&lt;/span&gt;
i eat_feast(Owner, MealCost): 
&lt;span class="comment"&gt;%We could say "histories [main].", but that's the default.
%refer to previously defined f_arc "full"&lt;/span&gt;
  set full.
  set poorer.
&lt;span class="comment"&gt;%we could define a new fluent inline with "set new_fluent(Arg): ... end.",
%then defining a fluent as above.
%refer to previously defined cancel&lt;/span&gt;
  cancel cancel_diet.
&lt;span class="comment"&gt;%cancels can be defined inline too: "cancel unwanted_fluents: ... end."
%refer to previously defined req&lt;/span&gt;
  require req_money_for_feast.
&lt;span class="comment"&gt;%requirements can be inline too: "require important_req: ... end."&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;This lightning tour of TSDL syntax bears some explaining.  The basic element of TSDL is the "definition", which can be one of seven types:&lt;/p&gt;
  &lt;dl&gt;
   &lt;dt&gt;q&lt;/dt&gt;
   &lt;dd&gt;An HQL query, just like in a .HQL file.&lt;/dd&gt;
   &lt;dt&gt;f&lt;/dt&gt;
   &lt;dd&gt;A fluent archetype&lt;/dd&gt;
   &lt;dt&gt;c&lt;/dt&gt;
   &lt;dd&gt;A cancel search&lt;/dd&gt;
   &lt;dt&gt;r&lt;/dt&gt;
   &lt;dd&gt;A requirement&lt;/dd&gt;
   &lt;dt&gt;i&lt;/dt&gt;
   &lt;dd&gt;An incident archetype&lt;/dd&gt;
   &lt;dt&gt;b&lt;/dt&gt;
   &lt;dd&gt;A binder function&lt;/dd&gt;
   &lt;dt&gt;follow&lt;/dt&gt;
   &lt;dd&gt;A follow definition&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;p&gt;We haven't looked at &lt;code&gt;binder&lt;/code&gt;s and &lt;code&gt;follow&lt;/code&gt;s yet, but each definition has roughly the same form:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
type name(arguments, if applicable):
  parameter value.
  ...
  subdefinition name(arguments, if applicable):
    subdef-param value.
    ...
  end.
  parameter value.
  ...&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;The distinction between parameters and definitions is straightforward: the former begin immediately and end with a period, and the latter begin after a colon and end automatically (or, in the case of inlined definitions of types &lt;var&gt;f&lt;/var&gt;, &lt;var&gt;c&lt;/var&gt;, or &lt;var&gt;r&lt;/var&gt;, with an &lt;code&gt;end.&lt;/code&gt; tag.  The end tag can be omitted for the other types when inlined).  Sub-definitions can be nested.&lt;/p&gt;
  &lt;p&gt;The other thing to note is that virtually all of the &lt;code&gt;parameter&lt;/code&gt;s take  functions of &lt;code&gt;(&lt;var&gt;Time&lt;/var&gt;, &lt;var&gt;Bindings&lt;/var&gt;)&lt;/code&gt; as their arguments.&lt;/p&gt;
  &lt;p&gt;Since the definition of &lt;code&gt;binder&lt;/code&gt;s and &lt;code&gt;follow&lt;/code&gt;s have various semantic consequences, we'll leave the discussion of TSDL there for today.&lt;/p&gt;
  &lt;h2&gt;Trigger Happy&lt;/h2&gt;
  &lt;p&gt;Actually triggering incident archetypes, given bindings and time, is done by &lt;code&gt;thucydides:trigger()&lt;/code&gt; in the local client interface and a similar message in the remote client interface.  Triggering an incident also checks the requirements and triggers any incidents that might follow it at that particular time.  Trigger can return three values:&lt;/p&gt;
  &lt;dl&gt;
   &lt;dt&gt;not_met&lt;/dt&gt;
   &lt;dd&gt;The requirements for this incident aren't met at the given time.&lt;/dd&gt;
   &lt;dt&gt;paradox&lt;/dt&gt;
   &lt;dd&gt;Triggering this incident is incompatible with the future state of the world, and would cause a paradox.  It isn't triggered.&lt;/dd&gt;
   &lt;dt&gt;{ok, TriggeredIncidents}&lt;/dt&gt;
   &lt;dd&gt;&lt;var&gt;TriggeredIncidents&lt;/var&gt; is the list of incidents that were triggered as a result of triggering the given incident; this can happen if a follow is set up to immediately react to an incident.  Follows will be described in a forthcoming article.&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;p&gt;Hopefully, TSDL reads more plainly than raw Erlang, even though it incorporates some Erlang syntax.  If there are any questions, please e-mail me or leave a comment below.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/04/stepping-forward.html' title='Stepping Forward'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=5941186789358090670' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/5941186789358090670'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/5941186789358090670'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-6852824087334831852</id><published>2008-04-21T11:27:00.007-04:00</published><updated>2008-04-30T12:35:35.683-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Stepping Back</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Rewriting History series. Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; and &lt;a href="http://joe.garbagecollective.org/2008/03/rewriting-history.html"&gt;Rewriting History&lt;/a&gt; before proceeding.&lt;/p&gt;
  &lt;h2&gt;The Challenge&lt;/h2&gt;
  &lt;p&gt;Start moving towards Herodotus-qua-platform.  Quit focusing so much on Erlang source code.  The last essay was too Erlang-centric, whereas Herodotus and Thucydides are meant to be platforms themselves.  Therefore, I'll be moving to a new notation for this essay, and hopefully it will hold.&lt;/p&gt;
  &lt;h2&gt;The Changes&lt;/h2&gt;
  &lt;p&gt;Before going on to the syntax, I'd like to explain some recent changes to the semantics.  In the development of the &lt;a href="http://joe.garbagecollective.org/2008/04/rock-paper-scissors"&gt;RPS military simulation&lt;/a&gt;, I encountered some semantic knots of Herodotus that I thought were worth untangling.  Mainly, I looked to simplify, improve, and more completely define the matching rules.&lt;/p&gt;
  &lt;h2&gt;A Match Made in Heaven&lt;/h2&gt;
  &lt;p&gt;The new matching rules are much more strongly defined, and are described below.  The match selector is represented by &lt;var&gt;Try&lt;/var&gt; and the value to check against by &lt;var&gt;Value&lt;/var&gt;.&lt;/p&gt;
  &lt;dl&gt;
   &lt;dt&gt;Atoms&lt;/dt&gt;
   &lt;dd&gt;Atoms are indivisible, distinct values, like symbols in Smalltalk or atoms in Lisp.  Numbers are also treated as atoms.  They are written as &lt;span class="catom"&gt;atom_name&lt;/span&gt;.  They match against the three types in the following ways:
   &lt;dl&gt;
    &lt;dt&gt;Atoms&lt;/dt&gt;
    &lt;dd&gt;&lt;var&gt;Try&lt;/var&gt; == &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
    &lt;dt&gt;Tuples&lt;/dt&gt;
    &lt;dd&gt;&lt;var&gt;Try&lt;/var&gt; matches some &lt;var&gt;V&lt;/var&gt; in &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
    &lt;dt&gt;Lists&lt;/dt&gt;
    &lt;dd&gt;&lt;var&gt;Try&lt;/var&gt; matches some &lt;var&gt;V&lt;/var&gt; in &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
   &lt;/dl&gt;&lt;/dd&gt;
   &lt;dt&gt;Tuples&lt;/dt&gt;
   &lt;dd&gt;Tuples are simple data structures.  They are written as &lt;span class="ctuple"&gt;{el1, el2, el3}&lt;/span&gt; and any element type can be placed in them.  Their meaning is roughly "all", and they match against the three types in the following ways:
   &lt;dl&gt;
    &lt;dt&gt;Atoms&lt;/dt&gt;
    &lt;dd&gt;Some &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; matches &lt;var&gt;Value&lt;/var&gt;.  This is a minor exception, but it's there for convenience.  The other possible behavior is virtually useless.&lt;/dd&gt;
    &lt;dt&gt;Tuples&lt;/dt&gt;
    &lt;dd&gt;All &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; match &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
    &lt;dt&gt;Lists&lt;/dt&gt;
    &lt;dd&gt;All &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; match &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
   &lt;/dl&gt;&lt;/dd&gt;
   &lt;dt&gt;Lists&lt;/dt&gt;
   &lt;dd&gt;Lists are sequences of values.  They are written as &lt;span class="clist"&gt;[el1, el2, el3]&lt;/span&gt; and any element type can be placed in them.  Their meaning is roughly "any", and they match against the three types in the following ways:
   &lt;dl&gt;
    &lt;dt&gt;Atoms&lt;/dt&gt;
    &lt;dd&gt;Some &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; matches &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
    &lt;dt&gt;Tuples&lt;/dt&gt;
    &lt;dd&gt;Some &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; matches &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
    &lt;dt&gt;Lists&lt;/dt&gt;
    &lt;dd&gt;Some &lt;var&gt;T&lt;/var&gt; in &lt;var&gt;Try&lt;/var&gt; matches &lt;var&gt;Value&lt;/var&gt;&lt;/dd&gt;
   &lt;/dl&gt;&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;p&gt;These new matching rules have two interesting consequences:&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;There's no longer any reason to distinguish between type and context.  There is now only "context".&lt;/li&gt;
   &lt;li&gt;Simulation designers have much more control over context definition and selection.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;In short, it allowed me to simplify and more easily explain the matching rules, remove a fair amount of closely similar code, reduced the amount of work to be done by a simulation designer in the simple case, and permitted much more complex and interesting queries and definitions at a stroke.&lt;/p&gt;
  &lt;p&gt;This semantic change is the most significant improvement since the shift to Herodotus/Erlang.&lt;/p&gt;
  &lt;h2&gt;Just Cause&lt;/h2&gt;
  &lt;p&gt;Another semantic addition to the tools available in Herodotus/Thucydides is the concept of causality.  A "Follow" is a simulation construct which describes cases where one or more incident archetypes can be triggered based on specific previously triggered archetypes, one or more conditions, or both.  A Follow also describes how bindings are obtained for the incident to be triggered and the requirements to be checked.  Finally, a Follow encodes some information about when it begins checking said conditions, and for how many units of time.&lt;/p&gt;
  &lt;p&gt;The semantic of Following is slightly more complex than the above lets on, but this understanding is sufficient to be able to talk about it.  Another feature implemented alongside Follows is time.  Simulations now maintain a "current time" which can be ticked forward by clients to arbitrary points at arbitrary resolution.  Backwards ticking and Follows have not been thoroughly tested and, frankly, the semantic is unclear.  I recommend against combining Follows with time travel.  If a simulation has need of such a feature, it can be implemented in Herodotus client code.&lt;/p&gt;
  &lt;h2&gt;Syntactically Delicious&lt;/h2&gt;
  &lt;p&gt;What the above semantics, along with past work, indicate is that any syntax for Herodotus must include the following:&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;Fluent selection and querying&lt;/li&gt;
   &lt;li&gt;Reasonable operations over dicts, tuples, lists, atoms, and numbers&lt;/li&gt;
   &lt;li&gt;Fluents, including optional arguments&lt;/li&gt;
   &lt;li&gt;Cancels&lt;/li&gt;
   &lt;li&gt;Incidents&lt;/li&gt;
   &lt;li&gt;History selection&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;And any syntax which expresses Thucydides must cover the above, plus:&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;Fluent archetypes&lt;/li&gt;
   &lt;li&gt;Incident requirements&lt;/li&gt;
   &lt;li&gt;Incident archetypes&lt;/li&gt;
   &lt;li&gt;Follows, including binder syntax&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;So, let's split the work into defining two small, specific languages:&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;Herodotus Query Language (HQL)&lt;/li&gt;
   &lt;li&gt;Thucydides Simulation Definition Language (TSDL)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Further, we'll posit that a set of simple operations on dictionaries, tuples, lists, atoms, and numbers is available to all of those languages.&lt;/p&gt;
  &lt;p&gt;The rationale for splitting the grammar this way is that HQL is meant to be used not just within a simulation or fluent definition, but also independently by client code, and the TSDL is how a client defines a simulation with archetypes, requirements, causality rules, &amp;c.  Certainly, a subset of TSDL could be defined which only considers archetypes; this can be called TADL, or Thucydides Archetype Definition Language, and would be useful to client code that doesn't wish to use Thucydides's causality mechanisms.  Since Erlang is a little obtuse to the unfamiliar, a set of small, specialized domain-specific languages will be introduced.&lt;/p&gt;
&lt;a name="jump"&gt;&lt;/a&gt;
&lt;span class="fullpost"&gt;
  &lt;p&gt;One more note before continuing on: There is a case where client code might want to use Herodotus directly, ignoring Thucydides outright.  However, this is really only useful for local clients (which will be explained below).  Even in their case, they will likely make use of Thucydides's incident archetype indexing and triggering mechanisms; so there's no reason to have a Herodotus Incident Definition Language apart from TADL/TSDL.&lt;/p&gt;
  &lt;h2&gt;Herodotus Query Language&lt;/h2&gt;
  &lt;p&gt;The goal of Herodotus Query Language is to provide a compact syntax for defining queries and operations on the results of queries.  It has an additional goal of being easy to read and easy to implement.  Initially I had thought of a syntax like this:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
history-name fluent-type start end args
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Like that, separated by spaces, where &lt;var&gt;history-name&lt;/var&gt; is an optional atom, defaulting to "main"; &lt;var&gt;fluent-type&lt;/var&gt; is an atom, a list of &lt;var&gt;fluent-type&lt;/var&gt;s, or a tuple of &lt;var&gt;fluent-type&lt;/var&gt;s; start is an optional number, defaulting to zero; end is a number; and args is an optional list of arguments, defaulting to the empty list.  Unfortunately, this syntax has some problems: it's not especially compact or easy to read, it's too whitespace-sensitive, and it's not obvious how to perform complex expressions.  With a little thinking, I came up with this compact form:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
history-name:fluent-type@start--end&amp;args
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;This replaced spaces with symbols, but it still wasn't satisfying because its syntax was so weird.  In the end, I decided to go with a subset of Erlang's syntax:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
q(history_name, {fluent_type, start, end}, args)
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;With the same optional values as mentioned above.  The advantage of this syntax is obvious in this example which finds the net worth of a person named Bill:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
NetWorth = q({{value, q({{assets, bill}, 10})}, 10})
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;This compound query can be passed in at-once.  To explain: the inner query &lt;code&gt;q({{assets, bill}, 10})&lt;/code&gt; gives the list of item identifiers in the possession of bill at time 10.  The outer query finds the &lt;code&gt;value&lt;/code&gt; of all of those item identifiers at time 10.  This kind of combination of queries is possible with this third syntax, which also lends itself more readily to variable binding and pattern matching.&lt;/p&gt;
  &lt;p&gt;Herodotus client code comes in two flavors: Local clients and remote clients.  Local clients run their own embedded Herodotus process; remote clients connect to a Herodotus server.  A local client is written in or bridged to Erlang, and can dynamically create and trigger arbitrary queries.  But a remote client can be written in any language, and has to limit these abilities for security reasons.  Therefore, HQL statements can be prepared beforehand:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;%in local client code:&lt;/span&gt;
hql:s(stored_query_1, fun() -&gt;
&lt;span class="comment"&gt;  %...hql statements...&lt;/span&gt;
end)

hql:s(stored_query_2, fun(Arg1, Arg2) -&gt;
&lt;span class="comment"&gt;  %...hql statements...&lt;/span&gt;
end)

&lt;span class="comment"&gt;%or in a .hql file for local or remote clients:&lt;/span&gt;
stored_query_1():
&lt;span class="comment"&gt;  %...hql statements...&lt;/span&gt;
  .

stored_query_2(Arg1, Arg2):
&lt;span class="comment"&gt;  %...hql statements...&lt;/span&gt;
  .
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Queries stored in such a way are triggered with:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;
q(stored_query_name, args)
  &lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Where args is a list.  The usage of HQL files for remote clients means that Herodotus server admins can vet the queries that are to be made and ensure that nothing damaging or harmful will be done.  Hooks will also be provided to allow some automatic security auditing of HQL queries.&lt;/p&gt;
  &lt;p&gt;A final note to make on HQL is how HQL queries are invoked.  In local client code, they're wrapped in an &lt;code&gt;hql:e()&lt;/code&gt; function call, which itself takes a &lt;code&gt;fun&lt;/code&gt; as argument.  This is similar to Mnesia's transaction function.  In remote client code, stored HQL queries are invoked by remote messages.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/04/stepping-back.html' title='Stepping Back'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=6852824087334831852' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/6852824087334831852'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/6852824087334831852'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-3146562193994296269</id><published>2008-03-11T18:20:00.003-04:00</published><updated>2008-03-17T14:18:38.997-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='thucydides'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Homage à Jones</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Rewriting History series. Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; and &lt;a href="http://joe.garbagecollective.org/2008/03/rewriting-history.html"&gt;Rewriting History&lt;/a&gt; before proceeding.&lt;/p&gt;
  &lt;h2&gt;The challenge&lt;/h2&gt;
  &lt;p&gt;Use a simple text-based adventure puzzle to show the basics of Thucydides.  The player will be the only actor of import in this world, and there will be a one to one correspondence between player actions and historical events.  This game will showcase two features of Thucydides:  Archetypes and Requirements.&lt;/p&gt;
  &lt;p&gt;The puzzle is trivial: The player starts in a treasure room, with a valuable statue on a pressure plate.  If the statue is removed, the exit will close immediately.  There is also a statue-shaped rock in the room.  The player must escape the room with the statue in hand.  The actions available to the player are:&lt;/p&gt;
  &lt;ul&gt;
      &lt;li&gt;&lt;span class="command"&gt;look&lt;/span&gt;&lt;/li&gt;
      &lt;li&gt;&lt;span class="command"&gt;leave&lt;/span&gt; when the door is open&lt;/li&gt;
      &lt;li&gt;&lt;span class="command"&gt;take &lt;span class="blank"&gt;item&lt;/span&gt;&lt;/span&gt; when the named item is on the floor and the player's hands are free&lt;/li&gt;
      &lt;li&gt;&lt;span class="command"&gt;lift&lt;/span&gt; when an item is on the pressure plate and the player's hands are free&lt;/li&gt;
      &lt;li&gt;&lt;span class="command"&gt;drop&lt;/span&gt; (to the floor) when the player is holding something&lt;/li&gt;
      &lt;li&gt;&lt;span class="command"&gt;place&lt;/span&gt; (on the pressure plate) when the plate is empty and the player is holding something&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Therefore, the solution will be &lt;span class="command"&gt;lift&lt;/span&gt;; &lt;span class="command"&gt;drop&lt;/span&gt;; &lt;span class="command"&gt;take &lt;span class="filledblank"&gt;rock&lt;/span&gt;&lt;/span&gt;; &lt;span class="command"&gt;place&lt;/span&gt;; &lt;span class="command"&gt;take &lt;span class="filledblank"&gt;statue&lt;/span&gt;&lt;/span&gt;; &lt;span class="command"&gt;leave&lt;/span&gt;.  The following will show how to implement such a puzzle using Thucydides, and sample code will be provided for Thucydides/Erlang.&lt;/p&gt;
  &lt;h2&gt;Setting the Stage&lt;/h2&gt;
  &lt;p&gt;First, the nouns must be examined.  This system does no dynamic generation of new actors, so it's sufficient to use the entities suggested by the puzzle description: A &lt;span class="filledblank"&gt;door&lt;/span&gt; to open and close, a &lt;span class="filledblank"&gt;statue&lt;/span&gt; and a &lt;span class="filledblank"&gt;rock&lt;/span&gt; to lift and drop, and a &lt;span class="filledblank"&gt;floor&lt;/span&gt;, &lt;span class="filledblank"&gt;plate&lt;/span&gt;, and &lt;span class="filledblank"&gt;player&lt;/span&gt; to hold items.&lt;/p&gt;
  &lt;p&gt;Nouns are the items bound into Archetypes to create an Incident when one should occur.  The &lt;span class="command"&gt;drop&lt;/span&gt; command will fill in a Drop Archetype with the dropper and the item to be dropped, for instance.&lt;/p&gt;
  &lt;p&gt;Now that the nouns are in place, the fluent types should be decided.  We should think of the states caused by the interactions of the commands and the nouns.  For instance, &lt;span class="ftype"&gt;inventory&lt;/span&gt; is a Fluent covering the &lt;span class="filledblank"&gt;floor&lt;/span&gt;, &lt;span class="filledblank"&gt;plate&lt;/span&gt;, and &lt;span class="filledblank"&gt;player&lt;/span&gt;.  &lt;span class="ftype"&gt;open&lt;/span&gt; is a Fluent covering the &lt;span class="filledblank"&gt;door&lt;/span&gt;.  &lt;span class="ftype"&gt;finished&lt;/span&gt; is a Fluent of interest to the game, and is set when the player leaves the room.&lt;/p&gt;
  &lt;p&gt;Next, the subject of Cancels should be approached.  We can imagine that if the &lt;span class="filledblank"&gt;door&lt;/span&gt; is &lt;span class="ftype"&gt;open&lt;/span&gt;, it will be so forever.  But when the &lt;span class="filledblank"&gt;plate&lt;/span&gt; is emptied, the &lt;span class="filledblank"&gt;door&lt;/span&gt;'s &lt;span class="ftype"&gt;open&lt;/span&gt;ness should be terminated.  While it would be possible to express "the door is open" as "the plate is full", this is a less flexible approach that doesn't take into account the fact that there could be other ways to open the door or keep it propped open.&lt;/p&gt;
  &lt;p&gt;We can make a simple mapping of commands onto Archetypes, so let's do that.  That gives us Look, Leave, Take, Lift, Drop, and Place.  Leave will set &lt;span class="ftype"&gt;finished&lt;/span&gt;.  Take will set &lt;span class="ftype"&gt;inventory&lt;/span&gt; with the &lt;span class="blank"&gt;item&lt;/span&gt; as value, stacking with an append in the context of the taker(the &lt;span class="filledblank"&gt;player&lt;/span&gt;) and a delete in the context of the old possessor(the &lt;span class="filledblank"&gt;floor&lt;/span&gt;).  Lift will set &lt;span class="ftype"&gt;inventory&lt;/span&gt; as Take did, but will also Cancel the door's &lt;span class="ftype"&gt;open&lt;/span&gt; state.  Drop is not just Take with reversed arguments; the player can only hold one thing, but the floor can hold many.  To keep things simple, rather than give inventories a size, we'll have a special Drop Incident that encodes this idea that a Taker can hold one thing and a Drop destination can hold many.  Finally, Place acts like Lift, with the exception that it sets {&lt;span class="ftype"&gt;open&lt;/span&gt;, &lt;span class="filledblank"&gt;door&lt;/span&gt;} rather than cancels it.&lt;/p&gt;
  &lt;p&gt;The final step in designing such a simple simulation is to look at the preconditions for actions, hinted at in the list of verbs above.  Each of those preconditions will be expressed as a Requirement on the corresponding Archetype.  Drop and Place both require that the taker's hands are full; Place further requires that the destination is empty; Take and Lift both require that the object is at the corresponding location and that the taker's hands are empty; Leave requires that the exit is open.&lt;/p&gt;
&lt;a name="jump"&gt;&lt;/a&gt;
&lt;span class="fullpost"&gt;
  &lt;h2&gt;Send in the Code&lt;/h2&gt;
  &lt;p&gt;First, we'll write a quick and dirty adventure game interface:&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;%No code!  We're going to use the Erlang shell for I/O, 
%and let our input alphabet be function calls 
%and our outputs be strings.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;With that out of the way, we can move on to the interesting parts.  I'll only show excerpts here, but &lt;a href="http://joe.garbagecollective.org/jones.erl"&gt; here's the whole file&lt;/a&gt;.  The Herodotus/Erlang implementation also includes this demo, but that's not ready to distribute yet.  Now, on to the tasks.&lt;/p&gt;
  &lt;h2&gt;Speak Fluent Erlang&lt;/h2&gt;
  &lt;p&gt;First, we'll look at simply applying Fluents in a Herodotus history.  In this example, we create a few Fluents, jam them into an Incident, and trigger that.&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;%... jones.erl 42-47: reset()
%This macro creates a Fluent with the given type, context,
%start, end, persist-value, value code, and stack code.
%These up the initial state of the room.
%Note that since we know these are the first fluents, we can just
%use the current fluent's value for the new net value in the stack mode.&lt;/span&gt;
RockOnFloor = ?FLUENT(inventory, floor, 0, infinity, removed, [rock], _Val),
StatueOnPlate = ?FLUENT(inventory, plate, 0, infinity, removed, [statue], _Val),
EmptyHands = ?FLUENT(inventory, player, 0, infinity, removed, [], _Val),
DoorOpen = ?FLUENT(open, door, 0, infinity, closed, open, _Val),
&lt;span class="comment"&gt;%Now we put all the Fluents into a list...&lt;/span&gt;
Fluents = [RockOnFloor, StatueOnPlate, EmptyHands, DoorOpen],
&lt;span class="comment"&gt;%And trigger a new incident using those fluents and no cancels.
%We trigger them in the main history of the jones_hero herodotus process.&lt;/span&gt;
herodotus:trigger(incident:new(init, Fluents, [], 0), main, jones_hero),
&lt;span class="comment"&gt;%...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;h2&gt;Incident Archetypes&lt;/h2&gt;
  &lt;p&gt;Now that the initial state is set, we can start looking at Thucydides.  We want to create five incident archetypes, but we'll only show a couple.  The first will be the Look archetype, which has no requirements.&lt;/p&gt;
  &lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;%... jones.erl 65-87: setup_iarc(look)
%This macro creates an 'Adder Fluent Archetype'.  All of the arguments 
%are in the context of a function.  The available vars are 
%(_Time, _Bindings) for the first five code arguments, where
%_Time is the time the Incident is triggered; and 
%(Self, _Now, _Args, _Time, _EndTime) for the sixth code argument.  
%Self is the Fluent being evaluated.
%This macro provides its own stack mode, so that definition isn't shown yet.
%A Fluent Archetype can be 'cloned' into a Fluent, given time and bindings.
%This is similar to the way incident archetypes are cloned into incidents.&lt;/span&gt;
&lt;span class="comment"&gt;%modify times_looked&lt;/span&gt;
FA = ?A_ADD(times_looked,
&lt;span class="comment"&gt;%for the looker - we use bindings for flexibility&lt;/span&gt;
            dict:fetch("Looker", _Bindings),
&lt;span class="comment"&gt;%at the given time&lt;/span&gt;
            _Time,
&lt;span class="comment"&gt;%forever&lt;/span&gt;
            infinity,
&lt;span class="comment"&gt;%if this gets ended somehow, it won't change the value&lt;/span&gt;
            persist,
&lt;span class="comment"&gt;%increment by one&lt;/span&gt;
            1),
Fluents = [FA],
&lt;span class="comment"&gt;%This is primarily for documentation and 
%discovery purposes, and may be removed later&lt;/span&gt;
Vars = ["Looker"],
&lt;span class="comment"&gt;%Look requires nothing in particular&lt;/span&gt;
Reqs = [],
&lt;span class="comment"&gt;%Look doesn't depend on any fluents&lt;/span&gt;
ExtraInputs = [],
&lt;span class="comment"&gt;%Look doesn't cancel anything&lt;/span&gt;
Cancels = [],
&lt;span class="comment"&gt;%Create the archetype&lt;/span&gt;
Look = i_arc:new(look, Fluents, Vars, Reqs, ExtraInputs, Cancels),
&lt;span class="comment"&gt;%Add the archetype to the simulation&lt;/span&gt;
simulation:add_iarc(Look, jones_sim)
&lt;span class="comment"&gt;%...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;The second archetype we examine will be Lift, which cancels the {open, [door, plate]} Fluent set initially(or set by Place).  We use a list context there, since we assume that the door could potentially be opened by a lever, even if the plate were empty.  Really, this is primarily to show the cancellation mechanism - it could just as well have been done with a fluent-set.  One example of a place to certainly prefer cancels over simple fluent replacement is when growth changes from linear to exponential, or some similar massive shift like that.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;%... jones.erl 132-192: setup_iarc(lift)&lt;/span&gt;
&lt;span class="comment"&gt;%A complete fluent archetype, including stack mode.&lt;/span&gt;
TakerAddItem = ?A_FLUENT(
&lt;span class="comment"&gt;%modify inventory&lt;/span&gt;
    inventory,
&lt;span class="comment"&gt;%of the taker&lt;/span&gt;
    dict:fetch("Taker", _Bindings),
&lt;span class="comment"&gt;%at the given time&lt;/span&gt;
    _Time,
&lt;span class="comment"&gt;%forever&lt;/span&gt;
    infinity,
&lt;span class="comment"&gt;%on cancellation, it's "removed"&lt;/span&gt;
    removed,
&lt;span class="comment"&gt;%the item to be added is the result of a query&lt;/span&gt;
    herodotus:value(
&lt;span class="comment"&gt;%when you make a query from within a fluent, you should provide&lt;/span&gt;
&lt;span class="comment"&gt;%the fluent making the query.&lt;/span&gt;
        Self,
&lt;span class="comment"&gt;%this query is against the inventory of the source.&lt;/span&gt;
&lt;span class="comment"&gt;%we can assume there's only one item in it.&lt;/span&gt;
&lt;span class="comment"&gt;%note that we use _Time, the time the fluent &lt;/span&gt;
&lt;span class="comment"&gt;%was set, and not _Now, the time it is evaluated&lt;/span&gt;
        selector:new(inventory, dict:fetch("Source", _Bindings), _Time),
&lt;span class="comment"&gt;%no extra args&lt;/span&gt;
        [],
&lt;span class="comment"&gt;%the history is the main history&lt;/span&gt;
        main,
&lt;span class="comment"&gt;%of the jones_hero herodotus process.&lt;/span&gt;
        jones_hero
    ),
&lt;span class="comment"&gt;%and it's merged into the taker's inventory&lt;/span&gt;
    fluent:fmerge(_Net, _Val)),
&lt;span class="comment"&gt;%Now for the next fluent:&lt;/span&gt;
SourceRemoveItem = ?A_FLUENT(
&lt;span class="comment"&gt;%modify inventory&lt;/span&gt;
    inventory,
&lt;span class="comment"&gt;%of the source&lt;/span&gt;
    dict:fetch("Source", _Bindings),
&lt;span class="comment"&gt;%right now&lt;/span&gt;
    _Time,
&lt;span class="comment"&gt;%until forever&lt;/span&gt;
    infinity,
&lt;span class="comment"&gt;%if it is canceled, it will be "returned"&lt;/span&gt;
    returned,
&lt;span class="comment"&gt;%lift the topmost item, whatever that means&lt;/span&gt;
    [hd(_Net)],                     
&lt;span class="comment"&gt;%and subtract it from the old inventory&lt;/span&gt;
    fluent:fsubtract(_Net, _Val)
),
&lt;span class="comment"&gt;%these are the fluents for this archetype&lt;/span&gt;
Flus = [SourceRemoveItem, TakerAddItem],
&lt;span class="comment"&gt;%these are the variables&lt;/span&gt;
Vars = ["Taker", "Source",
        "Trigger", "TriggerFluent",
        "TriggeredState", "UntriggeredState"],
&lt;span class="comment"&gt;%Now for the requirements&lt;/span&gt;
SourceHasItem =
&lt;span class="comment"&gt;%REQ is a macro which creates a Requirement, given three bits of &lt;/span&gt;
&lt;span class="comment"&gt;%selector information, arguments, and a function to check the &lt;/span&gt;
&lt;span class="comment"&gt;%value resulting from querying that selector with those args.&lt;/span&gt;
    ?REQ(
&lt;span class="comment"&gt;%Require that the value of the inventory&lt;/span&gt;
         inventory,
&lt;span class="comment"&gt;%of the Source&lt;/span&gt;
         dict:fetch("Source", _Bindings),
&lt;span class="comment"&gt;%at the time of application&lt;/span&gt;
         _Time,
&lt;span class="comment"&gt;%with no extra args&lt;/span&gt;
         [],
&lt;span class="comment"&gt;%contains an item&lt;/span&gt;
         is_list(_Val) andalso length(_Val) &gt; 0
    )
,
TakerHandsFree = 
    ?REQ(
&lt;span class="comment"&gt;%Require that the inventory&lt;/span&gt;
         inventory,
&lt;span class="comment"&gt;%of the taker&lt;/span&gt;
         dict:fetch("Taker", _Bindings),
&lt;span class="comment"&gt;%at the time of application&lt;/span&gt;
         _Time,
&lt;span class="comment"&gt;%with no extra args&lt;/span&gt;
         [],
&lt;span class="comment"&gt;%is empty.&lt;/span&gt;
         _Val =:= []
    )
,
&lt;span class="comment"&gt;%gather the requirements&lt;/span&gt;
Reqs = [SourceHasItem, TakerHandsFree],
&lt;span class="comment"&gt;%no extra dependencies&lt;/span&gt;
Extras = [],
&lt;span class="comment"&gt;%This finds the "door opened by plate" fluents and kills them.&lt;/span&gt;
&lt;span class="comment"&gt;%A_SEL creates a selector archetype, which follows the same&lt;/span&gt;
&lt;span class="comment"&gt;%rules as other archetypes.&lt;/span&gt;
TriggerFinder = ?A_SEL(
    dict:fetch("TriggerFluent", _Bindings),
    [dict:fetch("Trigger", _Bindings), dict:fetch("Source", _Bindings)],
    _Time,
    infinity
),
&lt;span class="comment"&gt;%Gather the cancels&lt;/span&gt;
Cancels = [TriggerFinder],
&lt;span class="comment"&gt;%and create the archetype&lt;/span&gt;
Lift = i_arc:new(lift, Flus, Vars, Reqs, Extras, Cancels),
&lt;span class="comment"&gt;%then add the archetype&lt;/span&gt;
simulation:add_iarc(Lift, jones_sim)
&lt;span class="comment"&gt;%...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;h2&gt;Trigger Action&lt;/h2&gt;
  &lt;p&gt;Now it's time to figure out how to trigger these incident archetypes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class="comment"&gt;%... jones.erl 349: look()&lt;/span&gt;
&lt;span class="comment"&gt;%This asks the simulation jones_sim to trigger the 
%"look" incident in the given history(main)&lt;/span&gt;
&lt;span class="comment"&gt;%at the given time with the given bindings.&lt;/span&gt;
&lt;span class="comment"&gt;%We use special bindings for the player just 
%to show a little more of the Archetype system.&lt;/span&gt;
simulation:trigger(look, 
                    main, 
                    current_time(), 
                    dict:store("Looker", player, dict:new()), 
                    jones_sim)
&lt;/code&gt;&lt;/pre&gt;
  &lt;p&gt;Triggering is simple!  This will return &lt;code&gt;ok&lt;/code&gt; if it completes successfully, &lt;code&gt;not_met&lt;/code&gt; if any requirements are not met, or &lt;code&gt;paradox&lt;/code&gt; if a paradox would result from applying that incident.  Thucydides handles all of the requirement checking, cancellations, paradox checking, and so on.  Also, note that if any non-&lt;code&gt;ok&lt;/code&gt; value is returned, the history is as it was before the trigger: a trigger either succeeds or fails, and intermediate states will not pollute other actions.&lt;/p&gt;
  &lt;h2&gt;Mission accomplished!&lt;/h2&gt;
  &lt;p&gt;While Thucydides/Erlang is still unfinished, I'd rather not put it up for download.  However, the above examples and the jones.erl file suggest how a simple simulation might look.  I plan to eventually replace the archetype definitions and the fluent queries with domain-specific languages, but until I know the capabilities that will need to be supported, I want to stick with this approach.&lt;/p&gt;
  &lt;p&gt;Something worth noting is that in about one week's worth of total work I've reproduced every feature of Herodotus/Io, only better-defined, faster, and safer.  Having the Io version around for comparison definitely helped, but I feel like the Erlang version will scale far, far better.&lt;/p&gt;
  &lt;p&gt;The next essay will implement a trivial military simulation.  Player involvement will be limited to army formation and the issuance of high-level commands, and the outcome of the fight will be decided by Thucydides's rules of causality.&lt;/p&gt; 
  &lt;!--RPS--#each--which to use--turntaking --&gt;
  &lt;p&gt;If there are any questions about the new Herodotus or Thucydides, or about the examples in this essay, please post them in the comments.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/03/homage-jones.html' title='Homage à Jones'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=3146562193994296269' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/3146562193994296269'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/3146562193994296269'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-8222376407104297737</id><published>2008-03-08T21:53:00.000-05:00</published><updated>2008-03-08T21:54:21.679-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Rewriting History</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Herodotus series. Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; before proceeding.&lt;/p&gt;
 &lt;h2&gt;The challenge&lt;/h2&gt;
 &lt;p&gt;Herodotus's Io implementation is slowish, complex, and a little clumsy. It is loosely defined, and that fault has extended to Herodotus as a whole, such that it is difficult to describe the system's actions. Especially prone to this complexity are cancellations, which have extremely loose semantics.  Accordingly, Herodotus will for now be defined concretely.&lt;/p&gt;
 &lt;p&gt;Furthermore, it will be necessary with the release of Metaplace to provide Herodotus as a service for worldbuilders. In pursuit of this goal, I have rewritten Herodotus in &lt;a href="http://www.erlang.org"&gt;Erlang&lt;/a&gt;, a concurrency-oriented functional programming language. Functional programming's lack of side effects is a perfect fit for the semantics of Herodotus, where a history is defined as a series of transformations(Incidents) on a base state.  As a nice bonus, the speed of Erlang means that Histories with tens of thousands of incidents are now quite feasible, even with the relatively few optimizations that have been performed so far(none of which yet include indexing or caching).&lt;/p&gt;
&lt;a name="jump"&gt;&lt;/a&gt;
 &lt;h2&gt;The Specification&lt;/h2&gt;
 &lt;p&gt;Herodotus will continue to have only a few concepts and operations at its core.  The Thucydides simulation framework will extend these concepts and handle all the logic of causality, as well as paradox detection and prevention.&lt;/p&gt;
&lt;span class="fullpost"&gt;
 &lt;p&gt;Herodotus provides:&lt;/p&gt;
  &lt;ul&gt;
  &lt;li&gt;Fluents
   &lt;ul&gt;
    &lt;li&gt;A Fluent is an &lt;code&gt;{id, selector, persistence, bindings, function, stack}&lt;/code&gt; tuple.
     &lt;ul&gt;
     &lt;li&gt;&lt;code&gt;id&lt;/code&gt; uniquely identifies this Fluent.&lt;/li&gt;
     &lt;li&gt;Selectors and Matching
     &lt;ul&gt;
      &lt;li&gt;A selector is a &lt;code&gt;{fluentType, context, start, end}&lt;/code&gt; tuple.&lt;/li&gt;
      &lt;li&gt;Selectors are used primarily for defining and querying fluents.&lt;/li&gt;
      &lt;li&gt;Two selectors "match" if their &lt;code&gt;fluentType&lt;/code&gt;s and &lt;code&gt;context&lt;/code&gt;s match.
       &lt;ul&gt;
        &lt;li&gt;Two single items match if they are identical, or if either is &lt;code&gt;any&lt;/code&gt;.&lt;/li&gt;
        &lt;li&gt;A single item is matched by a list if it matches any element of that list.&lt;/li&gt;
        &lt;li&gt;A list is matched by a single item if that item matches any element.&lt;/li&gt;
        &lt;li&gt;A list is matched by another list if every item in the latter matches an item in the former.&lt;/li&gt;
       &lt;/ul&gt;
      &lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;Persistence
     &lt;ul&gt;
      &lt;li&gt;When a Fluent is asked to provide a value after its end-time, it will choose what to do based on its persistence value.&lt;/li&gt;
      &lt;li&gt;If the value is &lt;code&gt;persist&lt;/code&gt;, then the value of the Fluent at its end-time will be used.&lt;/li&gt;
      &lt;li&gt;If the value is anything else, then the value will be its persistence value.&lt;/li&gt;
      &lt;li&gt;This provides a mechanism to detect the "death" of specific fluents.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;Bindings
     &lt;ul&gt;
      &lt;li&gt;When a Fluent is evaluated, it will be provided a dictionary of bindings.&lt;/li&gt;
      &lt;li&gt;These bindings are configuration for the Fluent, and are guaranteed to be static after the Fluent has been created.&lt;/li&gt;
      &lt;li&gt;This provides a way to provide arbitrary additional data to Fluents at creation time.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;code&gt;function&lt;/code&gt; is a function of Fluent, Time, and Arguments which returns the value of the Fluent at that time.
     &lt;ul&gt;
      &lt;li&gt;Fluents are evaluated in forward order by their &lt;code&gt;selector&lt;/code&gt;s' &lt;code&gt;set_time&lt;/code&gt;.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;code&gt;stack&lt;/code&gt; is a function of Fluent, Time, Arguments, Stack, Net, and Value which returns the new net value after applying this Fluent's Value.
     &lt;ul&gt;
      &lt;li&gt;A Stack is a list of &lt;code&gt;{Fluent, Selector, Persistence, Value}&lt;/code&gt; tuples in backward order by &lt;code&gt;set_time&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;After they are evaluated, Fluents are "stacked" together using their respective stack functions, in forward order by time.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
   &lt;/ul&gt;
   &lt;/li&gt;
   &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cancels
   &lt;ul&gt;
    &lt;li&gt;A Cancel prematurely terminates one Fluent.&lt;/li&gt;
    &lt;li&gt;It effectively sets an &lt;code&gt;end_time&lt;/code&gt; for that Fluent at the Cancel's &lt;code&gt;set_time&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Cancels also maintain a unique &lt;code&gt;id&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Cancelling Cancels is a little tricky: if Cancel-cancels are to be supported, then so must Cancel-cancel-cancels and so on.  Since the semantic is unclear, Herodotus does not define it.  There are two approaches recommended for applications that wish to counter the effect of a Cancel:
     &lt;ul&gt;
      &lt;li&gt;Remove the Incident which causes the Cancel.  This is suitable when you don't mind a destructive change.  This is the easiest and most correct solution.&lt;/li&gt;
      &lt;li&gt;Add a new Incident that sets a Fluent which continues the function of the old Fluent.  This must act differently depending on the old Fluent's &lt;code&gt;persist&lt;/code&gt; value.  This has a slightly different meaning, in that the period of time between the Cancel and the Cancel-cancel will act as an irregularity in the function.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
   &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Incidents
   &lt;ul&gt;
    &lt;li&gt;An Incident is a unit of historical change.&lt;/li&gt;
    &lt;li&gt;A guiding principle is that an Incident is indivisible and immutable.  Nothing should ever corrupt an Incident's value, and an Incident being removed should not damage the History in any way.&lt;/li&gt;
    &lt;li&gt;Incidents contain a payload of Fluents and Cancels.&lt;/li&gt;
    &lt;li&gt;Incidents are set at a particular &lt;code&gt;set_time&lt;/code&gt; and maintain a unique &lt;code&gt;id&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Incidents also mirror the &lt;code&gt;bindings&lt;/code&gt; used in their fluents.&lt;/li&gt;
    &lt;li&gt;To aid simulation frameworks or for self-documentation purposes, Incidents can be granted an &lt;code&gt;isa&lt;/code&gt; which maps to some Simulation construct.  For instance, a particular Instance might have an &lt;code&gt;isa&lt;/code&gt; of "birth", while another has "death".&lt;/li&gt;
   &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Histories
   &lt;ul&gt;
    &lt;li&gt;A History is a named series of Incidents.&lt;/li&gt;
    &lt;li&gt;Histories can have an Incident added to them.  This is called Triggering.&lt;/li&gt;
    &lt;li&gt;Histories can have an existing Incident rolled back.&lt;/li&gt;
    &lt;li&gt;Histories can be queried for the list of Fluents that would match a given Selector, post-Cancellation.&lt;/li&gt;
    &lt;li&gt;Histories can be queried for their value given a Selector and optional additional arguments.  These additional arguments will be passed on to the Fluents.&lt;/li&gt;
    &lt;li&gt;Histories can be queried for their Incidents matching a given &lt;code&gt;isa&lt;/code&gt;.&lt;/li&gt;
   &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Herodotus
   &lt;ul&gt;
    &lt;li&gt;A Herodotus process maintains a set of Histories.&lt;/li&gt;
    &lt;li&gt;Herodotus provides a complete external interface to these Histories, but prevents direct access.&lt;/li&gt;
    &lt;li&gt;Herodotus also provides a Transaction semantic.
     &lt;ul&gt;
      &lt;li&gt;A Transaction is opened automatically when a set of Dependencies is provided with an Incident to be triggered.
       &lt;ul&gt;
        &lt;li&gt;A Dependency is a tuple mapping from an input Selector to an output Selector.&lt;/li&gt;
       &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Whenever such a set of Dependencies intersects the set of Dependencies of an existing Transaction, the new Incident will be considered part of the existing Transaction.&lt;/li&gt;
      &lt;li&gt;Whenever a value or fluent query on a selector which intersects an existing Transaction's identifier is received, the query will use the corresponding inflight transaction data.
       &lt;ul&gt;
        &lt;li&gt;An exception will be made for "external" queries, i.e. those that come from outside the system.  These will ignore the intermediate data, and are the reason that the Transaction system is in place.&lt;/li&gt;
       &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Transactions can be completed, at which point the "hypothetical" Incidents will be triggered.&lt;/li&gt;
      &lt;li&gt;Transactions can be aborted, at which point the hypothetical Incidents will be thrown away.&lt;/li&gt;
      &lt;li&gt;Transactions can involve the triggering of Incidents across several Histories.&lt;/li&gt;
      &lt;li&gt;Multiple Transactions can be active at once.&lt;/li&gt;
     &lt;/ul&gt;
    &lt;/li&gt;
   &lt;/ul&gt;
  &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Although it isn't short, the above specification does completely specify the behavior of a Herodotus system.  In particular, note the absence of the Requirements present in Herodotus/Io.  After much deliberation, I decided that Requirements should be removed from base Herodotus and moved into Thucydides.  Thucydides will also provide a superior set of tools for expressing causal relationships and the handling of paradoxes.&lt;/p&gt;
  &lt;p&gt;A complete specification for Thucydides is still pending.  The above was a refinement of the existing implementations of and test cases for Herodotus/Io and Herodotus/Erlang.  A similar process must be used to develop the specification for Thucydides, or the result will be either over- or under-engineered.  Accordingly, the next few essays will express a series of text-based games, each showcasing an increasingly advanced simulation environment.  Bartle's &lt;a href="http://books.google.com/books?id=z3VP7MYKqaIC"&gt;Designing Virtual Worlds&lt;/a&gt; will be used as a reference for such "interesting" simulation.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/03/rewriting-history.html' title='Rewriting History'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=8222376407104297737' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/8222376407104297737'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/8222376407104297737'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-3158286593701313505</id><published>2008-02-12T13:31:00.000-05:00</published><updated>2008-02-12T13:33:40.140-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='thucydides'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Filling in the Blanks: Procedural Glue</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Herodotus series, and a followup to &lt;a href="http://joe.garbagecollective.org/2008/02/designing-story.html"&gt;Designing a Story&lt;/a&gt;.  Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; before proceeding.&lt;/p&gt;
    &lt;h2&gt;A Sticky Situation&lt;/h2&gt;
    &lt;p&gt;At the end of the last essay, we found ourselves with a problem: We had all these simulation constructs, but no clear way to, well, construct them.  This essay will shed some light on how stories in Rboehm's style could be built.&lt;/p&gt;
    &lt;h2&gt;Pick and Choose&lt;/h2&gt;
    &lt;p&gt;The fundamental variable unit of a Scene, and therefore of a Quest, is a Goal.  If we're looking to build a &lt;span class="goal"&gt;&lt;span class="blank"&gt;Asker&lt;/span&gt; asks &lt;span class="blank"&gt;Provider&lt;/span&gt; for &lt;span class="blank"&gt;Item&lt;/span&gt;&lt;/span&gt; goal, we should probably pick the &lt;span class="blank"&gt;Item&lt;/span&gt; based on the &lt;span class="blank"&gt;Asker&lt;/span&gt;.  Let's assume that the only &lt;span class="blank"&gt;Asker&lt;/span&gt; for now is the &lt;span class="filledblank"&gt;Farmer&lt;/span&gt;, though later we can look at ways to pick those too.&lt;/p&gt;
&lt;a name="jump"&gt;&lt;/a&gt;    &lt;p&gt;Recall that Characters have &lt;span class="ftype"&gt;desires&lt;/span&gt;.  In that case, we might want to pick an &lt;span class="blank"&gt;Item&lt;/span&gt; from among those &lt;span class="ftype"&gt;desires&lt;/span&gt;.  This gives us a nice little object-oriented and time-sensitive way to pick which &lt;span class="blank"&gt;Item&lt;/span&gt; to hunt for.  And if all of a Character's needs are satisfied?  Then we pick a different Character.&lt;/p&gt;
&lt;span class="fullpost"&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;//First, we need some new metadata for goals:&lt;/span&gt;
AskForItemGoal := Goal clone do(
  item ::= nil
  asker ::= nil
  &lt;span class="changed"&gt;askerTypes ::= list("consumer")&lt;/span&gt;
  provider ::= nil
  &lt;span class="changed"&gt;providerTypes ::= list("provider")&lt;/span&gt;
)
GiveItemGoal := Goal clone do(
  item ::= nil
  receiver ::= nil
  &lt;span class="changed"&gt;receiverTypes ::= list("consumer")&lt;/span&gt;
  giver ::= nil
  &lt;span class="changed"&gt;giverTypes ::= list("provider")&lt;/span&gt;
)
&lt;span class="comment"&gt;//Then later, in our goal creator...&lt;/span&gt;
createAskForItemGoal := method(asker, provider,
&lt;span class="comment"&gt;//In Thucydides, this could be:&lt;/span&gt;
&lt;span class="comment"&gt;//asker desires(now)&lt;/span&gt;
  currentDesires := history fluentValue("desires", asker, now)
  if((currentDesires == nil) or(currentDesires size == 0),
&lt;span class="comment"&gt;//This one is no good, pick a different one&lt;/span&gt;
&lt;span class="comment"&gt;//Other conditions for picking different characters could include&lt;/span&gt;
&lt;span class="comment"&gt;//incompatible alignment, national affiliation, location, and so on.&lt;/span&gt;
    newAsker := chooseDifferentCharacter(AskForItemGoal askerTypes, list(asker))
    return createAskForItemGoal(newAsker, 
                                provider)
  )
  desiredItems := currentDesires anyOne
&lt;span class="comment"&gt;//In Thucydides, this could be:&lt;/span&gt;
&lt;span class="comment"&gt;//SimObject clone setCategories(desiredItems) allActiveInAt(h, t)&lt;/span&gt;
  actualItem := history fluentValue(desiredItems, nil, now) anyOne
  AskForItemGoal clone setAsker(asker) setProvider(provider) setItem(actualItem)
)
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;And bam!  We get an &lt;span class="blank"&gt;Item&lt;/span&gt; for the Quest that's relevant to the Asker.  Now, in the supporting infrastructure, we can spawn in such an &lt;span class="blank"&gt;Item&lt;/span&gt;, perhaps in somebody's &lt;span class="ftype"&gt;inventory&lt;/span&gt; or on a &lt;span class="ftype"&gt;spawnLocation&lt;/span&gt; in some &lt;span class="ftype"&gt;cave&lt;/span&gt;.  Perhaps Items have some metadata saying what kinds of places they can spawn in.&lt;/p&gt;
    &lt;h2&gt;About Types&lt;/h2&gt;
    &lt;p&gt;This would be a good place to say something about types in Herodotus and in general.  Herodotus uses a very simple mechanism for matching types, where the types requested must all be present in the type matched against.  For example, [animal, cat] matches [animal], [cat], and [animal, cat], but doesn't match [animal, dog] or [construction-vehicle, cat].  In the future, Herodotus might use a matching system with rankings, but for now, this is how it works.  So, if we define a Donut's type to be [item, food, sweet, round, donut], and if we have a Goal which is looking for a [food, sweet], then the Donut will surely match; but if it's looking for [food, meat], there will be no match.  That is, unless there's a Donut clone of type [item, food, meat, round, donut].  In the end, the utility of this type system depends on how consistently it's applied.&lt;/p&gt;
    &lt;h2&gt;Calculated Character Creation&lt;/h2&gt;
    &lt;p&gt;Let's move to a slightly more complex topic: the creation of characters expressly for the purpose of a Scene.  This occurs when no existing character is available to fill a role, and it could include, for instance, spawning in the particular Kobold carrying the candles required to fulfill the quest; or it could be the visiting diplomat from another nation.  The benefit of doing this with Herodotus is twofold:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Character archetypes can be chosen from a broad pool, based on the quest, and the archetype chosen can influence the experience.&lt;/li&gt;
      &lt;li&gt;Spawned characters, if desired, can be implanted along with their own personal history, provided that history doesn't overlap or damage existing timelines.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;To clarify the second point a bit, we'll use the example of the visiting diplomat.  Instead of just spawning a "diplomat" at the requisite location, we could also place his time of birth, his nation of origin, his service record, and so on; making him effectively a permanent character that had been there all along.  This way, he can be used for other quests later on, and a mystery-solving Scene which required finding out the diplomat's history could be created, too.  &lt;em&gt;Mid-timestream insertion is currently dangerous in Herodotus.&lt;/em&gt;  Future versions will make it safe to use as a general technique, but for now, please just be sure that the fluents placed in the middle of a time stream don't violate the preconditions of later fluents or the invariants of prior fluents.&lt;/p&gt;
    &lt;p&gt;The synthesis of characters is a complex business; and since I'm preparing for GDC next week, this essay will have to stop here.  Hopefully, the approach above shows that the fundamental technique is to query the history, then decide what kind of thing to spawn or use.  Future articles will, having explored this path a bit, return to the starting-point and evaluate Herodotus as a service; a Herodotus Simulation Language and Herodotus Query Language will be proposed; and the quest generator will be revisited in a more formal framework.  Then, we will explore the application of Herodotus to a game called Stranded, designed by Rob Rix and myself.&lt;/p&gt;
    &lt;p&gt;If any GDC attendees would like to get in touch with me, please &lt;a href="mailto:joe@garbagecollective.org"&gt;send an e-mail&lt;/a&gt;.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/02/filling-in-blanks.html' title='Filling in the Blanks: Procedural Glue'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=3158286593701313505' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/3158286593701313505'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/3158286593701313505'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-1846404872922985993</id><published>2008-02-04T21:53:00.000-05:00</published><updated>2008-02-08T10:27:53.000-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='example'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='thucydides'/><category scheme='http://www.blogger.com/atom/ns#' term='herodotus'/><title type='text'>Designing a Story: Building Narratives from Story Atoms</title><content type='html'>&lt;p class="support"&gt;This is an essay in the Herodotus series.  Please read at least &lt;a href="http://joe.garbagecollective.org/2008/01/introducing-herodotus.html"&gt;Introducing Herodotus&lt;/a&gt; before proceeding.&lt;/p&gt;
    &lt;h2&gt;Rboehme's Quest Generator&lt;/h2&gt;
    &lt;p&gt;&lt;a href="http://www.areae.net"&gt;Areae&lt;/a&gt;'s &lt;a href="http://www.metaplace.com"&gt;Metaplace&lt;/a&gt; is an upcoming virtual world platform, construction kit, and social network.  One of the exciting ideas in the days leading up to its launch is the &lt;a href="http://forums.metaplace.com/viewtopic.php?f=6&amp;t=340&amp;st=0&amp;sk=t&amp;sd=a"&gt;plan&lt;/a&gt; by &lt;a href="http://www.cookingxp.com"&gt;Rboehme&lt;/a&gt; and others on the Metaplace forums to write a &lt;a href="http://www.sf.net/projects/questgen"&gt;procedural quest generator&lt;/a&gt;.  Since this sort of algorithm is precisely what Herodotus was written for, I hope to contribute to the project by providing a Herodotus simulation back-end for it.  This essay will also introduce &lt;code&gt;Thucydides&lt;/code&gt;, a simulation toolkit for Herodotus.&lt;/p&gt;
  &lt;h2&gt;The Father of History and the Father of Lies&lt;/h2&gt;
  &lt;p&gt;Herodotus, the man, went by an additional epithet: "The Father of Lies".  This ignominious label was conferred upon him by his critics who detested his ways of presenting multiple conflicting accounts of a story and his habit of writing on local folklore or third- or fourth-hand reports.  Thucydides, a slightly later historian, introduced the "objective" approach to history that historians use today, meaning that he competes for the title of "The Father of History".  Since Thucydides's work was more responsible and more restrained, I thought it just that the technology which provided a framework for history and a clear structure for the simulation framework should be called Thucydides.&lt;/p&gt;
  &lt;p&gt;Thucydides uses the context feature of Fluents and the forwarding mechanism of Io to conceal the inner workings of Herodotus from client programs.  A Thucydides &lt;code&gt;SimulationObject&lt;/code&gt; triggers an Incident when it is created or destroyed, is uniquely identifiable among other &lt;code&gt;SimulationObject&lt;/code&gt;s, and passes on any slot requests such as &lt;var&gt;age&lt;/var&gt; or &lt;var&gt;height&lt;/var&gt;, parameterized with a time, to the History in which they're defined.  What this means is that a lot of duplicated or error-prone Herodotus API can be replaced with the use of these &lt;code&gt;SimulationObject&lt;/code&gt;s.  Furthermore, it's possible to mix Thucydides and Herodotus code, as long as the user is careful not to violate any assumptions the &lt;code&gt;SimulationObject&lt;/code&gt;s might have about whether their represented contexts are still valid, whether their histories still exist, etc.&lt;/p&gt;
  &lt;a name="jump"&gt;&lt;/a&gt;&lt;p&gt;In this essay, we'll only be considering a single History, and will attempt to show how Thucydides can express Rboehm's Quest Generator.&lt;/p&gt;
&lt;span class="fullpost"&gt;  &lt;h2&gt;About the Simulation&lt;/h2&gt;
  &lt;p&gt;As I understand it, Rboehme's basic approach is to define some terms as follows:&lt;/p&gt;
  &lt;dl&gt;
    &lt;dt&gt;Story&lt;/dt&gt;
      &lt;dd&gt;A context in which Quests take place.&lt;/dd&gt;
    &lt;dt&gt;Quest&lt;/dt&gt;
      &lt;dd&gt;A series of Scenes designed to express a unit of Story.&lt;/dd&gt;
    &lt;dt&gt;Scene&lt;/dt&gt;
      &lt;dd&gt;A setting involving specific sets of necessary, sufficient, and optional goals.&lt;/dd&gt;
    &lt;dt&gt;Character&lt;/dt&gt;
      &lt;dd&gt;An entity placed at a specific Location, with a Memory of things which have occurred to him before in the short, medium, and long terms.  Also includes a list of Goals which can be used to feed the quest generator, as well as a list of likes and dislikes and a list of relationships to other Characters.&lt;/dd&gt;
    &lt;dt&gt;Role&lt;/dt&gt;
      &lt;dd&gt;Provides a list of Goals that a Character fulfilling that Role can choose from.  For instance, a Priest might choose the "Peaceful Resolution" Goal for the "Ender of the Brawl" Role, whereas a Barbarian might choose the "Pacify By Force" Goal.  Also includes information about whether the Character is a major, minor, or walk-on personage.  These Roles and their Goals drive AI behavior or PC options.&lt;/dd&gt;
    &lt;dt&gt;Goal&lt;/dt&gt;
      &lt;dd&gt;An abstract Goal (&lt;span class="goal"&gt;&lt;span class="blank"&gt;ROLE&lt;/span&gt; brings &lt;span class="blank"&gt;ITEM&lt;/span&gt; to &lt;span class="blank"&gt;ROLE&lt;/span&gt;&lt;/span&gt;, &lt;span class="goal"&gt;&lt;span class="blank"&gt;ROLE&lt;/span&gt; compels &lt;span class="blank"&gt;ROLE&lt;/span&gt; to &lt;span class="blank"&gt;ACTION&lt;/span&gt;&lt;/span&gt;, &lt;span class="goal"&gt;&lt;span class="blank"&gt;ROLE&lt;/span&gt; removes &lt;span class="blank"&gt;ROLES&lt;/span&gt; from &lt;span class="blank"&gt;AREA&lt;/span&gt;&lt;/span&gt;, etc).  Goal slots are filled with Roles provided by the Scene.&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;p&gt;For example, in a standard "fetch quest", the first scene, or Start, of the Quest would include the part where the player approaches the NPC and asks for a mission.  Its Goal would be &lt;span class="goal"&gt;&lt;span class="blank"&gt;ROLE&lt;/span&gt; asks &lt;span class="blank"&gt;ROLE&lt;/span&gt; for &lt;span class="blank"&gt;REQUEST&lt;/span&gt;&lt;/span&gt;, with the Roles being &lt;span class="filledblank"&gt;CUSTOMER&lt;/span&gt; and &lt;span class="filledblank"&gt;DELIVERYMAN&lt;/span&gt; respectively, and the &lt;span class="blank"&gt;REQUEST&lt;/span&gt; being for a particular &lt;span class="blank"&gt;ITEM&lt;/span&gt;.  This &lt;span class="blank"&gt;ITEM&lt;/span&gt; would be determined by the &lt;span class="filledblank"&gt;CUSTOMER&lt;/span&gt;'s Location, likes/dislikes, and other attributes.  This Goal would be part of the "Customer" Role, and the "Deliveryman" (our player) must wait for it to happen.  It might happen as part of conversation, or the distraught NPC might run up to the player and demand help.&lt;/p&gt;
  &lt;p&gt;In turn, this Scene would seed the Goal for the next Scene: &lt;span class="goal"&gt;&lt;span class="blank"&gt;ROLE&lt;/span&gt; brings &lt;span class="blank"&gt;ITEM&lt;/span&gt; to &lt;span class="blank"&gt;ROLE&lt;/span&gt;&lt;/span&gt;, with &lt;span class="filledblank"&gt;DELIVERYMAN&lt;/span&gt; and &lt;span class="filledblank"&gt;CUSTOMER&lt;/span&gt; being the Roles in order this time, and the &lt;span class="blank"&gt;ITEM&lt;/span&gt; being the one previously decided.  It is in this next scene, Finish, that the traditional MMO fetch quest takes place as the player completes that goal.&lt;/p&gt;
  &lt;p&gt;If this seems like a lot of work for a simple fetch quest, that might be excused; but consider that this description is not just one fetch quest, but &lt;em&gt;every fetch quest&lt;/em&gt;.  By varying the &lt;span class="blank"&gt;ITEM&lt;/span&gt; and its Location (or Owner), or by using an &lt;span class="blank"&gt;ITEM&lt;/span&gt; which requires some special preparation before it can transform into the "true" &lt;span class="blank"&gt;ITEM&lt;/span&gt;, all kinds of fetch quests can be produced.  &lt;em&gt;The primary benefit of quest synthesis is that you can script the variation into the objects, rather than into the quest itself.&lt;/em&gt;&lt;/p&gt;
  &lt;p&gt;In terms of an overarching Story, the player's perceived Goal can shift radically from Quest to Quest depending on the Goal used to reach completion at a given Quest.  If this Goal is a "failure"-like Goal, that has ramifications on what Quests are available afterwards; if it's a success and a part of a chain, the future Quests themselves continue the theme.&lt;/p&gt;
  &lt;h2&gt;In Terms of Herodotus&lt;/h2&gt;
  &lt;p&gt;Now, we'll rephrase these building blocks of Rboehme's quest simulation as Herodotus constructs, building a quest where a farmer wants a donut from the player.  A delicious donut is hidden in the nearby cave, but a passable donut is available on the farm itself.  Once we've met the requirements of Herodotus, we'll again recast the simulation as Thucydides entities, just to show how the process works.&lt;/p&gt;
  &lt;p&gt;We'll build from the simplest components of the system up to the most complex ones.&lt;/p&gt;
  &lt;h2&gt;Location, location, location&lt;/h2&gt;
  &lt;p&gt;First, we'll place the static tokens in the world.  A complete implementation would include a large number of Locations for quests to take place in, or Characters to live in, but for now we'll make do with three: Nowhere; a Farm; and a Cave.  To implement these in straight Herodotus, we would say something like this:&lt;/p&gt;
  &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
history := History clone

Location := Object clone
Nowhere := Location clone
CreateNowhere := Incident clone do(
  setFluent(FAppendContext create(list("locations", "nowhere"), Nowhere))
  setTime(0)
)
CreateNowhere occurIn(history)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Farm := Location clone
Cave := Location clone
CreateFarm := Incident clone do(
  setFluent(FAppendContext create(list("locations", "farms"), Farm)) 
  setTime(0) 
)
CreateCave := Incident clone do(
  setFluent(FAppendContext create(list("locations", "caves"), Cave)) 
  setTime(0)
)
CreateFarm occurIn(history)
CreateCave occurIn(history)
  &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;p&gt;In Thucydides:&lt;/p&gt;
&lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
history := History clone
&lt;span class="comment"&gt;//Go ahead and use this history for all SimObjects&lt;/span&gt;
SimObject setHistory(history)

Location := SimObject clone appendCategory("locations") setSpawnTime(0)
Nowhere := Location clone appendCategory("nowhere")
Nowhere spawn
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Farm := Location clone appendCategory("farms")
Cave := Location clone appendCategory("caves")
Farm spawn
Cave spawn
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;p&gt;From here, we can still do all the usual Herodotus queries on that History; &lt;code&gt;spawn&lt;/code&gt; just triggers an Incident, after all.&lt;/p&gt;
  &lt;h2&gt;Things and Stuff&lt;/h2&gt;
  &lt;p&gt;Continuing with the simple pieces, let's consider Items next.  Items can provide arbitrarily complex goals, but for now we'll treat Items as tokens to be grabbed.  For now, we'll just make two Donuts of differing quality.  In raw Herodotus:&lt;/p&gt;
  &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Item := Object clone do(
  categories ::= list("items")
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Donut := Item clone do(
  categories := list("items", "donuts")
&lt;span class="comment"&gt;//On a scale of 1-10&lt;/span&gt;
  baseQuality ::= 5
)
LousyDonut := Donut clone setBaseQuality(2)
TastyDonut := Donut clone setBaseQuality(8)
CreateDonut := Incident clone do(
  donut ::= nil
  loc ::= Nowhere
  setFluent(FAppendContext create(donut categories, donut))
&lt;span class="comment"&gt;//Establish the donut's start-position and initial quality&lt;/span&gt;
  setFluent(FReplaceConstant create("location", donut, loc)
  setFluent(FReplaceConstant create("quality", donut, donut baseQuality)
&lt;span class="comment"&gt;//Donuts degrade as time goes on.&lt;/span&gt;
&lt;span class="comment"&gt;//If one unit of time is one hour, a donut is absolutely bad&lt;/span&gt;
&lt;span class="comment"&gt;//after 24 time units, or one day.&lt;/span&gt;
  setFluent("quality", donut, h, t, 
    ((1 - (t - time)) / 24) max(0)
  ) stackBy(MultiplyNumber)
  setTime(0) 
)
CreateDonut clone do(
  setLocation(Farm) 
  setDonut(LousyDonut)
  occurIn(history)
)
CreateDonut clone do(
  setLocation(Cave)
  setDonut(TastyDonut)
  occurIn(history)
)
  &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;p&gt;And in Thucydides:&lt;/p&gt;
  &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Item := SimObject clone appendCategory("items")
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Donut := Item clone appendCategory("donuts") do(
  setQuality(5)
  setLocation(Nowhere)
&lt;span class="comment"&gt;//Intrinsics are a list of Fluents that go hand-in-hand&lt;/span&gt;
&lt;span class="comment"&gt;//with a SimObject and are applied as soon as it spawns.&lt;/span&gt;
  intrinsics := list(
&lt;span class="comment"&gt;//Donuts degrade as time goes on.&lt;/span&gt;
&lt;span class="comment"&gt;//If one unit of time is one hour, a donut is absolutely bad&lt;/span&gt;
&lt;span class="comment"&gt;//after 24 time units, or one day.&lt;/span&gt;
    Fluent create("quality", self, h, t, 
      ((1 - (t - time)) / 24) max(0)
    ) stackBy(MultiplyNumber)
  )
)
LousyDonut := Donut clone setQuality(2) setLocation(Farm)
TastyDonut := Donut clone setQuality(8) setLocation(Cave)
LousyDonut spawn
TastyDonut spawn
  &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;p&gt;The fascinating trick in this example is the way the "setQuality" and "setLocation" calls work.  Note that those methods aren't defined on Item or Donut or, indeed, on SimObject!  So, how are they resolved?&lt;/p&gt;
  &lt;p&gt;They are handled by SimObject's forward(), which deals with unrecognized messages, and the rule they use is as follows:  If the message starts with "set", remove the "set" and treat the lowercase name as a fluent type.  If the object hasn't spawned yet and no time argument is provided, append to the Intrinsic Fluents an FReplaceConstant Fluent with the given fluent type and using the SimObject as context.  If the object has spawned already, require a time argument in the first position.  If there's a time argument, create and apply a new Incident using an FReplaceConstant Fluent.  SimObject's forward mechanism works similarly for messages beginning with "add", "subtract", "multiply", "divide", "append", and "remove".  This removes the need for a lot of very similar Herodotus API uses.&lt;/p&gt;
  &lt;p&gt;Note that these only create one-way links - if you take two SimObjects A and B and perform &lt;code&gt;A appendFriend(B)&lt;/code&gt;, a fluent of type &lt;span class="ftype"&gt;friend&lt;/span&gt; will be created with the context &lt;code&gt;{&lt;var&gt;A&lt;/var&gt;}&lt;/code&gt; and a result list containing B.  The reverse relationship will not hold.  If Friendship is always two-way, then it might be reasonable to create a Friendship Relationship and attach both A and B to it via something like &lt;code&gt;Relationship clone appendCategory("friends") setParticipants(list(A, B)) setStrength(0.5)&lt;/code&gt;.  Relationship is a Thucydides SimObject clone which is responsible for maintaining simple relationship statuses between a group of SimObjects.  It's very simple, but it provides a nice single point of use.  A Relationship's participants, strength, and other slots are, of course, time-based, mutable, and queriable as usual.&lt;/p&gt;
  &lt;h2&gt;Goals and Roles&lt;/h2&gt;
  &lt;p&gt;Here is where we need to think a little more about what we're doing, exactly.  A Scene's Goal is a test of whether some conditions are met.  There are several ways we can express this:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;An Invariant on a Scene.  If a Goal is met, the Scene ends.  This means that subsequent Scenes must handle any "mess" that results from a Scene ending abruptly.  This is the only way that Herodotus can automatically handle Scene endings.&lt;/li&gt;
    &lt;li&gt;A plain Object property of a Scene and of various Roles.  As actions are performed and Incidents are generated and added, check to see if any Scene's Goals are met.  If so, permit them to terminate gracefully.&lt;/li&gt;
    &lt;li&gt;As above, but instead creating a Goal SimObject and associating it through Relationships with a Scene.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;The difference between the first two and the last one is whether Goals are mutable during a Scene.  This comes down to a question of whether a "changing goal" means "an alternate goal that was always available", "the goal of a new scene triggered by the 'failure' of this scene", or "an actual shift in goals of the same scene".  Personally, I think the middle option is the best, and a Quest can potentially be many Scenes in a row, with each Scene having one static set of goals.  So, if the goal "shifts" from &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Player&lt;/span&gt; delivers the &lt;span class="filledblank"&gt;Letter&lt;/span&gt; to the &lt;span class="filledblank"&gt;Captain&lt;/span&gt;&lt;/span&gt; to &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Player&lt;/span&gt; reports to the &lt;span class="filledblank"&gt;Captain&lt;/span&gt; that the &lt;span class="filledblank"&gt;Letter&lt;/span&gt; has been destroyed&lt;/span&gt;, what actually occurred is that the Goal &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Player&lt;/span&gt; discovers the &lt;span class="filledblank"&gt;Letter&lt;/span&gt;'s destruction&lt;/span&gt; was achieved, which ended the first scene and segued into the second scene, which included a primary goal of &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Player&lt;/span&gt; reports to the &lt;span class="filledblank"&gt;Captain&lt;/span&gt; that the &lt;span class="filledblank"&gt;Letter&lt;/span&gt; has been destroyed&lt;/span&gt;.  Fluent-driven objects are powerful, but add complexity.  &lt;em&gt;If it's possible to simplify the model by making certain parts static, feel free to do so&lt;/em&gt;.&lt;/p&gt;
    &lt;p&gt;Now then, let's express two Goals: &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Farmer&lt;/span&gt; asks &lt;span class="filledblank"&gt;Player&lt;/span&gt; to bring him &lt;span class="filledblank"&gt;a Donut&lt;/span&gt;&lt;/span&gt; and &lt;span class="goal"&gt;&lt;span class="filledblank"&gt;Player&lt;/span&gt; delivers &lt;span class="filledblank"&gt;a Donut&lt;/span&gt; to the &lt;span class="filledblank"&gt;Farmer&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;//This is a barebones Goal with a very simple completion check.&lt;/span&gt;
&lt;span class="comment"&gt;//There's no reason Goals couldn't check certain fluent values&lt;/span&gt;
&lt;span class="comment"&gt;//on their Roles, or other arbitrary behavior.&lt;/span&gt;
Goal := Object clone do(
  availableTime ::= 0
  satisfiedInAt := method(h, t,
    h fluentValue("satisfied", self, t)
  )
)
AskForItemGoal := Goal clone do(
  item ::= nil
  asker ::= nil
  provider ::= nil
)
GiveItemGoal := Goal clone do(
  item ::= nil
  receiver ::= nil
  giver ::= nil
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
AskForDonutGoal := AskForItemGoal clone do(
  setItem(Donut) 
  setAsker(Farmer) 
  setProvider(Player)
)
GiveDonutGoal := GiveItemGoal clone do(
  setItem(Donut)
  setReceiver(Farmer) 
  setGiver(Player)
)
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;The above example actually looks identical in Thucydides.  This is to be expected, since none of this uses Herodotus.  Now, just to illustrate a fancier &lt;code&gt;satisfiedInAt&lt;/code&gt; condition, we'll show what would happen if the GiveItemGoal were to check for evidence of a Transaction between the giver and receiver involving that item.&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Transaction := Object clone do(
  aItem ::= nil
  bItem ::= nil
  aParty ::= nil
  bParty ::= nil
  aItemCost ::= 0
  bItemCost ::= 0
  time ::= 0
)
&lt;span class="comment"&gt;//...&lt;/span&gt;
&lt;span class="comment"&gt;//This is just an example of a complex goal in GiveItemGoal.&lt;/span&gt;
&lt;span class="comment"&gt;//It could just as easily have been done on the accomplishing side&lt;/span&gt;
&lt;span class="comment"&gt;//by manually setting "goalSatisfied".&lt;/span&gt;
  satisfiedInAt := method(h, t,
    h fluentValue("transactions", nil, t) detect(i, v,
&lt;span class="comment"&gt;//Make sure this transaction is from the giver to the receiver,&lt;/span&gt;
&lt;span class="comment"&gt;//that it involves the right item type, and that it happened after&lt;/span&gt;
&lt;span class="comment"&gt;//the goal became available&lt;/span&gt;
      (v aParty == giver) and(
        v bParty == receiver) and(
        v aItem categories containsAll(item categories)) and(
        v time &gt; availableTime
      )
    )
  )
  &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
  &lt;p&gt;And, in Thucydides, a couple of small changes:&lt;/p&gt;
  &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Transaction := &lt;span class="changed"&gt;SimObject&lt;/span&gt; clone do(
  &lt;span class="changed"&gt;appendCategory("transactions")&lt;/span&gt;
&lt;span class="comment"&gt;//These are all static, so we don't need to change them,&lt;/span&gt;
&lt;span class="comment"&gt;//which means they're "real" slots and not Fluent slots.&lt;/span&gt;
  aItem ::= nil
  bItem ::= nil
  aParty ::= nil
  bParty ::= nil
  aItemCost ::= 0
  bItemCost ::= 0
&lt;span class="comment"&gt;//Time is covered by the SimObject.&lt;/span&gt;
  &lt;span class="changed"&gt;//time ::= 0&lt;/span&gt;
)

  satisfiedInAt := method(h, t,
&lt;span class="comment"&gt;//Make sure this transaction is from the giver to the receiver,&lt;/span&gt;
&lt;span class="comment"&gt;//that it involves the right item type, and that it happened after&lt;/span&gt;
&lt;span class="comment"&gt;//the goal became available&lt;/span&gt;
&lt;span class="changed"&gt;    Transaction allActiveInAt(h, t)&lt;/span&gt; detect(i, v,
      (v giver == giver) and(
        v receiver == receiver) and(
        v item categories containsAll(item categories)) and(
        v time &gt; availableTime
      )
    )
  )
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;There's not much to be gained in this specific case from using this feature, though, so we'll stick with the simpler version above.  As for actually fulfilling these goals, that can be done in places like the hypothetical giveItem() or converseWithNPC(), or some other place.  There, too, we can record in the receiving character's &lt;span class="ftype"&gt;inventory&lt;/span&gt; fluent the receipt of the good or the bad donut, and even influence their mood based on how good a donut it was.&lt;/p&gt;
    &lt;p&gt;Next, let's introduce Roles.  A Role, for a Scene, includes a set of Goals, a list of characters, and some metadata.  In the Scene where an &lt;span class="blank"&gt;Asker&lt;/span&gt; asks a &lt;span class="blank"&gt;Provider&lt;/span&gt; to bring him an &lt;span class="blank"&gt;Item&lt;/span&gt;, the &lt;span class="blank"&gt;Asker&lt;/span&gt; Role would have a single Goal, which is within the Scene's ending goals, and the &lt;span class="blank"&gt;Provider&lt;/span&gt; would have none, except implicitly to be asked about bringing the &lt;span class="blank"&gt;Item&lt;/span&gt;.  The &lt;span class="blank"&gt;Item&lt;/span&gt; is chosen from among the likes or needs of the Character fulfilling the &lt;span class="blank"&gt;Asker&lt;/span&gt; Role.&lt;/p&gt;
    &lt;p&gt;We'll express Roles, too, as static data, and assume that once a Character is set on a Role, he won't switch or lose that Role for the duration of the Scene.&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Role := Object clone do(
&lt;span class="comment"&gt;//Categories are metadata about the sort of role it is.&lt;/span&gt;
  categories ::= list()
&lt;span class="comment"&gt;//The characters slotted into this role.&lt;/span&gt;
  characters ::= list()
&lt;span class="comment"&gt;//Those goals that the characters should want to fulfill&lt;/span&gt;
&lt;span class="comment"&gt;//to properly execute this Role.&lt;/span&gt;
  goals ::= list()
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
&lt;span class="comment"&gt;//Scene one:&lt;/span&gt;
DonutAsker := Role clone do(
&lt;span class="comment"&gt;//This "consumer" category means "someone who takes something in"&lt;/span&gt;
  setCategories(list("consumer"))
&lt;span class="comment"&gt;//In other words, it's the Farmer in this Scene.  Generally, a Category&lt;/span&gt;
&lt;span class="comment"&gt;//is like a meta-Role that spans the whole Scene.&lt;/span&gt;
  setCharacters(list(Farmer))
  setGoals(list(AskForDonutGoal))
)
DonutProvider := Role clone do(
&lt;span class="comment"&gt;//The Provider is "someone who supplies something to a consumer".&lt;/span&gt;
  setCategories(list("provider"))
  setCharacters(list(Player))
)
&lt;span class="comment"&gt;//Scene two:&lt;/span&gt;
DonutReceiver := Role clone do(
  setCategories(list("consumer"))
  setCharacters(list(Farmer))
)
DonutGiver := Role clone do(
  setCategories(list("provider"))
  setCharacters(list(Player))
  setGoals(list(GiveDonutGoal))
)
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;Easy enough, and identical in Thucydides, since we assume that Roles are, basically, unchanging tokens.&lt;/p&gt;
    &lt;h2&gt;Building Character&lt;/h2&gt;
    &lt;p&gt;Since this example is already running long, we'll make Characters as simple as possible: a list of desired items and a location.  In a full implementation, we'd include personal goals, memories, and so on, but for now we don't want to make it seem like I'm being paid by the word.  We'd like Characters to move around and shift their desires, though, so let's go ahead and see that in Herodotus:&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Character := Object clone
CreateCharacter := Incident clone do(
&lt;span class="comment"&gt;//Initial state.&lt;/span&gt;
  desires ::= list()
  location ::= Nowhere
  character ::= nil
  setupFluents := method(
&lt;span class="comment"&gt;//As usual, add the context...&lt;/span&gt;
    setFluent(FAppendContext("characters", character))
&lt;span class="comment"&gt;//Then add the initial state, like &lt;span class="ftype"&gt;desires&lt;/span&gt;, and&lt;/span&gt;
&lt;span class="comment"&gt;//link it to the character...&lt;/span&gt;
    setFluent(FReplaceList("desires", character, desires))
&lt;span class="comment"&gt;//Add the &lt;span class="ftype"&gt;location&lt;/span&gt; too&lt;/span&gt;
    setFluent(FReplaceConstant("location", character, location))
  )
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Farmer := Character clone
Player := Character clone
&lt;span class="comment"&gt;//Remember, this is an Incident.&lt;/span&gt;
CreateFarmer := CreateCharacter clone do(
&lt;span class="comment"&gt;//The Farmer wants donuts&lt;/span&gt;
  setDesires(list("donuts")) 
&lt;span class="comment"&gt;//and he lives on the Farm&lt;/span&gt;
  setLocation(Farm) 
&lt;span class="comment"&gt;//and he's represented by Farmer&lt;/span&gt;
  setCharacter(Farmer)
)
CreatePlayer := CreateCharacter clone do(
  setLocation(Farm)
  setCharacter(Player)
)
CreateFarmer occurIn(history)
CreatePlayer occurIn(history)
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;In Thucydides:&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
&lt;span class="comment"&gt;//Thucydides makes this much smoother&lt;/span&gt;
Character := SimObject clone do(
  appendCategory("characters")
  setLocation(Nowhere)
  setDesires(list())
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
Farmer := Character clone do(
&lt;span class="comment"&gt;//Fluent appending works on a whole list at once, so it uses&lt;/span&gt;
&lt;span class="comment"&gt;//the plural.  Sorry, but it was the easiest way to do it&lt;/span&gt;
&lt;span class="comment"&gt;//with the forwarding mechanism.&lt;/span&gt;
  appendDesires(list("donuts"))
  setLocation(Farm)
)
Player := Character clone do(
  setLocation(Farm)
)
Farmer spawn
Player spawn
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;Note the use of "appendDesires", one of the forward-handled methods from before.&lt;/p&gt;
    &lt;h2&gt;Making a Scene&lt;/h2&gt;
    &lt;p&gt;The Scene level is the first place we see tying together all these independent objects.  Recall that a Scene has a set of Roles and some Goals, and if certain of those Goals are met the Scene is concluded.  Fortunately, scenes are static!  There's nothing in a Scene that must vary with time.&lt;/p&gt;
    &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Scene := Object clone do(
&lt;span class="comment"&gt;//The roles appearing in the scene&lt;/span&gt;
  roles ::= list()
&lt;span class="comment"&gt;//The goals that, when any are accomplished, satisfy the scene&lt;/span&gt;
  finishGoals ::= list()
&lt;span class="comment"&gt;//A list of blocks of the form (scene, oldScene, h, t)-&gt;bool&lt;/span&gt;
  preconditions ::= list()
&lt;span class="comment"&gt;//Delegate finished status to goals&lt;/span&gt;
  satisfiedInAt := method(h, t,
    finishGoals detect(i,v,
      v satisfiedAtIn(h, t)
    )
  )
&lt;span class="comment"&gt;//Is it valid to segue into this?&lt;/span&gt;
  canSegueFromInAt := method(oldScene, h, t,
&lt;span class="comment"&gt;//If any precondition block forbids it, fail to segue&lt;/span&gt;
    preconditions foreach(i,v,
      if(v call(self, oldScene, h, t) not,
        return false
      ))
    )
&lt;span class="comment"&gt;//Otherwise, segue away&lt;/span&gt;
    true
  )
&lt;span class="comment"&gt;//Pick the roles that match the given categories&lt;/span&gt;
  rolesFor := method(categories,
    roles select(i, v, v categories containsAll(categories))
  )
&lt;span class="comment"&gt;//Set up role characters based on previous scene's roles&lt;/span&gt;
  segueFromInAt := method(lastScene, h, t,
&lt;span class="comment"&gt;//You could do other stuff in this method too, like set fluents&lt;/span&gt;
    lastScene roles foreach(i,v,
      rolesFor(v categories) foreach(i2, v2, 
       v2 characters appendSeq(v characters)
      )
    )
  )  
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
SceneOne := Scene clone do(
  setRoles(list(DonutAsker, DonutProvider))
  setGoals(DonutAsker goals)
)
SceneTwo := Scene clone do(
  setRoles(list(DonutReceiver, DonutGiver))
  setGoals(DonutGiver goals)
  setPreconditions(list(
    block(scene, oldScene, h, t,
&lt;span class="comment"&gt;//Ensure that the question has been asked.&lt;/span&gt;
&lt;span class="comment"&gt;//For now, we only have these two scenes, so it doesn't matter,&lt;/span&gt;
&lt;span class="comment"&gt;//but this way shows how scene chaining like this might be done.&lt;/span&gt;
&lt;span class="comment"&gt;//In other words, "ensure that the goal which was accomplished was&lt;/span&gt;
&lt;span class="comment"&gt;//the ask-for-things goal".&lt;/span&gt;
      askGoal := oldScene rolesFor("consumer") first goals first
      h fluentValue("satisfied", askGoal, t)
    )
  ))
)
    &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
    &lt;p&gt;This might be all that's needed of a Scene.  The important part is that Scenes are fairly self-sufficient - they look into the previous scene to see if they can execute, and to grab the characters they need for their roles.  Note that the item involved between these scenes is encoded into the goals themselves.&lt;/p&gt;
  &lt;p&gt;At this point, one might be justified in saying that it's sleight of hand to simply provide these "And later..." definitions, but in the next essay, I'll show how these might be generated.&lt;/p&gt;
    &lt;h2&gt;Quest and Answer&lt;/h2&gt;
    &lt;p&gt;A Quest, recall, is a series of Scenes.  Since Scenes handle their own entrances, and the change of currentScene over time isn't really important to track, Quest can be fairly simple:&lt;/p&gt;
  &lt;blockquote class="support"&gt;&lt;pre&gt;&lt;code&gt;
Quest := Object clone do(
&lt;span class="comment"&gt;//All the Scenes that might show up in this Quest.&lt;/span&gt;
  possibleScenes ::= list()
&lt;span class="comment"&gt;//All the Scenes that count as endpoints for the Quest.&lt;/span&gt;
  finaleScenes ::= list()
&lt;span class="comment"&gt;//The currently active Scene.&lt;/span&gt;
  currentScene ::= nil
&lt;span class="comment"&gt;//The Scenes that have been played.&lt;/span&gt;
  completedScenes ::= list()
&lt;span class="comment"&gt;//Housekeeping.&lt;/span&gt;
  init := method(
    setCompletedScenes(list())
    self
  )
&lt;span class="comment"&gt;//Pick and segue to the next Scene.&lt;/span&gt;
  chooseNextSceneInAt := method(h, t, 
&lt;span class="comment"&gt;//Bail if we're in the middle of a Scene.&lt;/span&gt;
    if(currentScene satisfiedInAt(h, t) not, return false)
    if(satisfiedInAt(h, t),
      return true
    )
    available := possibleScenes select(i,v,
  completedScenes contains(v) not and(
   canSegueFromInAt(currentScene, h, t)
  )
 )
    completedScenes append(currentScene)
&lt;span class="comment"&gt;//We can choose randomly here, but a real implementation&lt;/span&gt;
&lt;span class="comment"&gt;//would be smarter and replace the simple 'canSegue...' with&lt;/span&gt;
&lt;span class="comment"&gt;//some numerical value for how good a match it is.&lt;/span&gt;
    next = available anyOne
    next segueFromInAt(currentScene, h, t)
    setCurrentScene(next)
    true
  )
  satisfiedInAt := method(h, t,
    finaleScenes contains(currentScene) and(
      currentScene satisfiedInAt(h, t)
    )
  )
)
&lt;span class="comment"&gt;//And later, in our quest generator...&lt;/span&gt;
DonutQuest := Quest clone do(
  setPossibleScenes(list(SceneOne, SceneTwo))
  setFinaleScenes(list(SceneTwo))
  setCurrentScene(SceneOne)
)
&lt;span class="comment"&gt;//And somewhere in our game code...&lt;/span&gt;
while(
&lt;span class="comment"&gt;//...&lt;/span&gt;
&lt;span class="comment"&gt;//Try picking the next Scene.&lt;/span&gt;
&lt;span class="comment"&gt;//If it returns true, something happened.&lt;/span&gt;
   if(currentQuest chooseNextSceneInAt(h, t),
&lt;span class="comment"&gt;//Is the quest over?&lt;/span&gt;
     if(currentQuest satisfiedInAt(h, t),
&lt;span class="comment"&gt;//The quest is over!&lt;/span&gt;
       startNextQuest()
       ,
&lt;span class="comment"&gt;//We must have a new scene...&lt;/span&gt;
       handleNextScene()
     )
  )
&lt;span class="comment"&gt;//...&lt;/span&gt;
)
 &lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
 &lt;p&gt;I say that the currentScene isn't important to track historically because what's important about a Scene happening in a Quest isn't the Scene itself, but the Fluents that are set as the Scene transpires.  Also, the stuff in the "game code" section above could be much nicer and written much differently - I just present it as a naive approach to using this kind of data.&lt;/p&gt;
 &lt;p&gt;So where does Herodotus really come in?  That would be in the Character memories, Goal tracking, quest histories, next-Scene picking, Scene conclusion, and so on.  Storing this information in Herodotus makes it a lot easier to write fancier quest generators, design better NPC simulations, and provide ays for Character actions to materially change the game world.&lt;/p&gt;
 &lt;p&gt;In the next essay, we'll look at how to generate these Donut quests and we'll make a simple text-based adventure game using Thucydides.&lt;/p&gt;
 &lt;p class = "support sig"&gt;Thanks to &lt;a href="http://www.cookingxp.com"&gt;Rboehme&lt;/a&gt; and the other participants in the &lt;a href="http://www.sourceforge.net/projects/questgen"&gt;questgen&lt;/a&gt; project.&lt;/p&gt;
&lt;/span&gt;</content><link rel='alternate' type='text/html' href='http://joe.garbagecollective.org/2008/02/designing-story.html' title='Designing a Story: Building Narratives from Story Atoms'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6497377610042929535&amp;postID=1846404872922985993' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://joe.garbagecollective.org/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/1846404872922985993'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6497377610042929535/posts/default/1846404872922985993'/><author><name>Joe Osborn</name></author></entry><entry><id>tag:blogger.com,1999:blog-6497377610042929535.post-1157376605066234548</id><published>2008-02-03T21:22:00.000-05:00</published><updated>2008-02-03T21:23:58.528-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='kids on campus'/><category scheme='http://www.blogger.com/atom/ns#' term='metaplace'/><title type='text'>Workshop Options</title><content type='html'>&lt;h2&gt;Some background&lt;/h2&gt;
    &lt;p&gt;RIT hosts a yearly summer tech workshop series for pre-high-schoolers called "&lt;a href="http://www.rit.edu/~kocwww"&gt;Kids on Campus&lt;/a&gt;".  I'll be teaching there this summer.&lt;/p&gt;
    &lt;p&gt;I traded some e-mails with the development VP of the Metaplace folks, Jason Hable(jason@areae.net).  Unfortunately, I couldn't get any additional information about how exactly Metaplace works, or how difficult it would be for first-timers who are also junior high school students or thereabouts.  It's worth noting, however, that anecdotal evidence from alpha testers and Areae employees suggests that even non-programmers can build a simple world very easily.  I've sent him another e-mail, but in the meantime, I have some loose plans for the workshops I would enjoy teaching:&lt;/p&gt;
 &lt;h2&gt;A Metaplace Of Your Own&lt;/h2&gt;
 &lt;p&gt;Work alone and in small teams(2-4 person) to design and build your own virtual worlds!  Metaplace is a toolkit and a social network for making and sharing games, avatar chats, or any other single- or multi-player online world.  You can put Metaplaces on your Facebook profile or your personal website, and share them with everyone!&lt;/p&gt;
 &lt;p&gt;Learning Objectives:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Real game and virtual world design techniques from the games industry!&lt;/li&gt;
  &lt;li&gt;Exposure to a brand-new way of developing online games&lt;/li&gt;
  &lt;li&gt;Programming in Metascript, a variation on the Lua scripting language&lt;/li&gt;
  &lt;li&gt;Sharing Metaplaces with friends and family&lt;/li&gt;
 &lt;/ul&gt;
 &lt;p&gt;Concerns:  Not enough information yet.  I'm sure that Metaplace will be available, or at least in open beta, by the summer, but without concrete information on how it is to use I don't know how much I want to advocate it.&lt;/p&gt;
&lt;a name="jump"&gt;&lt;/a&gt;
&lt;span class="fullpost"&gt;
 &lt;h2&gt;Game Design 101&lt;/h2&gt;
 &lt;p&gt;Analyze and dissect the board and computer game classics, old and new, to see what makes them tick - and what makes them fun.  Work individually or in small teams(2-4 person) to make your own unique board or card game.&lt;/p&gt;
 &lt;p&gt;Learning Objectives:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Real game design techniques from the games industry!&lt;/li&gt;
  &lt;li&gt;Survey of trends in board and computer game design&lt;/li&gt;
  &lt;li&gt;Practice in "paper prototyping", a process used by real game designers to polish their computer games' core gameplay&lt;/li&gt;
  &lt;li&gt;Exposure to formal methods in game design and the budding field of "ludology".&lt;/li&gt;
 &lt;/ul&gt;
 &lt;p&gt;Concerns: Is there enough of a connection to the "tech" here?  I would love to make a whole course out of this, though I could compress it down to four days if I had to for one of the other programming courses.&lt;/p&gt;
 &lt;h2&gt;Game Design and Development with RubyGame&lt;/h2&gt;
 &lt;p&gt;Work in small teams(2-4 person) and make a game from start to finish with the Ruby programming language and the RubyGame framework.  Use real-world game design techniques with a real-world programming language!&lt;/p&gt;
 &lt;p&gt;Learning Objectives:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Real game design techniques from the games industry!&lt;/li&gt;
  &lt;li&gt;Exposure to many independent games&lt;/li&gt;
  &lt;li&gt;Programming in Ruby, a popular new programming language&lt;/li&gt;
  &lt;li&gt;Basics of 2D graphics and animation&lt;/li&gt;
 &lt;/ul&gt;
 &lt;p&gt;Concerns: This is a lot of topic to cover in 9 days.  I want to use Ruby instead of something like Flash because Ruby is simple, free, and kids can acquire it easily, plus it can be used for many things besides animation and games.  Would this overlap too much with the Flash workshop?&lt;/p&gt;
 &lt;h2&gt;Fun and Board Game Design&lt;/h2&gt;
 &lt;p&gt;A world of board and card games exists beyond Monopoly and Sorry!.  Meet fun, interesting board games from Europe and the United States, and work individually and in small teams(2-4 person) to make your own unique board and card games!&lt;/p&gt;
 &lt;p&gt;Learning Objectives:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Exposure to games such as Icehouse, Kill Doctor Lucky, Settlers of Catan, Carcasonne, and other significant board games&lt;/li&gt;
  &lt;li&gt;Capturing a theme or feeling and expressing it in a board game&lt;/li&gt;
  &lt;li&gt;Recognizing the elements of fun and improving on them incrementally with testing&lt;/li&gt;
 &lt;/ul&gt;
 &lt;p&gt;Concerns: I think this is fascinating because I know about these games, but to someone who doesn't know about the really interesting board games, it might not be compelling.&lt;/p&gt;
 &lt;h2&gt;8-Bit Music&lt;/h2&gt;
 &lt;p&gt;Compose your retro magnum opus!  Learn how people are using old video game hardware to make fantastic modern music, from techno to hip-hop, from rock and roll to heavy metal, and from classical to country.  Choose your weapon - NES or Game Boy - and learn how to write "chiptunes", the first music genre of this generation.&lt;/p&gt;
 &lt;p&gt;Learning Objectives:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;A basic introduction to assembly language programming and computer organization&lt;/li&gt;
  &lt;li&gt;History of video game systems since 1980&lt;/li&gt;
  &lt;li&gt;Composing and arranging music with a limited sonic palette, using either t