Zillions of Games Feedback

This page contains feedback for the Zillions of Games development group on improvements that might be made for a possible Zillions of Games 2.0 product. Authors are Joao Neto and Adrian King.

This page was formatted by David Howe.

João's feedback
Adrian's feedback



Feedback from João Pedro Neto

*** Proposals for ZRFs (version 1.1)

Here are a bunch of suggestions for an update of the ZRF language.
Let's shoot in all directions, in order to hit something! :-)

  *****************************************
  * comments for blocks, like the /* */ comments in C

  *****************************************
  * (last-player?   player)
  * (actual-player? player)
  * (next-player?   player)

      true if the last/actual/next player is <player>

  *****************************************
  * (piece-of-player? player [position|direction])
  
      true if the piece is of <player>

  *****************************************
  * <any-piece> declaration for win/loss-conditions

  *****************************************
  * Real global flags for the entire game (boolean and 
    position data type)

     e.g., (set-global var_name bool_value)
           (set-global var_name position-name)

    with a place in the (game ) block for initialization

     e.g.
          (game ...
                ... (set-global var_name bool_value) ...
          )           

    This is ideal for many things, e.g, for programming KO rules 
    (you can save the tabu square to compare later).

    Also, with position variables, there can be instructions like,

     (send-piece position1 position2)

    to send a piece from one position to another, in a more
    direct way.

    Just a side thought: It's a known result of Theory of Computation 
    that if you have a programming language with iteration, conditional 
    and global memory, you have Turing Equivalence (that is, you can 
    make everything that is computable), at least up to the available
    memory. 

    I'm not sure if the ZoG memory system satisfies the requirements 
    for Turing Equivalence. This may mean that certain board games 
    cannot be implemented, even with hard and/or unelegant work. 
    And that's nasty, because it's impossible to have a procedure 
    to decide if a game (defined by an algorithm) is programmable 
    or not.

  *****************************************
  * The option of a piece moved by other player, to be able to use 
    the player's symmetries only in that move turn, Nice to handle
    neutral pieces that act differently depending of who is moving
    them (eg. the Holes in Amoeba)

    e.g.,

    (piece ...
       (user-symmetry true) ...
    )

  *****************************************
  * Multiple Mark/Back mechanism, using a Stack and/or a Queue

  *****************************************
  * ForEach instruction, a loop process for iterate elements in a set

    e.g.,

    (foreach (<square> in <some-zone>)
       ; stuff using <square>
    )

    With this instruction, there may have some set generators,
    for e.g.,

      - (found-pieces (<player> <piece>) (...) ... )
      - (found-pieces (<player> any-piece) )
      - (found-pieces (any-player any-piece) )
        ...

       returns the squares where these pieces are

      - (found-pieces (condition) )
 
       returns the squares where the pieces with condition true are
       (e.g., (found-pieces (attacked?) ), get all attacked pieces)

      - (found-marked-squares)

       returns all marked squares

      - (found-attribute <attr-name> <value> )

       returns the squares where the pieces that have <attr-name>
       with value <value>

  *****************************************
  * A CASE statement. This may be useful, if ZRF starts handling
    non-boolean variables and functions.

    e.g., 

    (case (actual-player) 

      ( (White) (...stuff...) )
      ( (Black) (...stuff...) )
      ( (Red)   (...stuff...) )

    ) ;endcase

  *****************************************
  * Integer types with aritmetic (+,-,*,/,trunc,round) and 
    relacional (>,<,=,<> ...) operators. 
    Also, local and global integer variables would be nice.

  * Random Numbers,
      e.g., rand(n) gives a number between 0 and n-1 
            with normal distribution

  Possibly, ZoG doesn't have integer types because 
  of performance reasons (At least it is not real aritmetic :-).

  *****************************************

  A last note: we know very well that it is easier to propose
  things than to make them! I want to thank ZoG team for such 
  a great game!!!

  And thank you very much for reaching EOF :)

               Joao Pedro Neto (vascog@uol.com.br | jpn@di.fc.ul.pt)





Feedback from Adrian King

(adrian@uranos.xidak.com)

Foreshadowing

In my programming career, I've had occasion to design a handful of special-purpose microlanguages, though they were generally not as ambitious as ZRF. It is my experience that as soon as you unleash such a thing on the world, users will immediately want to push the microlanguage far beyond its intended boundaries. If you want to satisfy the users, you almost always wind up creating something close to a full-fledged general-purpose programming language. We might call this the Law of Microlanguages: "Bloat or die". This will presumably be ZRF's fate as well, and from Jeff and Mark's point of view, probably the best they can hope for (if they want to keep ZRFers reasonably happy) is managed bloat rather than no bloat.

