Check out Grant Acedrex, our featured variant for April, 2024.


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

Comments/Ratings for a Single Item

Later Reverse Order EarlierEarliest
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 Mon, Mar 13, 2023 07:38 PM UTC in reply to Daniel Zacharias from 05:53 PM:

The difficulty I have with that is making the notation work with it, since if I record the extra move, it isn't considered legal in some situations.

To avoid the need to write code for screening out extended moves, Game Courier uses the maxmove system variable and the ban and allow commands. The maxmove variable indicates how many moves may be made on a single turn. You can use the ban command to ban many things globally then use the allow command to make exceptions for certain types of moves at certain places in the extended move.


Daniel Zacharias wrote on Mon, Mar 13, 2023 05:53 PM UTC:

It occurred to me that the problem I was having with king moves might be because I was setting after in a for loop but not resetting it to false before the next piece was evaluated. Changing that does seem to solve the problem. There might still be better ways to do this with the fairychess system.

I do like the idea of having a non-displacement capture entered with only one click on the target piece because that's the easiest way I can see to disambiguate between a capture and a non-capture in cases where both would result in the moving piece landing on the same destination. The difficulty I have with that is making the notation work with it, since if I record the extra move, it isn't considered legal in some situations.


H. G. Muller wrote on Mon, Mar 13, 2023 01:04 PM UTC in reply to Fergus Duniho from 12:29 PM:

In the Interactive Diagram script I included my own random implementation to guarantee consistency. In the GAME code include file for shuffling that it uses I do use a constant ('startshuffle') to store and retrieve the array '$space' at the start of the game, and only shuffle when this constant is not defined.


🕸📝Fergus Duniho wrote on Mon, Mar 13, 2023 12:29 PM UTC in reply to H. G. Muller from 09:31 AM:

(But in shuffle games you would also have to remember the start position, or at least the random seed used for generating it.)

It normally stores the seed, but when several games of Fischer Random Chess broke because PHP's algorithm for selecting random numbers had changed, I added constants to the language. Since Game Courier is designed for correspondence games, it runs a game from the beginning for each new move. Unlike variables, whose values are determined only by the running of the program and the input fed to it, constant values were stored in logs or $_POST data so that they would be available without re-running the code that originally generated them. The main thing distinguishing a constant is that it's value survives from one run of the program to the next. With that in mind, its value may be changed if necessary, but this is done with a special command, since going along with the way constants work in other languages, a constant is supposed to keep the same value.


H. G. Muller wrote on Mon, Mar 13, 2023 09:31 AM UTC in reply to Fergus Duniho from Sun Mar 12 08:22 PM:

Storing the game state as the sequence of moves from the initial position is a good method, and for most of the game more compact than remembering the current board position. Especially for large games. And a large part of the move history is actually part of the game state, if there is an N-fold repetition rule. Ordinary move notation is not reversible, so taking back moves directly would require storing extra information (such as what was captured), and replaying the game from the start solves that problem. (But in shuffle games you would also have to remember the start position, or at least the random seed used for generating it.)

The question was not whether it was needed/desirable to replay the moves, though, but whether it was necessary to test the (pseudo-)legality during this replay. And there the answer is "no, except for the latest move". Since Game Courier is such that you can only add one move at the time, all earlier moves must have been the latest move at the time they were added, and when they were legal then, they will be legal in the replay as well. And otherwise they would have been refused, and never added to the game.

So for all but the last move there is no need to test pseudo-legality, and moves that are 'self-explanatory' can just be performed as specified. The only caveat is the handling of moves that have implied side effects. These should be recognized at all time, and when they appear the implied side effect should be performed in addition to what the move specifies explicitly. Common cases of implied side effects are disappearence of the enemy Pawn on e.p. capture, and moving of the Rook in castling. Depending on the prescribed move notation there could be other cases, such as the captures in Ultima. In principle all Ultima moves can be described by the origin and destination of the moving piece.

In the GAME code generated by the Play-Test Applet I treated this by having two sets of moves for each piece: one consiting of all the moves, and one only of the moves with implied side effects. For most pieces the latter set would be empty. Only for the latest move the full move set is used, to check if the newly entered move is amongst those. For all other moves it is only tested whtherthe move matches one with implied side effects, and if it does the generated move (which is aware of the side effect) is performed rather than the move from the move list (which does not specify any side effect). Moves that do not match any of the moves with implied side effects are taken at face value.


🕸📝Fergus Duniho wrote on Sun, Mar 12, 2023 08:22 PM UTC:

As things work right now, it is possible to take back moves, because when you do, it will replay all the canonical moves and skip over the moves that were taken back, recalculating game data as each move is made. But suppose you're evaluating each move only once, using constants to keep track of game information like whether certain pieces have already moved, and someone takes back a move that changed some of the information stored in the constants. You would either have to restore the game data to what it used to be, which could become rather tricky, or give up the ability to take back moves that do change game data.


Thomas wrote on Sun, Mar 12, 2023 06:26 PM UTC:

Thank you. I have to think about it and experiment a bit.


🕸📝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.


🕸📝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: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.


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.


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?


🕸📝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.


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 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 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 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.


🕸📝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.


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 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 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 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.


🕸📝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.


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 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.


25 comments displayed

Later Reverse Order EarlierEarliest

Permalink to the exact comments currently displayed.