Utility functions for Zillions rule f... Log Out | Topics | Search
Moderators | Register | Edit Profile

Zillions of Games Discussion Forum » Designing Games for Zillions » Utility functions for Zillions rule files « Previous Next »

Author Message
Patrick S. Duff (Pduff)
Posted on Monday, October 23, 2000 - 9:33 pm:   

Here's an update to my counter functions. In this version, you can have more than one counter. Just use the name of the counter as the first argument to each function.

I've added the function "max-counter".

There are three new functions, "set-counter", "add-counter" and "subtract-counter", which take two counter names as their arguments.

As written, these counter functions will handle values from 0 to 15. If you need to count higher than 15, just add more bits following the same pattern.

Be aware that all counters are automatically reset to zero by Zillions at the beginning of each move generation block.

[Unfortunately, the indentation isn't displayed properly by this discussion software. You'll have to add it back in yourself.]

(define reset-counter
; Set counter $1 to 0
(set-flag $1-1 false)
(set-flag $1-2 false)
(set-flag $1-4 false)
(set-flag $1-8 false)
)

(define increment-counter
; Add 1 to counter $1 (Warning: no overflow detection)
(set-flag Carry (flag? $1-1))
(set-flag $1-1 (not-flag? $1-1))
(if (flag? Carry)
(set-flag Carry (flag? $1-2))
(set-flag $1-2 (not-flag? $1-2))
)
(if (flag? Carry)
(set-flag Carry (flag? $1-4))
(set-flag $1-4 (not-flag? $1-4))
)
(if (flag? Carry)
(set-flag Carry (flag? $1-8))
(set-flag $1-8 (not-flag? $1-8))
) )

(define decrement-counter
; Subtract 1 from counter $1 (Warning: no underflow detection)
(set-flag $1-1 (not-flag? $1-1))
(set-flag Carry (flag? $1-1))
(if (flag? Carry)
(set-flag $1-2 (not-flag? $1-2))
(set-flag Carry (flag? $1-2))
)
(if (flag? Carry)
(set-flag $1-4 (not-flag? $1-4))
(set-flag Carry (flag? $1-4))
)
(if (flag? Carry)
(set-flag $1-8 (not-flag? $1-8))
(set-flag Carry (flag? $1-8))
) )

(define not-zero-counter
; Is counter $1 greater than zero?
(or (flag? $1-1)
(flag? $1-2)
(flag? $1-4)
(flag? $1-8)
) )

(define max-counter
; Is counter $1 set to its maximum value?
(and (flag? $1-1)
(flag? $1-2)
(flag? $1-4)
(flag? $1-8)
) )

(define set-counter
; Set the value in counter $1 to the value in counter $2
(set-flag $1-1 (flag? $2-1))
(set-flag $1-2 (flag? $2-2))
(set-flag $1-4 (flag? $2-4))
(set-flag $1-8 (flag? $2-8))
)

(define add-counter
; Add the value in counter $2 to counter $1 (result in counter $1)
(while (and
(not-zero-counter $2)
(not (max-counter $1))
)
(increment-counter $1)
(decrement-counter $2)
) )

(define subtract-counter
; Subtract the value in counter $2 from counter $1 (result in counter $1)
(while (and
(not-zero-counter $1)
(not-zero-counter $2)
)
(decrement-counter $1)
(decrement-counter $2)
) )
Patrick S. Duff (Pduff)
Posted on Tuesday, October 24, 2000 - 7:52 am:   

I stated above that all counters are automatically reset to zero by Zillions at the beginning of each move generation block. I've now been informed that while "position-flags" are automatically reset to zero at the beginning of each move generation block, "flags" are not. This should mean that counter values will persist from move to move, so things like turn counters are possible.

However, the help file says "Flags are intended to be used only within a move generation block, rather than across them". This doesn't say it won't work. I guess if you want to use them across move generation blocks, you should test everything carefully!
Jeff Mallett (Jeffm)
Posted on Tuesday, October 24, 2000 - 1:01 pm:   

Hi,

A reason you'd need to be careful about assuming a flag set in one move block will be valid in another move block is that Zillions doesn't guarantee what order move blocks for a piece will be processed in. If you would like to set flags once and then use them throughout the entire move generation for a piece, you would need to try to do all move generation in a single move block. For instance, instead of running off the edge of the board by repeatedly going in a direction, use on-board? to detect the board edge and then jump back to the start position before processing a new direction.
David GLAUDE (Glu)
Posted on Tuesday, October 24, 2000 - 2:49 pm:   