What Zillions Has Now in the Way of Programming Facilities

In thinking about what I want from Zillions, I've found it useful to try to inventory what Zillions already has. The Zillions documentation has not always made this easy, but here's my understanding of what's there.

One thing to be clear on is that computation doesn't take place in Zillions the way it would in a normal programming language. Each game state that Zillions examines needs to have its own copy of the values of all variables that are persistent from state to state, so that there is not a unique copy of so-called "global" variables. Zillions has to deal with a large number of parallel universes, each cloned from a preceding universe, and each with its own copy of the state of every persistent variable.

One problem with the ZRF documentation is the lack of consistency in terminology, which is very confusing. The blocks in which instructions can occur (e.g., the arguments to "moves") don't seem to have a single name; they seem to be called, among other things, "move generation block", "move block", and "<move-def>". I'll call them "action blocks"; they're the places where the allowable actions in the game are computed. The entire block headed by "moves", which can contain many action blocks, I'll call a "moves block". Note that a "drops" block is also considered to be an action block.

What Zillions has now:

Data Types Zillions Needs

Unquestionably, a lot of games could be described a lot more easily if Zillions had integer variables and expressions. You can simulate arithmetic with boolean logic by means of computations like:

if a-is-1 and b-is-1 then set sum-is-2 true 
else if a-is-1 and b-is-2 then set sum-is-3 true 
else if a-is-2 and b-is-1 then set sum-is-3 true 
else if a-is-2 and b-is-2 then set sum-is-4 true... 

but this is exhausting if a and b can take on are more than a tiny range of values.

Some kinds of computations would probably be easier if there were a higher-level data structure such as sets, arrays, or lists that could contain elements of primitive data types (and perhaps contain set, array, or list elements). This would be the kind of thing you would return from the "set generators" (e.g., found-pieces) David Howe described in his message to me. However, this kind of data structure might be more work to implement, and is probably lower priority for ZRF programmers than the ability to work more generally with the primitive data types. Below, I'll refer to this kind of data structure as "list", although some other structure might be implemented instead, if any is implemented.

Data Types of Which the Programmer Should Be Able to Declare Variables

A ZRF program should be able to declare (at least implicitly, by setting the variable) a variable of any of the types ZRF recognizes, except possibly string. Ideally there would be a way to have variables of type boolean, position, direction, piece, player, movetype, integer, and list.

With the ability to have a variable of a given type you'll want the ability to have expressions of those types, meaning you need operators that take those types as arguments. For every type you want a way to compare 2 values for equality or inequality (yielding a boolean result), and the ability to set a variable to a value of its type. Other possible operators:

    and, not, or:     boolean operators, already provided 
(owner <position/direction>): 
    returns <player>; owner of piece at 
    position 
last-player, current-player, next-player: 
    return <player> of previous, current, 
    following turn 
current-position:   return the current <position> (applicable 
    only in an moves block) 
