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

Enter Your Reply

The Comment You're Replying To
H. G. Muller wrote on Tue, Jul 28, 2020 06:52 AM UTC:

Move legality testing will be based on a move generator. This generates the pseuo-legal moves that are possible in the given position, always being fully aware of any side effects these moves might have. These moves are then compared to the input move, and if there is a match we know the input move was pseuo-legal. Normally we consider a move a match only if all the parameters ori, desti, promo, suicide, freedrop and dropped of the input move are equal to their counterparts orisqr, destsqr, locustsqr, dropsqr and unload of the generated move. But for moves with implied side effects we only match ori, desti and promo (the latter should be 0), and accept what the move generator specifies as side effects. E.g. for castling the locustsqr would be at the Rook to make it disappear, and the dropsqr would indicate where we must drop a Rook to make it reappear.

To make this process efficient, we generate only moves of the piece that according to the input is going to move. For moves that were already tested for legality before (now played for setting up the current position) we even take a short-cut on that: we only generate the moves with implied side effects, to calculate and perform those. The subroutine GenMoves will thus have three parameters: the piece type and start location from which its moves should be generated, and a Boolean that indicates whether we want all moves of the piece, or just those with implied side effects. In the latter case most pieces would of course have no moves at all; in orthodox Chess only the KIng (castling) and Pawns (e.p.) have moves with side efects.

sub GenMoves piece sqr all:            // generates moves for 'piece' on 'sqr' in current position
                                       // 'all' specifies whether we get only moves with side effects
  my index legcount;
  set side islower #piece;             // remember which side we are generating for
  set index fn #piece #all;            // function returns start of piece description in legdefs table
  set hit false;
  do:
    set legcount elem #index #legdefs; // the first element specifies the number of legs
    verify #legcount;                  // a 0 sentinel ends the list of moves
    inc index;                         // 'reads away' the leg count
    gosub NextLeg #legcount #index #sqr #sqr 0 0 0;
    set index + #index * 4 #legcount;  // skip to the next set of legs (= move)
  loop until #hit;
endsub;

The move descriptions come from the table legdefs, and where in this table the description of the given piece type starts is given by a function with the name of the piece type. This function has an additional argument, indicating whether we want all moves or just those with implied side effects. The latter will be found behind the former in the legdefs table, so that we can just start later in the table to get only those. Each move description will start with a number indicating how many legs the move has (where each leg is a leap or a ride). Each leg is then described by 4 numbers: range, sideway and vertical step, and mode. We call the subroutine NextLeg to interpret these. To get to the next move of a piece the table index then has to be incremented by 1 plus 4 times the number of legs. A dummy move with 0 legs indicates we are done with this piece, and ends the loop by terminating the subroutine though verify. A global variable hit can cause the loop to terminate early; there is usually no need to go on generating moves after we found the one we were looking for.

The routine NextLeg does the real work. It calls itself recursively in case there is more than one leg, to do the follow-up legs. Its first parameter controls the depth of this recursion, the next specifies where in legdefs to find the four numbers that describe the leg. Then follow a number of squares: the start square of the move, and the start square of the leg (which for the first leg are of course the same), then the squares for the side effects (starting at the default 0) locustsqr and dropsqr. Finally there is a parameter with which we can request an exact length of a ride when it is non-zero.

We will not go into the details of NextLeg now. When it succeeds in constructing the move according to the description in legdefs, it will eventually call a routine GotMove, passing it the parameters that describe the move and all its side effects. Because we will want to use the move generator for various purposes (e.g. testing whether a given move is pseuo-legal, regeneration of implied side effects, testing whether we can capture a royal piece, making a table of legal moves...), a global variable task will specify what this routine must do. For now we will only have 'task 1', regeneration of the implied side effects.

sub GotMove orisqr destsqr locustsqr dropsqr unload implied:
  switch #task:
    case 1:
      verify == #orisqr #ori and == #destsqr #desti;
      if not #implied: // explicitly specified side effects must also match
        verify == #locustsqr #suicide;
        verify == #dropsqr #freedrop;
        verify == #unload #dropped or not #dropsqr;
     else:            // no side effects must be specified when they are implied
        verify not #suicide and not #freedrop;
        if #locustsqr:
          capture #locustsqr;
        endif;
        set implieddrop #dropsqr;
      endif;
      set hit true;    // we found a matching pseudo-legal move
  endswitch;
endsub;

The move generator always specifies the side effects, and whether these are implied. If they are explicit, they will be automatically applied by Game Courier's execution of the input move. If they were implied, we perform any locust capture, and remember whether we should drop a piece somewhere, so we can do that later.

Why not immediately do all implied side efects? Well, we cannot always make the freedrop of a castling Rook before Game Courier has made the input move, as in some castlings the Rook then would clobber the King. So we must apply the freedrop after feeding the move to Game Courier.

sub HandleMove player:
  set mvs explode chr 59 thismove; // split at semicolons
  gosub ParseMove #player;         // syntax check and interpretation
  set task 1;
  set implieddrop 0;
  gosub GenMoves #mover #ori 0;    // only moves with implied side effects
  set k 0;
  do while < var k count var mvs:  // for all legs
    eval join "MOVE: " trim elem var k var mvs; // apply the move
    inc k;
  loop;
  if #implieddrop:                 // implied freedrop
    add #dropped #implieddrop;
  endif;
endsub;

Note that this code doesn't worry about promotions yet.


Edit Form
Conduct Guidelines
This is a Chess variants website, not a general forum.
Please limit your comments to Chess variants or the operation of this site.
Keep this website a safe space for Chess variant hobbyists of all stripes.
Because we want people to feel comfortable here no matter what their political or religious beliefs might be, we ask you to avoid discussing politics, religion, or other controversial subjects here. No matter how passionately you feel about any of these subjects, just take it someplace else.
Avoid Inflammatory Comments
If you are feeling anger, keep it to yourself until you calm down. Avoid insulting, blaming, or attacking someone you are angry with. Focus criticisms on ideas rather than people, and understand that criticisms of your ideas are not personal attacks and do not justify an inflammatory response.
Quick Markdown Guide

By default, new comments may be entered as Markdown, simple markup syntax designed to be readable and not look like markup. Comments stored as Markdown will be converted to HTML by Parsedown before displaying them. This follows the Github Flavored Markdown Spec with support for Markdown Extra. For a good overview of Markdown in general, check out the Markdown Guide. Here is a quick comparison of some commonly used Markdown with the rendered result:

Top level header: <H1>

Block quote

Second paragraph in block quote

First Paragraph of response. Italics, bold, and bold italics.

Second Paragraph after blank line. Here is some HTML code mixed in with the Markdown, and here is the same <U>HTML code</U> enclosed by backticks.

Secondary Header: <H2>

  • Unordered list item
  • Second unordered list item
  • New unordered list
    • Nested list item

Third Level header <H3>

  1. An ordered list item.
  2. A second ordered list item with the same number.
  3. A third ordered list item.
Here is some preformatted text.
  This line begins with some indentation.
    This begins with even more indentation.
And this line has no indentation.

Alt text for a graphic image

A definition list
A list of terms, each with one or more definitions following it.
An HTML construct using the tags <DL>, <DT> and <DD>.
A term
Its definition after a colon.
A second definition.
A third definition.
Another term following a blank line
The definition of that term.