Pre and Post move generation code.
Maybe we need to have the option to add a
Pre- and Post- move code.
In order to have a way to initialise and use some flag computation without the need to put everything into one move "block".

David GLAUDE
Jens Markmann (Jensm)
Posted on Wednesday, October 25, 2000 - 1:56 am:   

I experimented with a kind of 'global pre-move generation' code. For this I used a move block that has topmost move-priority, but doesn't contain an add. It should always be executed first due to its priority, but since it doesn't actually generate moves, it doesn't prevent other moves, and is thus very useful to set and reset flags.
However, it is possible that this technique fails in some case. As Jeff said, the order of the action blocks is not guaranteed, altough their order seems much more stable to me than the order in which the pieces generate their moves.
Anyway, with the new ability to generate moves with a DLL, all this clever ZRF hacking probably becomes obsolete; or not?
Patrick S. Duff (Pduff)
Posted on Thursday, October 26, 2000 - 5:42 am:   

I've been trying unsuccessfully to get your suggestion working.

I've defined a macro named "init" which sets flags but does not add any moves, and a macro named "shift" which adds moves based upon the current flag settings. Because running "init" is very expensive, I only want to run it once for each friendly piece on the board.

Suppose I have (move-priorities Initialize Shift-Piece) and then do:

(moves
(move-type Initialize)
((init))
(move-type Shift-Piece)
((shift n))
((shift e))
((shift s))
((shift w))
((shift ne))
((shift nw))
((shift se))
((shift sw))
)

I expect this to find a friendly position on the board, run (init) with that position marked, then run all of the calls to shift with that position marked, then go to the next friendly position and repeat. Instead, it acts like Zillions is getting confused about which board position is being considered during execution of "init". Ten hours (!) of painstaking debugging has proven to me that calls to (on-board?) which should be succeeding are failing inside "init". "init" does not have any "mark" calls, so "back" should always take me to the position for which moves are being generated (according to the help file!). However, I've proven that "back" is taking me somewhere else. Adding extra calls to "mark" and "back" everywhere doesn't help either.

But if I do:

(moves
((init) (shift n))
((init) (shift e))
((init) (shift s))
((init) (shift w))
((init) (shift ne))
((init) (shift nw))
((init) (shift se))
((init) (shift sw))
)

Then everything works, but runs slowly because of all the extra calls to "init".

How did you get your "global pre-move generation" code to work?
Jens Markmann (Jensm)
Posted on Thursday, October 26, 2000 - 10:25 am:   

>I expect this to find a friendly position on the board, run (init) with that position >marked, then run all of the calls to shift with that position marked, then go to the next >friendly position and repeat.

I don't think this expectation is correct; as 'Initialize' has priority, Zillions should generate 'init' for one piece, then 'init' for the next piece and so on, and then, in a second run, do the shifts. Do your observations confirm that order?

When I said 'global', I meant once per turn. Since you want something once per piece, have you tried removing the priorities, simply relying on Zillions processing the action blocks from top to bottom for every piece? I often get very good results with that.

>How did you get your "global pre-move generation" code to work?

Well, you hit the weak spot there. I tried something similarily complex in Camelot (I want to scan the board for captures at the beginning of every turn), but after hours of testing, it showed up the computer player would sometimes get moves it shouldn't have. I still don't have a satisfying explanation for that, but strange and unsupported interactions between flags and move priorities might be the cause.
Anyway, that's an argument to keep the code simple, and so I refer you to Cheskers ZRF, which uses such a 'global pre-move generation' just to reset one flag at the beginning of every turn, and also appears to work all the time.
chessvariants.com might have this ZRF; if not, I could email it if you want.
John Henckel (Jdhenckel)
Posted on Sunday, November 18, 2001 - 5:25 pm:   

This ZRF hacking to simulate integers using several bits seems very silly to me. Isn't anyone maintaining the Z engine? If so, why don't they just add integer attributes? It can't be that hard.

Add Your Message Here
Post:
Username: Posting Information:
This is a private posting area. Only registered users and moderators may post messages here.
Password:
Options: Enable HTML code in message
Automatically activate URLs in message
Action: