Joel Uckelman on Thu, 5 Aug 2010 09:27:20 -0700 (MST)


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[game-lang] defining static parts of games


I'm thinking about how one would go about defining static game features,
i.e., components which don't change with the game state. I'm using some
sort of Prolog-ish language here to describe a small hex grid and the
adjacency relation on it. I'm expecting that the people who will be using
this would not be writing the adjacency rules themselves, but rather the
adjacency rules would be something they'd import from a library.

#
# This is a 3-column, 3-row hex grid. 
# 
hex([0,0]).
hex([0,1]).
hex([0,2]).

hex([1,0]).
hex([1,1]).
hex([1,2]).

hex([2,0]).
hex([2,1]).
hex([2,2]).

#
# Adjacency. Note that odd columns are up columns.
#

# These are the four adjacencies which hold for all columns 
adj(a,b) :- hex(a) & hex(b) & col(a)-1 = col(b) & row(a)   = row(b).
adj(a,b) :- hex(a) & hex(b) & col(a)   = col(b) & row(a)-1 = row(b).
adj(a,b) :- hex(a) & hex(b) & col(a)   = col(b) & row(a)+1 = row(b).
adj(a,b) :- hex(a) & hex(b) & col(a)+1 = col(b) & row(a)   = row(b).

even(n) := int(n) & n % 2 = 0.
odd(n)  := int(n) & !even(n).

# These are the adjacencies specific to even columns
adj(a,b) :- hex(a) & hex(b) & col(a)-1 = col(b) & row(a) = row(b) & even(col(a)).
adj(a,b) :- hex(a) & hex(b) & col(a)+1 = col(b) & row(a) = row(b) & even(col(a)).

# These are the adjacencies specific to odd columns
adj(a,b) :- hex(a) & hex(b) & col(a)-1 = col(b) & row(a) = row(b) & odd(col(a)).
adj(a,b) :- hex(a) & hex(b) & col(a)+1 = col(b) & row(a) = row(b) & odd(col(a)).



This takes care of the edges properly---hex([0,-1]) is false, for example---
so hex([0,0]) has only three adjacencies. It's not too bad for readability.
You have to specify the hexes manually, which will be painful for a map
which is 100x100, but the adjacency relation works for grids of any size
(which have N-S grain and odd colulmns as up columns).

Some repetition syntax would be nice. I sort of feel like doing this:

  for (int r = 0; r < 4; r++) {
    for (int c = 0; c < 4; c++) {
      printf("hex([%d,%d])", c, r);
    }
  }

where the loop is *not* part of the logic program----rather, it means
that "hex[c,r]" will be printed into the program the desired number of
times. (Metaprogramming can be quite handy.)

Or, perhaps, just do this:

  hex([c,r]) :- 0 <= c & c < 4 & 0 <= r & r < 4.



What else is going on here?

* There is arithmetic.

* There are some other functions which are not boolean-valued, namely
  col() and row(), which are just the obvious projection functions from 
  coordinate pairs. If you can't define functions which are not predicates,
  then I suspect things will become ugly very quickly. For example, if
  you're forced to write col() as a two-place predicate col(h,c) which is
  true iff c is the column component of h, then simple things like the
  tests I wrote above become harder:

    col(a)+1 = col(b)

  gets translated to:

    col(a,c+1) & col(b,c)

  where c is a free variable. I find this harder to read.

-- 
J.
_______________________________________________
game-lang mailing list
game-lang@xxxxxxxxx
http://lists.ellipsis.cx/mailman/listinfo/game-lang