Check out Glinski's Hexagonal Chess, our featured variant for May, 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 ]

Comments/Ratings for a Single Item

Earlier Reverse Order LaterLatest
How to Enforce Rules in Game Courier. A tutorial on programming a rule-enforcing preset in the GAME Code language.[All Comments] [Add Comment or Rating]
🕸📝Fergus Duniho wrote on Tue, Mar 22, 2022 05:01 PM UTC:

Attention Game Courier Developers

While working on a preset for Miller's Spherical Chess, I was using the problem composer to set up positions for testing whether the pieces had the correct moves. While doing this, I happened to have the white King on h1 while testing its powers of movement, and it had nine moves highlighted as legal. I eventually figured out that it was counting the castling moves as legal even though I had no Rooks on the board.

To fix this, I replaced this code:

setflag a1 a8 h1 h8 e1 e8;

with this code, which conditionally checks whether the right piece is on each space before setting the flag.

if == K space e1:
  setflag e1;
endif;
if == R space a1:
  setflag a1;
endif;
if == R space h1:
  setflag h1;
endif;
if == k space e8:
  setflag e8;
endif;
if == r space a8:
  setflag a8;
endif;
if == r space h8:
  setflag h8;
endif;

The reason the King was getting an extra legal move on h1 is because h1 was flagged for the Rook. When I tried the King on g1, it had only 8 legal moves. By setting each flag conditionally, a problem will not allow castling unless a King and Rook are in the right positions for castling. I have made this change to the Chess preset, and with appropriate modifications, it should be made for any preset that allows castling and uses flags to control when castling is allowed.


Daniel Zacharias wrote on Thu, Jan 19, 2023 02:17 AM UTC:

I'm trying to follow these instructions to enforce the rules for this game, but I've run into trouble with my pawn subroutine. I want the pawns to capture by jumping over one piece to an empty space, but the hopping move isn't accepted as legal.

sub P from to;
    verify > rank #to rank #from;
    if capture:
        die "A Pawn may only capture by jumping over a piece immediately in front of itself.";
    elseif == distance #from #to 2: 
        verify checkahop #from #to -1 1 or checkahop #from #to 0 1 and islower screen;
        capture screen;
    else:
         verify checkaride #from #to -1 1 or checkaride #from #to 0 1;
    endif;
    if onboard where #to 0 #pzs or onboard where #to -1 #pzs:
        if != space #to moved:
            die "You may not promote a Pawn until it reaches the promotion zone.";
        endif;
    elseif == P space #to:
        askpromote #wprom;
    elseif not match space #to var wprom:
        set np space #to;
        die "You may not promote your Pawn to a" #np;
    endif;
    set nopvc 0;
    return true;
endsub;

🕸📝Fergus Duniho wrote on Thu, Jan 19, 2023 02:47 AM UTC in reply to Daniel Zacharias from 02:17 AM:

The line capture screen will not work, because the capture command cannot evaluate an expression. Save the value of screen to a variable, then use the variable with the capture command.

Also, the value of screen is set after calling checkahop, but you are calling screen before checkahop. Remember that expressions are evaluated from end to front, which is the reverse of reverse polish notation, or just polish notation. So, your code should look like this:

verify checkahop #from #to -1 1 or checkahop #from #to 0 1;
verify islower screen;
set scrn screen;
capture #scrn;

Daniel Zacharias wrote on Thu, Jan 19, 2023 05:04 AM UTC in reply to Fergus Duniho from 02:47 AM:

That helped a lot! Now I have this, which does capture, but the check for whether the destination is empty doesn't work, and I haven't found a way to have the post-move code check the value of the piece captured in this way.

