Patheos

BuddhistCatholicContemplativeEvangelicalGeneral ChristianHinduJewishLatter-day SaintMuslimNew VisionsProgressive Christian

Beliefs

Topics

Columnists

Resource Library

Research Tools

Video

Podcasts

Thought Readers

Faith In Media Tracker

Newsletters

Ad-Free & Subscriber Log-In Subscription Support

Patheos

Ad-Free & Subscriber Log-In Subscription Support

Follow Patheos Patheos on Facebook Patheos on YouTube

Cry 'Woof'

Adventures in Clojure: The Fact Base

Last updated on: August 9, 2014 at 3:35 am   by willduquette

Adventures in Clojure: The Fact Base 2014-08-08T19:35:38-05:00 willduquette

LOGO Patheos Explore the world's faith through different perspectives on religion and spirituality! Patheos has the views of the prevalent religions and spiritualities of the world.

clojure When you’re writing a game based around a game world of some kind, be it a text adventure like Zork, an action adventure like The Legend of Zelda, or any number of other games, there’s stuff your game needs to remember. A lot of it has to do with the player: where is he, how much health does he have, does he have the Iron Mitts of Cooking that let him invade and conquer the Iron Chef Temple of Cuisine?

But on top that, there are a lot of just plain facts to remember. Where has he been? What areas have been unlocked? What puzzles have been solved, what are still vexing him, and which ones have yet to be discovered?

You’d like to keep all of this information in one place, so as to make it easy to save it with the rest of the game data; and you’d like it to be easy to update and query.

My solution was to define the notion of a fact. A fact is a vector of values, usually keywords, that together indicate something true about the game world. Here’s my initial set of facts:

(def facts 
  (atom #{
   [:sewer :clogged]
   [:tv :broken]
}))

The :tv is an object, the player’s television. It’s broken at the start of the game; the player needs to fix it. And there’s another problem; down the street, the sewer’s clogged. It’s not yet clear whether the keyword :sewer refers to any explicit entity; our player may never lay eyes on the sewer, but he might unleash a flood that breaks through the clog (thus removing this fact from the fact base) and thereby making that annoying smell go away.

I’ve used an atom to contain the facts; another possibility would be to represent the full set of game data in a single map value that gets updated with each move the player makes, as several commenters suggested on my last post. They may well be right; but since my programming time has all been devoted to Quill in recent weeks, I’m presenting the game code as it is rather than as it might be.

The facts atom contains a set of facts; a set is a data structure that mimics a mathematical set, and can contain at most one of any given value. You can do all of the usual set operations on them, but the most basic operations are to put a value into the set, and to remove it from the set. For this, Clojure defines the conj (conjoin) function, and the disj (disjoin) function. Each takes a set and a value, and returns a set that either contains or does not contain the value.

Since the set is in an atom, we use swap! in conjunction with conj and disj to add and remove facts:

(defn add-fact! [f]
  (swap! facts conj f))

(defn remove-fact! [f]
  (swap! facts disj f))

The exclamation point indicates that these functions mutate global state.

Next, we need a query: is a putative fact actually a fact? Is the :sewer still :clogged? A value f is a fact if @facts contains? it; otherwise it is not a fact. Thus, I could define my query fact? like this:

(defn fact? [f] (contains? @facts f))

But I found it useful to extend the notion of a fact a little. If the first element of the fact vector is :not, then I want fact? to return true if the remaining elements of the vector are not in the fact base. In other words:

=> (fact? [:sewer :clogged])
true
=> (fact? [:not :sewer :clogged])
false
=> (fact? [:fred :dead])
false
=> (fact? [:not :fred :dead])
true

In this way, both facts and the negations of facts have exactly the same form, a simple vector. The following version of fact? gives the desired behavior:

(defn fact? [f]
  (if (not= (first f) :not)
    (contains? @facts f)
    (not (contains? @facts (rest f)))))

For extra credit, I could make it recursive; and I probably should.

Finally, for convenience I’ve got if-fact, where (if-fact f x y) is equivalent to (if (fact? f) x y). It looks like this:

(defn if-fact
  ([f x]   (if-fact f x nil))
  ([f x y] (if (fact? f) x y)))

Woof Guide to Technology

clojure

Previous Post



August 8, 2014

St. Dominic

Next Post



August 10, 2014 What's a Meme? Let me count the ways....


Browse Our Archives

Select a Category Admin App o' the Morning Ask the Dogmat Believing Thomas Bits of Fiction Blasts from the Past Bootstrapping the Interior Life Catholic Mom Christian Living Deep Thoughts from the Doghouse Dominicana Evangelii Gaudium Interviews It Was A Dark and Stormy Night Links to This and That Lumen Fidei Meme Watch On Writing Operation Gratitude Pedant Errant Photography Quill Random Barkings S'Mary's World Shakers of Salt Software Development The Dog Whistler The Dogmat Sez Third Orders Thomas Aquinas Uncategorized Vikings at Dinos Woof Guide to Cinema Woof Guide to History Woof Guide to Literature Woof Guide to Obscure Catholic Music Woof Guide to Philosophy Woof Guide to Popular Music Woof Guide to Technology Woof Guide to Theology Words I Wish I'd Written Works For Me

Select a Month September 2016 August 2016 June 2016 May 2016 April 2016 March 2016 February 2016 January 2016 December 2015 November 2015 October 2015 September 2015 August 2015 July 2015 June 2015 May 2015 April 2015 March 2015 February 2015 January 2015 December 2014 November 2014 October 2014 September 2014 August 2014 July 2014 June 2014 May 2014 April 2014 March 2014 February 2014 January 2014 December 2013 November 2013 October 2013


Follow Us!

Follow Us on Facebook Follow Us on Twitter



TAKE THE

Religious Wisdom Quiz

Who said, "The Lord will fight for you; you need only to be still"?

Select your answer to see how you score.

Solomon Joshua David Moses

Related posts from Cry 'Woof'

Catholic

Second Look: Amazon Echo after One Week

Cry 'Woof'

Catholic

First Look: Amazon Echo, or Alexa Tells You...

Cry 'Woof'

Catholic

Kindle and the Calibre App

Cry 'Woof'

Catholic

Book Reader Notes: Kindle vs. iBooks vs. Google...

Cry 'Woof'

TRENDING AT PATHEOS Catholic

Rejecting Doom: Christian Hope And Human Action

Christianity is a religion of hope. We are to have hope and...

It’s What Comes From Within Which Matters

One of the most difficult things for us to understand is why...

Why I Choose the Eucharist Over the Sermon

Choose the Eucharist, Not the Sermon What are we supposed to get...

5 Design Elements Found in Spiritually Rooted Homes

Putting Spirituality Into Home Decor Our homes are more than our living...

Credo: A Story of God Told with the...

About 10 years ago, I began to imagine a personal "Credo" that...

The Anatomy of Divine Revelation in Catholic Thought

The claim that God has made Himself known to human beings is...

view all Catholic blogs

Patheos on Facebook Patheos on YouTube

Ad-Free & Subscriber Log-In Subscription Support

Copyright 2008-2026, Patheos. All rights reserved.

Subscription Support Ad-Free & Subscriber Log-In

Follow Patheos Patheos on Facebook Patheos on YouTube