Check out Janggi (Korean Chess), our featured variant for December, 2024.


[ Help | Earliest Comments | Latest Comments ]
[ List All Subjects of Discussion | Create New Subject of Discussion ]
[ List Earliest Comments Only For Pages | Games | Rated Pages | Rated Games | Subjects of Discussion ]

Single Comment

Jocly. An html-based web platform for playing 2-player abstract stategy games.[All Comments] [Add Comment or Rating]
H. G. Muller wrote on Fri, Dec 15, 2023 01:13 PM UTC:

I have been writing a short description of the features offered by the fairy-move-model.js module, and how these can be used:

Programming with sub-models

To enhance the support for chess variants with fairy pieces,
several sub-models were created.

fairy-moves-model.js

This sub-model, when included in the model build with base-model.js,
will provide various forms of support that chess variants featuring
unorthodox pieces would often need. This ranges from new routines
for generating move graphs of often encountered unorthodox pieces,
move-mode flags for some common forms of locust capture (i.e.
removal of pieces on other squares than the destination of the move),
and anti-trading rules.

Move graphs.

Several new routines for creating the graphs for fairy pieces are
available. These are (as they would be used in the game's model file
for defining the piece moves):

this.cbCamelGraph(geometry, confine);      // [1,3] leaper
this.cbZebraGraph(geometry, confine);      // [2,3] leaper
this.cbElephantGraph(geometry, confine);   // [1,1] and [2,2] leaper
this.cbWarMachineGraph(geometry, confine); // [2,0] and [1,0] leaper
this.cbAlibabaGraph(geometry, confine);    // [2,0] and [2,2] leaper
this.cbWizardGraph(geometry, confine);     // [1,1] and [1,3] leaper
this.cbChampionGraph(geometry, confine);   // [1,0],[1,1] and [2,0] leaper
this.cbVaoGraph(geometry, confine);        // diagonal XQ Cannon
this.cbCardinalGraph(geometry, confine);   // Knight-Bishop compound
this.cbMarshallGraph(geometry, confine);   // Knight-Rook compound
this.cbAmazonGraph(geometry, confine);     // Knight-Queen compound
this.cbGriffonGraph(geometry, confine);    // R after F bent slider
this.cbRhinoGraph(geometry, confine);      // B after W bent slider

More general routines for creating graphs are:

this.cbSkiGraph(geometry, stepSet, flag, bendAngle, iflag, range);

This creates a two-leg trajectory, where the second leg can continue
at an angle specified by bendAngle from the first. Here 0 means
straight on, 1 a (symmetric) 45-degree bent, etc. The first step
will use the iflag, the remaining trajectory the flag argument
for its mode.

this.cbAdvancerGraph(geometry, stepSet, range);

This creates a graph for a rider in the given directions with the
given range, which makes Advancer capture (stopping just before the
piece on its trajectory that it wants to capture). These moves
are implemented as e.p. captures, so the user won't have to click
the intended capture target, just the destination.

Locust and double captures

There now is some automated support for moves that have set the
(new) this.cbConstants.FLAG_FAIRY amongst their flags. Some flag
bits that otherwise would be freely available to the user will
then specify in which way moves that were pushed on the special-
moves stack will be automatically processed and transferred to
the array of pseudo-legal moves. The available flavors are:

this.cbConstants.FLAG_RIFLE;   // capture target without moving
this.cbConstants.FLAG_HITRUN;  // capture is followed by king move
this.cbConstants.FLAG_CHECKER; // capture by jumping over enemy 

The latter should be used only by moves that step to the second
square, and would only be allowed if that square is empty. But
by combining it with FLAG_SPECIAL_CAPTURE it can be made to
also work for a double capture.

All these flags have FLAG_FAIRY set in their bit pattern.
Without that, when using FLAG_SPECIAL, FLAG_SPECIAL_CAPTURE
or FLAG_CAPTURE_SELF the move would be put in the array
'special' of candidate moves if the specified target square
was empty, or occupied by a foe or friend, respectively.
(Combinations thereof are possible.) This feature is already
supported in base-model.js. One would then have to provide
his own post-processing routine to convert these candidate
moves to real moves, and push those to the 'moves' array.

The move that is used to leave the capture square on hit & run
capture can be controlled by assigning a graph to the variable
Model.Game.neighbors (i.e. this.neighbors in the game definition).
By default it would be the King graph.

Entering these moves requires the capture victim to be clicked,
after which the possible final destination(s) will get highlighted,
and have to be clicked to complete the move. This way for entering
moves requires that multi-leg-view.js is included in the view build.

If the user wants to use custom code for processing special
moves in combination with the fairy-move-model.js file, he can
provide a routine this.customGen(moves, move, board, aGame)
to convert the given move from the special moves stack into
a real one, and push that to the moves array (or disgard it).
The final two arguments are the game state (a Board object) and the
Game object, which can be consulted to perform the transformation.

Like always, the candidate will contain a field x (apart from the
normal f, t, c and a fields for squares of origin and destination,
index of the piece at the destination in the pieces array (or null),
and abbreviated piece name, respectively), which contains the XOR
of the destination square and the previously visited square on the
path in the low 16 bits, and the mode flags in the high-order bits.

Flying capture

The base model already supports 'flying capture', i.e. the power
to jump over arbitrary many pieces for capturing, as a special
case of screen capture. Just for a reminder we describe it here.

Flying capture is indicated by FLAG_SCREEN_CAPTURE, just like
normal screen capture. What makes the difference is a non-zero
value in the optional 'ranking' field of the piece definition:

ranking: N,

In that case the move along a ray is not terminated with the
screen capture, but can also fly over it for capturing further
down the ray.

Whether a piece can be used as a screen at all is determined
by the ranking of the latter. This must be lower than that
of the piece making the capture, or equal if they are an even
number. This allows implementation both of the case where
equal pieces would block each other, and where they don't.

Note that normal screen capture (which has N=0) can use all
piece types as a screen, irrespective of the ranking of the
latter.

Anti-trade rules

There also is support for some anti-trade rules. Pieces can be
assigned to an 'anti-trade group' N with the aid of a field

antiTrade: N,

amongst the piece properties. Pieces in the same odd-numbered
group will then not be able to capture each other, if recapture
on the same square would be possible. (I.e., if the captured
piece was protected.) If |N| > 100 (and odd) it is even forbidden
to capture unprotected pieces of the same trade group.

Pieces with an even antiTrade value can always be traded for each
other, but cannot capture a protected piece with the next odd
anti-trade group.

If N < 0 'counter-strike' against the piece is also banned:
in the move directly following the capture of a piece from
such a group, pieces from the same group cannot be captured
by pieces outside the group.

The anti-trading provisions only get switched on by assigning
a non-zero value M to

Model.Game.minimumBridge=M;

The actual value you use for this will be significant when
anti-trading restrictions apply to a piece capable of double-
capture: all pieces of a type >= M captured as 'side catch'
to the trade will cause the ban on trading to be lifted.
(Note that the ban only appied for capturing on the destination
square to begin with.) To lift the ban for any side catch,
you can take M = -1.