sub P from to;
    verify > rank #to rank #from;
    verify (empty #to);
    verify or (checkaride #from #to -1 1 or checkaride #from #to 0 1) (and == distance #from #to 2 or checkahop #from #to -1 1 checkahop #from #to 0 1);
    set hopped screen;
    if (not empty #hopped):
        capture #hopped;
    endif;

H. G. Muller wrote on Thu, Jan 19, 2023 11:50 AM UTC in reply to Daniel Zacharias from 05:04 AM:

If this is 'Post-Move' code, the Pawn has already landed on the to-square, so that it is no longer empty? Try

verify == captured @;

For my understanding: why is it necessary to copy the screen to a variable, before testing it. Is there a problem with writing

capture screen;

?


🕸📝Fergus Duniho wrote on Thu, Jan 19, 2023 04:18 PM UTC in reply to H. G. Muller from 11:50 AM:

If this is 'Post-Move' code, the Pawn has already landed on the to-square, so that it is no longer empty?

Correct.

verify == captured @;

verify not capture; should also work.

For my understanding: why is it necessary to copy the screen to a variable, before testing it. Is there a problem with writing

capture screen;

When I started what became the GAME Code language, I started with commands, which simply took arguments, and I let arguments be separated by spaces. I added expressions to the language later, and I used Polish notation, which also used spaces as separators, because it was easier to implement than infix syntax with parentheses, and its prefix syntax would be quicker to interpret too, which matters for an interpreted language written in another interpreted language. Because of these choices, it's not easy to distinguish between an expression and a list of arguments. So, instead of letting an expression be used anyplace an argument can be used, only some commands can interpret expressions. These include commands for setting variables or for controlling the flow of the program.


Daniel Zacharias wrote on Thu, Jan 19, 2023 07:32 PM UTC:

Is there any reason for the pawn function to include non-capturing moves since the actual movement is handled by the subroutine?


🕸📝Fergus Duniho wrote on Thu, Jan 19, 2023 07:49 PM UTC in reply to Daniel Zacharias from 07:32 PM:

Is there any reason for the pawn function to include non-capturing moves since the actual movement is handled by the subroutine?

The function has to handle potential moves, since it is used to determine whether a potential move is legal. Back when functions were used only with the checked subroutine, the pawn function would only have to concern itself with capturing moves. Now that the stalemated subroutine systematically makes a list of every legal move for the purpose of displaying legal moves when a player clicks on a piece, it is important for each function to cover every possible move a piece can make. When a piece has only a function and no subroutine, the function has to cover both potential and actual moves. But when a subroutine is used for the actual moves, all the function has to cover are the potential moves.


Daniel Zacharias wrote on Tue, Feb 7, 2023 08:20 PM UTC in reply to Fergus Duniho from Thu Jan 19 07:49 PM:

Is there a reason not to have stalemated just use the pawn subroutine? I ask because I'm trying to figure out how to implement pieces with non-displacement capture. Is it possible for a function to relocate a piece after it captures?


🕸📝Fergus Duniho wrote on Tue, Feb 7, 2023 08:47 PM UTC in reply to Daniel Zacharias from 08:20 PM:

Is there a reason not to have stalemated just use the pawn subroutine?

Yes, the pawn subroutine is designed for handling actual moves, not potential moves, it sometimes exits the whole program with the die command and an error message, it resets nopvc to 0, and it asks for extra input for incomplete promotion moves.


🕸📝Fergus Duniho wrote on Tue, Feb 7, 2023 11:38 PM UTC in reply to Daniel Zacharias from 08:20 PM:

I ask because I'm trying to figure out how to implement pieces with non-displacement capture. Is it possible for a function to relocate a piece after it captures?

The pawn functions use remove to handle en passant capture. This is the only built-in function that normally has an effect, since functions and expressions are normally just supposed to return values. To achieve any other effect in a function, you can call a subroutine from it, and the subroutine can cause any effects you like. But if your interest is in non-displacement capture, then remove should be all you need. See the Breaking Logic section of the fairychess include file tutorial for details on how it is used in the pawn functions.


Daniel Zacharias wrote on Wed, Mar 8, 2023 08:10 PM UTC:

I've been working on this game and I'm having a problem I can't figure out how to solve. If white starts by moving a pawn to f8 or g8, the black king shows no legal moves, although if a valid king move is entered it is accepted. I think it has something to do with how I have a few pieces that use multi-stage moves with the second stage being made automatically. It's just not clear why it doesn't work.


🕸📝Fergus Duniho wrote on Wed, Mar 8, 2023 10:40 PM UTC in reply to Daniel Zacharias from 08:10 PM:

You're getting lots of error messages about moves not being well-formed. Let's fix that first, then see if your other problem remains. The error is because these moves do not include the piece label. To make sure that the move is well-formed, you have three options.

  1. Construct the move in your stalemated subroutine as a string, and pass that string to setlegal instead of a pair of coordinates.
  2. Restore the position before using setlegal.
  3. Make sure you don't have moves where both coordinates end up empty. From looking at your use of #after in the stalemated subroutine, it looks like you might have moves of this sort. So, make sure to do one of the other two.

I would also recommend writing your code to the latest standard, which is the fairychess include file.


Daniel Zacharias wrote on Thu, Mar 9, 2023 12:35 AM UTC in reply to Fergus Duniho from Wed Mar 8 10:40 PM:

I didn't see error messages. How would I find those?

I've tried changing stalemated as suggested, but the problem still occurs. It is not clear to me how I would end up with empty moves or how to avoid that.

I was thinking of switching to the fairychess include file but I thought I'd try to get things working with what I'd already started first. I'd need my own stalemated subroutine either way.


🕸📝Fergus Duniho wrote on Thu, Mar 9, 2023 02:26 AM UTC in reply to Daniel Zacharias from 12:35 AM:

I didn't see error messages. How would I find those?

It looks like the code was set up to report them only to me. I just changed it to report them to anyone.


🕸📝Fergus Duniho wrote on Thu, Mar 9, 2023 03:01 AM UTC in reply to Daniel Zacharias from 12:35 AM:

One thing I fixed was where, which you're using in your doubleleap function. I modified it to return false when it calculates a coordinate that doesn't exist, such as an unpaired file or rank marker. However, it didn't fix things for your King.

As I understand how the Catapult and the Skirmisher work from your rules page, they capture by en passant. But in your stalemated subroutine, you're executing the command move #to #after after you have executed move #from #to, and this will move the piece you just moved to #to to #after, changing its position on the board from what it should actually be. If these pieces just capture by en passant, then you should just remove the piece on #after instead of moving the capturing piece there.


Daniel Zacharias wrote on Thu, Mar 9, 2023 03:51 AM UTC in reply to Fergus Duniho from 03:01 AM:

What I was thinking is that since these pieces have only one possible destination for each capturing move, I can have the move entered as a normal displacement capture and then move the piece to the calculated destination represented by #after. That seemed like it would be simpler to implement and would also resolve ambiguity for situations where a move could be either capturing or non-capturing.

To do this, I have subroutines for the relevant pieces that move them again if they made a capture, and also that section in stalemated to do the same when calculating legal moves.

But all this seems to mess up the king's move somehow, so either I'm doing it wrong or I need a different strategy.


🕸📝Fergus Duniho wrote on Thu, Mar 9, 2023 02:46 PM UTC in reply to Daniel Zacharias from 03:51 AM:

There are two main contexts for evaluating the legality of potential moves. One is the normal context of evaluating whether a move from one space to another is legal. In this context, the destination should be the space the piece moves to. The other context is evaluating whether a piece is checking the King. For displacement captures, this simply involves evaluating whether a piece can move to the King's position. So, for non-displacement captures, you will have to simulate a move to the King's position.

The fairychess include file has a mechanism for dealing with these two types of moves. It's not well-documented, but it does come up in the breakdown of the White_Pawn function. If you go to the include file itself and compare the checked subroutine with the stalemated subroutine, you will see that each gives a different value to the variable movetype. The White_Pawn function uses this value to stop the function early when all it has to evaluate is whether it can check the King, since as a divergent piece, some of its powers of movement will not be relevant to this question. Although the Pawn can capture another Pawn by en passant, it cannot capture a King by en passant. So, its ability to capture by non-displacement has no effect on its ability to check a King.

But for a piece that normally captures by non-displacement, you will need to write its move function to account for two types of moves. For moves with the MOVE type, your function should evaluate whether the piece can move to the destination, and it should handle non-displacement captures with the remove built-in function, just as the Pawn functions do for en passant. For moves with the CHECK type, your function should evaluate whether it can capture a piece on the destination. Since this will be used only for telling whether it is checking a King, you may treat this as a move to the King's space without worrying about moving the piece to another space.

If you use the fairychess include file, you should be able to use its checked and stalemated subroutines without writing your own. The main thing you will need to do is write your piece functions to handle two different types of moves.


Daniel Zacharias wrote on Thu, Mar 9, 2023 08:20 PM UTC in reply to Fergus Duniho from 02:46 PM:

Thanks, I'll start working on that then. It looks like I shouldn't need to set the movetype myself. Is that right?

How would you suggest handling a piece with optional withdrawal capture, where a move could be either capturing or non-capturing?


🕸📝Fergus Duniho wrote on Thu, Mar 9, 2023 11:21 PM UTC in reply to Daniel Zacharias from 08:20 PM:

As an example of how you can handle non-displacement captures, I have been working on a new preset for Ultima today. I'm writing *_MOVE and *_CHECK functions as separate functions, and I'm using the main function for a piece to call the appropriate function depending on the value of #movetype.

If you use your functions for actual moves, as I have been doing so far, you should set movetype to MOVE in your Pre-Game code. This will give it a default value when you're not in checked or stalemated.

I have already written code for the Withdrawer, and you might be able to figure out how to make its capture optional.


Thomas wrote on Sun, Mar 12, 2023 11:57 AM UTC:

I wonder if it would suffice to check the legality of the newest move only.

As I understand it, every time a player makes a move a program containing all previous moves is built, with the newest move at the end, then executed. Usually the legality is checked in the post-move part, thus all older moves are checked again and again, after every move made by a player.

Wouldn't it be enough to test the legality of a move only once, directly after it is made, in the post-game part, just assuming that all previous moves are legal?


H. G. Muller wrote on Sun, Mar 12, 2023 01:35 PM UTC in reply to Thomas from 11:57 AM:

I wonder if it would suffice to check the legality of the newest move only.

That is what the code used when you generate rule enforcement through the play-test applet does. But it doesn't do it in the Post-Game section, but conditionally skips the full test in the Post-Move section (in the routine HandleMove). It does this by comparing the variables mln and $maxmln, which are equal for the latest move.

The point is that the code in the Post-Move section will update the game state (by performing the move). So the Post-Game code is only executed after the latest move has already been performed. And it is a bit cumbersome to test the (pseudo-)legality of a move after it has been made. The (pseudo-)legality might depend on aspects of the game state that were not reversibly updated. Like e.p. or castling rights, side-effect captures of an Ultima Withdrawer or Long Leaper. It was much easier to test the legality of the move before it is made.

The processing of the non-latest moves was already quite similar as that of the latest move anyway, due to the requirement to handle moves with implied side effects (such as e.p. captures and castlings). To make that possible it was necessary to generate a list of all such moves (including their side effects), and then pick out the one with the origin and destination that matches the input, to supply the unspecified actions that have to be applied to the position to perform the move. For the latest move all pseudo-legal moves are generated, rather than just those with implied side effects, so that it can easily be tested whether the input move is amongst those.

This only applies to the testing of pseudo-legality. Testing whether the move is truly legal (i.e. did not expose the royal to capture) is something that is more easy to do after the move has been made, and thus is performed in the Post-Game section.


🕸📝Fergus Duniho wrote on Sun, Mar 12, 2023 03:31 PM UTC in reply to Thomas from 11:57 AM:

I wonder if it would suffice to check the legality of the newest move only.

That's going to depend upon how explicit you make your notation. In Chess, for example, I have long treated castling as a King's move, though I have recently written code for handling it as a two-piece move, and I still treat en passant as just a single Pawn move without explicitly adding the capture to the notation. In Shogi, I handle moving captured pieces off the board and changing their sides automatically without including notation for it.


🕸📝Fergus Duniho wrote on Sun, Mar 12, 2023 03:40 PM UTC in reply to H. G. Muller from 01:35 PM:

The (pseudo-)legality might depend on aspects of the game state that were not reversibly updated. Like e.p. or castling rights, side-effect captures of an Ultima Withdrawer or Long Leaper.

That's a good point. Board position is not the only thing affecting the legality of a move. For castling, it has to keep track of whether the King and Rook have moved before, and this is done with flags that change value after a King or Rook moves. If you evaluated each move only once, you would need to use constants to keep track of whether the King or Rook had moved. Since constants normally keep their value, this would have to be done with resetconst. Back before I added constants to the language, though, this wasn't an option.


🕸📝Fergus Duniho wrote on Sun, Mar 12, 2023 03:47 PM UTC in reply to Thomas from 11:57 AM:

Here's another issue. My code for evaluating actual moves, which is normally run in the Post-Move sections, includes error messages for various illegal moves, and beyond just saying that the move was illegal, some of them explain what was illegal about it. But the code I use for evaluating potential moves cannot include error messages, because the task is just to check whether there are any legal moves and to make a list of them all.


25 comments displayed

Earlier Reverse Order LaterLatest

Permalink to the exact comments currently displayed.