current-piece:     <piece> whose move is being calculated 
current-movetype:   <movetype> being calculated 
(+/-/*///... <integer> <integer> ...): 
    return <integer>; the usual operators 
(</>/<=/>= <integer> <integer>): 
    return <boolean>; integer comparisons 

Possible list operators:

(append <list> <value>) 
(push <list> <value>): 
    push is same as append, but thinking of 
    the list as a stack; return value 
            pushed/appended 
(prepend <list> <value>): 
    like append, but add to start of list 
(pop <list>):     remove and return last item of list 
(remove-head <list>): 
    remove and return first item of list 
(list-item <list> <integer>): 
    return <integer>th item of list 
(delete-list-item <list> <integer>...) 
    delete specified items in list 
(insert-list-item <list> <integer> <value>) 
    insert specified items in list 

Times When Computations Should Be Able to Be Performed

Arbitrary computation (by which I mean doing anything except changing the state of the board; that should be allowed only in action blocks) should be able to be performed at any of the following times:

When computation is performed at the start of a turn, the resulting variable values are saved; those values are then restored at the start of the moves block for each piece (since a moves block can change the variables further). Similarly, when computation is performed at the start of a moves block, values are saved and then restored at the start of each action block.

Temporal Durations and Scopes of Variables Zillions Should Support

Of course, allowing arbitrary computation at various points is not useful if Zillions immediately forgets the results. That means some additional durations and scopes need to be allowed for variables.

A persistent variable's value at the start of a turn is the same value it had at the time of the "add" for the last move made.

Desirable Control Structures

A "case", in addition to the current "if" and "while", would be syntactically convenient, although I don't know that it would have much advantage over a series of ifs.

Example:

(case (owner $1) 
    ( (White) ... ) 
    ( (Black) ... ) 
    ... 
) 

"foreach" might offer more benefits in terms of concision, especially in conjunction with list variables (the first argument to foreach could presumably be a list expression).

Example: 

(foreach x (north south east west up down) (check-for-adjacent-paralyzer x) )

Out-of-line procedure calls (rather than macro expansions) might allow some of the more complicated games to fit in memory. A fairly complicated game like the 4-dimensional Chesseract requires specifying moves in so many different directions that it's easy to generate enormous macro expansions. Presumably these would be slower to call than a macro; the programmer would have to use them judiciously.

Example: 

(define-proc check-for-adjacent-paralyzer 
    ; set paralyzer-adjacent? if enemy Paralyzer is adjacent in 
    ; direction $1 
    (if (on-board $1) 
    ... (set-flag paralyzer-adjacent? ...) ... 
    ) 
) 

Desirable Actions

These are miscellaneous things that are hard to do right now.

These operations could only be allowed in an action block, and generally take effect only when the following "add" occurs:

These actions should, if possible, take place in the order in which they were specified in the moves block; otherwise, the programmer may get very confused about what happens when. Instructions that set persistent variables should also take place in the same order, so that if I do these operations in this order:

I wind up with piece z in the off-board pool, its variable v set to x, and y's variable v still has the same value it had while y was in the off-board pool.

These actions have to do with modifying the turn order:

More Stuff

The limit of 1000 distinct symbols is easily exceeded for very large boards, which may have more than 1000 positions even if the game is not particularly complex. It would be helpful to increase this.

Debugging

ZRF programmers are adventurous but not infallible. Adding a sophisticated debugger to Zillions would be swell but probably not worth the effort. However, it sure would be nice to have the debugger of last resort, namely some kind of print statement, e.g.:

(print "The " current-piece " is now on " current-position "\")

When this statement was reached, it could display its output to the "Moves Played" window:

The Knight is now on e6

Used incautiously, this could result in a prodigious amount of output; used judiciously, it could allow ZRFers who have lost their way to see where they have gone wrong.

How Zillions Treats the Off-Board Pool

I'd think it would be advantageous to make the off-board pool more explicitly available to the player, as well as to the ZRF programmer. If the pool could be controlled well enough to be used in Shogi, then you'd want a display of the current contents of the pool, so that you'd know what pieces you have in hand. I'd suggest that the pool should be displayed in another subwindow of the Zillions window (although the display should probably be suppressed if the game is known not to make use of the pool).

The pool is sort of like a special "position" that, unlike all other positions, is capable of containing an indefinite number of pieces of different types and owners.

How Zillions Displays Possible Moves

When you select a piece, Zillions puts green circles on the places it thinks the piece can go. If the piece you select cannot move itself, but can cause something to happen on some other position (e.g., capturing a piece by shooting), Zillions doesn't always let you "move" the piece (at least not if you program the move in the most straightforward way).

I would have thought that Zillions would use a different algorithm to determine how to mark the possible "destination" squares. I'd imagine that any position (including the pool) whose content could change by the move of a piece would be marked as a possible destination for that piece; if you dragged the piece to that position, and more than one move could affect that position, you'd get a menu to choose which move you wanted.

This means that sometimes the starting square of the piece would also be marked, e.g., in cases where the piece can promote in place. In such cases you'd also want to mark the starting square as a possible destination, so that picking up the piece and dropping it on the same square could select a move that affects the starting square.

As an exception, you probably wouldn't want to mark the starting square as a possible destination if it wound up empty and the piece that was moving wound up on another square (this is the way most kinds of chess pieces move). In this case, it would probably be more useful to mark only the square where the piece wound up.

Another possibility is to include in the ZRF language an operator that says "after adding this move, when the human player selects the current piece, display symbol x on square y (and actually make the move if the player drags the piece to square y)". That would certainly cover any cases where the game designer's desires didn't match Zillions's default behavior.

As a detail, you probably don't want to allow a ZRF file to generate moves whose results differ only by variable settings. For example, if you generate 2 moves, one of which moves the Flarg at a1 to b2 and sets the Flarg's attribute cool? to false, and the other of which moves the Flarg from a1 to b2 and sets its attribute cool? to true, Zillions should probably consider this an error rather than giving you a menu that tries to describe how the variable settings changed in the 2 different moves. Variables, in this view, should be visible to the programmer but not the player. Similarly, Zillions should flag an error if a move is generated whose sole effect is to change the value of variables without altering the kind, owner, or number of piece(s) on any position (counting the pool as a special position).

And in Conclusion May I Say

It may sound as if I'm being critical of ZRF, but dang, I wish I'd thought of it.