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
Play-test applet for chess variants. Applet you can play your own variant against.[All Comments] [Add Comment or Rating]
🕸Fergus Duniho wrote on Wed, Jun 17, 2020 10:24 PM UTC:

It said "I resign" when I stalemated it, and again when I checkmated it. Can you make it indicate whether a game has ended in stalemate or checkmate?


💡📝H. G. Muller wrote on Wed, Jun 17, 2020 10:54 PM UTC:

Problem is that just saying it is not enough; it must know whether stalemate is a draw or a loss, so that it knows whether it should go for it or avoid it, depending on whether it is winning or losing. So the stalemate result must become a parameter for the diagram, and the applet must somehow provide a way for the user to control that parameter.

I will work on it. It was first posted hardly more than 24 hours ago, and I had more problems than I expected to get promotions working properly. (We don't want to allow the AI to promote to any piece in the table, so it had to keep track of which pieces participate, and which don't.) And so far I was concentrating on the interface, how to make this reasonably user-friendly.

Feedback is much appreciated, btw. E.g. besides stalemate, should we also be able to specify other game terminations? Such as baring, or whether multiple royals would mean extinction royalty or not. Also, there are still many pieces in the list that do not have a move. Which seems a pity; as they are there anyway for their pretty looks, they might as well be used to provide the user more choice of moves without having to mess with the move definitions himself. Can you suggest any moves for pieces like Ox, Ram, Crocodile...?

I fixed the stalemate; I added a parameter stalemate=draw to the diagram, and actually made that the default. It now also prints the message. I also changed the King position evaluation in the end-game, to draw to the center (extra strong for a bare King) and to draw to the action; as a result it can even force checkmate with a Queen now, at 2 ply.

This facility isn't really meant for playing end-games; at a depth of two ply and without any dedicated strategic knowledge that will really suck. To see if pieces can checkmate a bare King we have the checkmating applet, which is based on End-Game Tables rather than search. This is intended for seeing how the design works out in the middle-game.


💡📝H. G. Muller wrote on Mon, Jun 29, 2020 09:04 PM UTC:

I now put a somewhat more refined search in the AI of the Interactive Diagram, in the hope that this would make it more human-like w.r.t. the things it will overlook. It now focuses its attention more on moves that are logical continuations of what happened before. In particular moves that 'touch' squares that were mutated one or two ply earlier. That would include recaptures, plunder raids, discovered threats, pin punishment. But also hopper activation; it doesn't matter whether the mutation was evacuation or placement; if a move goes over or to it, it gives it more attention than other moves.

As this search is much less fixed-depth than the previous one, the meaning of the ply setting has become a bit vague. If we count PV moves as one ply, most non-captures elsewhere in the tree would count double. I made the '2 ply' setting such that it will still search every reply to the move it intends to play (validated by an exchange evaluation), which means that the PV will actually be 3 ply long. Recaptures are now only not counted in the depth when a lower-valued piece captures a higher or an unprotected one; recapturing a lower protected piece doesn't get more attention than any other capture (or PV move).

It is still true that at 2 ply it wouldn't see a (new) mate-in-1 threat against it, and at 3 ply it will. It would see it when it can checkmate you in one at 2 ply.

As this is a bit more bug-prone than the very simple original search, please let me know if it shows erratic behavior. I am aware that its play with Pawns currently sucks. I could easily put in some evaluation that would solve this for FIDE/Shatranj Pawns, but that would break the generic nature of the AI. It does seem to be the kind of Pawn for which this is most important, though; there don't seem to be many subtleties with Asian or Berolina Pawns. (And of course the overwhelming majority of CVs have FIDE Pawns.)

I am open for suggestions for what additional features (other than pieces with nearly arbitrary moves) could be supported by the AI to make it more useful.


💡📝H. G. Muller wrote on Thu, Jul 16, 2020 11:35 AM UTC:

Just to probe the amount of negativism this idea still provokes: wouldn't it be cool if, next to a button 'Show HTML', which displays the code for an Interactive Diagram of the set-up variant that can be copy-pasted into any HTML page, there also was a button 'Show GAME code', which would display code that could be copy-pasted to make a Game Courier rule-enforcing preset?


A. M. DeWitt wrote on Thu, Jul 16, 2020 11:35 AM UTC in reply to H. G. Muller from 11:35 AM:

Great idea, but how would you even go about implementing that? For a game like Yangsi or regular Chess, it would be fairly simple, but for a game like Chu Shogi or Suzumu Shogi, or even regular Shogi, things become really complicated really quick. Chu Shogi and Suzumu Shogi have multi-moving pieces, which required specialized code to enforce properly, namely a modified version of the code in Extra Move Chess that can enforce single and double moves, as well as a special subroutine that determines if a piece moved to a square that allows it to move again. In Chu Shogi, even more specialized code is needed to enforce the Lion-trading rules. Same for regular Shogi, except the specialized code handles drops rather than multi-moving pieces. Thanks to this and the fact that XBetza notation and GAME Code are two wildly different things, it would be incredibly difficult to properly implement the full version of your idea. Still, adding a button that, at the very least, prints out GAME Code functions for each piece, would be a great addition to this page in my opinion.


💡📝H. G. Muller wrote on Thu, Jul 16, 2020 02:53 PM UTC:

OK, let me stress that I hardly know anything about GAME code. But I read somewhere that it is a Turing-complete programming language. I don't doubt that Betza notation is very far from GAME code, but it is also very far from JavaScript. And it wasn't all that hard to write a move generator driven by Betza notation in JavaScript. The Diagram script first compiles the Betza string into lists of 'move legs', where each leg can be either a leap or a slide in an absolutely specified direction, and specifies what must be at the square it ends on (friend / foe / empty). These lists are then interpreted at 'run time', i.e. when the Diagram needs to highlight squares, or the AI needs to generate a list of pseudo-legal moves for a given position. So my first thought would be to translate that move list to GAME code, plus a universal GAME-code routine that interprets the list in the context of a given position, just as the JavaScript routine does for the Diagram.

For the purpose of making a server the only tasks would be to determine whether an input move is pseudo-legal in a given position, and whether the royal is capturable in a given position. Both could be done by having it return TRUE as soon as it stumbles on a move that fits the description (i.e. matches a given destination, and in the case of an input move, also a given origin (and perhaps promotion choice or additional info, such as locust squares), which is (partly) guaranteed by only generating the moves for the piece at the origin, if an origin is given.


🕸Fergus Duniho wrote on Thu, Jul 16, 2020 02:53 PM UTC in reply to H. G. Muller from 02:53 PM:

> OK, let me stress that I hardly know anything about GAME code. But I read somewhere that it is a Turing-complete programming language.

It is Turing-complete, but it is also relies on specialized functions, and code written in GAME Code follows certain conventions. One of these is that the movement of a piece is usually defined by two functions, and sometimes by an optional subroutine for actual moves. One function defines the range of the piece, and the other checks whether a particular move is legal. Using both functions is an optimization that saves the code from checking for legal moves to every space on the board. Since actual moves sometimes include complications that may be ignored when checking whether a potential move is legal, and also because they are evaluated after pieces have moved instead of before, subroutines are sometimes used to handle actual moves. The distinction that GAME Code makes between functions and subroutines is not part of most languages, including JavaScript. It was borrowed from BASIC.


💡📝H. G. Muller wrote on Fri, Jul 17, 2020 11:36 AM UTC:

What would be the best place to read up on GAME code? There seems to be a lot of material about it here, but it seems that GAME code evolved a lot, and not everything is up to date.

One thing that is not clear to me after glancing through one of the tutorials is how these code snippets are embedded in the larger design of the server. I would have expected checking a given move for pseudo-legality to be a different task from performing a move for updating the position, but I did not recognize that in the examples. E.g. the routine for Pawn moves seems to automatically clear the e.p. square. Which seems a problem if the move later turns out to be illegal (e.g. because the victim on the e.p. square was sheltering your King). Is there an automatic takeback when you say 'die' at any stage?

I am not worrying so much about elementary leapers, sliders and their compounds. (Although a very large fraction of CVs don't use anything more than that.) The real challenges are more complex moves, such as bent sliders, hook movers, locust captureres. Espcially if they are not uniquely specified by just two squares.


🕸Fergus Duniho wrote on Fri, Jul 17, 2020 11:36 AM UTC in reply to H. G. Muller from 11:36 AM:

What would be the best place to read up on GAME code? There seems to be a lot of material about it here, but it seems that GAME code evolved a lot, and not everything is up to date.

The most recent thing is the tutorial on the Fairychess Include file. The Developer's Guide is also important.

One thing that is not clear to me after glancing through one of the tutorials is how these code snippets are embedded in the larger design of the server. I would have expected checking a given move for pseudo-legality to be a different task from performing a move for updating the position, but I did not recognize that in the examples.

It is different. See the distinction between potential and actual moves.

E.g. the routine for Pawn moves seems to automatically clear the e.p. square. Which seems a problem if the move later turns out to be illegal (e.g. because the victim on the e.p. square was sheltering your King). Is there an automatic takeback when you say 'die' at any stage?

The die command exits the program with a message, behaving just the same as the PHP function. When this happens, the player should use the back arrow and reload the script to make a different move. Instead of continuously running a script during the entire course of a game, Game Courier runs the same script numerous times. When a player is ready to move, he runs the script to see the current position. When he makes his move, the scipt runs again to show the preview. When he confirms his move, the script runs for a third time. If he makes an illegal move, this is caught during the preview, at which time the log has not yet been updated with a new move. All he has to do is go back, run the script again to see the current position, and make a different move.


💡📝H. G. Muller wrote on Sat, Jul 18, 2020 04:54 AM UTC:

I did read the tutorial How to Enforce Rules in Game Courier (2016), but some things where not entirely clear to me:

  • When it discusses the code for promotion in the Post-Move code, it mentions how to reject a move R a1-f1; Q-a1;. I don't understand the Q-a1. Must pieces be promoted on their starting square? Why not on f1? Are the moves also evaluated right to left?
  • Apparently the input format is such that promotion is written as a separate, extra move. How is such a sequence of moves handled by the basic input system before the Post-Move code is invoked? Their seems to be no provision for multiple moves, just origin, dest, moved and old. Yet you can test the board (spaces) to check whether promotion took place. Are all moves of the sequence performed, and do the variables only convey the parameters of the last move that was processed? Do promotion 'moves' alter any of these variables?
  • What happens when you promote an empty square? Is that equivalent to dropping a piece on that square? (That would be useful e.g. for pieces that swap location with other pieces.)
  • Can you 'promote' something to an empty square?
  • In several places it is mentioned that the Post-Game code is executed only after all moves have been performed. What does this 'all moves' refer to? Normally (ie. for non-promotion) there would only be a single move to perform, right? Namely the one the user entered.
  • What is the convention for entering non-implied locust captures, like for the Chu-Shogi Lion? Is it capture followed by a move to the destination, or a direct move to the destination followed by promoting the locust victim(s) to empty squares?
  • Should automatic locust captures, such as for the Ultima Long Leaper, be explicitly specified, or should they be automatic side effects of the move to the destination?

🕸Fergus Duniho wrote on Sat, Jul 18, 2020 04:54 AM UTC in reply to H. G. Muller from 04:54 AM:

When it discusses the code for promotion in the Post-Move code, it mentions how to reject a move R a1-f1; Q-a1;. I don't understand the Q-a1. Must pieces be promoted on their starting square? Why not on f1? Are the moves also evaluated right to left?

That was a typo. I have changed it to f1.

Apparently the input format is such that promotion is written as a separate, extra move. How is such a sequence of moves handled by the basic input system before the Post-Move code is invoked? Their seems to be no provision for multiple moves, just origin, dest, moved and old. Yet you can test the board (spaces) to check whether promotion took place. Are all moves of the sequence performed, and do the variables only convey the parameters of the last move that was processed? Do promotion 'moves' alter any of these variables?

While a regular move would change all these variables, a promotion would not. This allows promotions to be handled as second moves without coding the game as a multi-move game.

What happens when you promote an empty square? Is that equivalent to dropping a piece on that square? (That would be useful e.g. for pieces that swap location with other pieces.)

Drop has a technical use in Game Courier, which means moving a piece from an off-board area to the board, as in Shogi. Regular drops are not used for promotion. Adding a piece to a space is used for promotion, and I do think I describe this with the term free drop. In adding a piece, or performing a free drop, the piece comes from nowhere and replaces whatever was on the space. Promotion is handled by adding a piece to an occupied space. It is also possible to add a piece to an empty space, as is done in the new variant Fertile Queen Chess.

Can you 'promote' something to an empty square?

No, you can add a new piece to an empty square, but that would not be called promotion.

In several places it is mentioned that the Post-Game code is executed only after all moves have been performed. What does this 'all moves' refer to? Normally (ie. for non-promotion) there would only be a single move to perform, right? Namely the one the user entered.

It means all the moves a player enters on one turn. Game Courier began as a dumb board simulator without any programming language for enforcing rules, and it can still be used without rule enforcement. So, it works by playing all moves a player enters in sequence before updating the position. It does not normally work by evaluating each move before performing it.

What is the convention for entering non-implied locust captures, like for the Chu-Shogi Lion? Is it capture followed by a move to the destination, or a direct move to the destination followed by promoting the locust victim(s) to empty squares?

I have never programmed Chu Shogi, and I'm not sure what a locust move is. Ask Adam DeWitt what he did. If it's the same as a grasshopper move, there is a function for that, but I suspect it's not.

Should automatic locust captures, such as for the Ultima Long Leaper, be explicitly specified, or should they be automatic side effects of the move to the destination?

Since you mentioned the Long Leaper specifically, there is a built-in function called checklongleap. However, I didn't program Ultima. Antoine Fourrière did. So, I'm not sure if there were extra details for programming the piece. I am just answering questions quickly right now. I'll have more time to dig into things later.


💡📝H. G. Muller wrote on Sat, Jul 18, 2020 04:54 AM UTC in reply to Fergus Duniho from 04:54 AM:

No, you can add a new piece to an empty square, but that would not be called promotion.

I meant: would it be possible to clear a piece from an occupied square by 'free-dropping' an empty square on top of it (e.g. by entering @-f1). And come to think of it: the code that checked the promotion just looks whether the piece at 'dest' after the move is still 'moved'. But what if someone would have really entered the typo R a1-f1; Q-a1; ? Presumably that would leave a Rook at f1, so you would not catch that. Would it have free-dropped a Queen at a1 after the Rook moved ('fertile Rook')? Or is there some intrinsic test on the input that enforces that promotion moves can only free-drop on dest? (Probably not, because that would make the mention of any square redundant.) Because the promotion move doesn't set any variable similar to dest, it isn't clear to me how you could test whether free-drops go to an allowed square.

BTW, some variants allow only promotion of a piece that was lost before, and in those it can make sense to collect the captured pieces in a separate area (without color flip), and move them from there to effect promotion.

I have never programmed Chu Shogi, and I'm not sure what a locust move is.

'Locust capture' in general is capturing a piece on a square you are not moving to. Like capture in Checkers, or e.p. capture in orthodox Chess. But in these two cases the capture is an implicit side effect of the move. So the Pawn subroutine can recognize e.p. capture, and automatically remove the victim, without the user having to enter any additional moves. (I guess promotion in Shatranj or Makruk could also be handled that way.) The problem arises when the capture would be optional. E.g. in Odin's Rune Chess a Forest Ox moves and captures like a Knight, but can in addition remove one other enemy piece adjacent to its destination. So there you would somehow have to indicate whether you want to do that, and if so, which of the (possibly eight) adjacent pieces. F c3-e4; @-d5; could be a suitable notation for that, if such a thing were allowed.


Greg Strong wrote on Sat, Jul 18, 2020 04:54 AM UTC in reply to H. G. Muller from 04:54 AM:

BTW, some variants allow only promotion of a piece that was lost before, and in those it can make sense to collect the captured pieces in a separate area (without color flip), and move them from there to effect promotion.

Game Courier does this automatically.  There is an associative array called capturedpieces that keeps track of the pieces captured and the associated count.  It uses the starting array to know the total number of each piece.  When playing a game, there is a display that shows all the captured pieces for both players, but that box only appears when something has been captured.


🕸Fergus Duniho wrote on Sat, Jul 18, 2020 04:54 AM UTC in reply to H. G. Muller from 04:54 AM:

I meant: would it be possible to clear a piece from an occupied square by 'free-dropping' an empty square on top of it (e.g. by entering @-f1).

Yes, that is possible. But there are other ways of removing a piece from a space without moving to it. You can use the empty command, the remove function in an expression, or the notation of moving what's on that space nowhere, such as f1-. In contrast, -f3 would remove the space. See the user guide for details on different types of notation.

And come to think of it: the code that checked the promotion just looks whether the piece at 'dest' after the move is still 'moved'. But what if someone would have really entered the typo R a1-f1; Q-a1;

The ban command allows the programmer to ban certain kinds of moves, so that the main code doesn't have to handle them. If a blanket ban command is used, the allow command can be used to explicitly allow certain kinds of moves. Since the Rook would be on f1, adding a Queen to a1 would be a free drop, and these may be banned without banning promotions. A free drop is a drop from nowhere to an empty space, whereas a promotion is to an occupied space. This is commonly done in most Chess variants with code like this:

ban commands allmoves;
allow moves 1 captures 1 promotions 2;

BTW, some variants allow only promotion of a piece that was lost before, and in those it can make sense to collect the captured pieces in a separate area (without color flip), and move them from there to effect promotion.

See how Grand Chess and Gross Chess handle this. As Greg mentioned, Game Courier keeps track of captured pieces. Although this is normally done automatically, it can also be done in a manner controlled by the code. Data on the captured pieces can be used to control which pieces a Pawn may promote to.

'Locust capture' in general is capturing a piece on a square you are not moving to.

This is handled in the Pawn functions and subroutines because of en passant. Although functions are ideally meant to return a value without changing the position, I had to add a remove function so that the Pawn functions would handle en passant properly.

The problem arises when the capture would be optional.

Each move option has to be distinguished in the notation. If a piece may optionally capture a piece on another space than the one it moves to, it's move might have to be broken into two moves. This could be handled as moving to the space the piece is on, then moving to another space. Or it could be handled by moving directly to its destination and capturing the piece as a second move. Without rule enforcement, the choice of notation wouldn't matter. But with rule enforcement, you should pick one and think about how to program it. The latter has the advantage of not introducing a second regular move. If you did it the first way, you would have to allow regular moves on the second move, and then your main code would have to prevent it whenever it is illegal. Using the latter way, you could allow suicides on the second move, and that might be easier to handle.

In general, much of the code is able to be kept as simple as possible by banning all the types of movement that are never used in a game. For example, players could delete spaces, do rifle captures, or use GAME Code to enter complex moves. But when the programmer bans certain types of input, that reduces what the code has to deal with. So, code for checking the legality of moves comes in the context of assuming that certain types of input are banned. If you want to convert Betza notation to GAME Code functions and subroutines, you might have to assume a context where any type of move is allowed, and that would make programming more complicated.


💡📝H. G. Muller wrote on Sun, Jul 19, 2020 08:21 AM UTC:

OK, so I could allow moves and captures for the first move, and promotions, suicides and freedrops for the second (and perhaps third) move, depending on whether the game needs those. (Freedrops would only be needed when there participates a piece that uses an 'unload' modifier in its Betza notation, and suicides only when there are multi-leg moves that can capture on a non-final leg.)

The question is how the presence of suicides or freedrops in the input move is relayed to the post-move code so that it can check for their legality. For promotions it could just check 'space dest', because the basic input system already enforced that these could only alter the piece that just moved. But the freedrops and suicides could strike anywhere. Is there a variable similar to 'dest' that tells which location they altered, or must I make a copy of the board before the move to compare to afterwards, to see if anything was changed, and what?

Is the post-move code run after each move in the sequence, and then the post-game code at the end? But then I don't understand how the code in the tutorial can work, because promotion happens only in the second move, so that the first move should be flagged as illegal when you run the post-move code after it, because it still has the Pawn on last rank.


🕸Fergus Duniho wrote on Sun, Jul 19, 2020 04:52 PM UTC in reply to H. G. Muller from 08:21 AM:

The question is how the presence of suicides or freedrops in the input move is relayed to the post-move code so that it can check for their legality.

A freedrop will change the values of $origin, $dest, and $old. It will set $origin to false. A suicide is treated as a move to the null space. This is a space with an empty string for a coordinate. The important point is that it changes all the same values as a regular move does. So, doing a freedrop or a suicide on the second move is going to erase information about the first move. Promotions are special, because they do not erase information about the first move.

Is there a variable similar to 'dest' that tells which location they altered, or must I make a copy of the board before the move to compare to afterwards, to see if anything was changed, and what?

There is not. I suppose you could copy the board position, then check the hamming distance with the current position to see how many positions have changed.

Is the post-move code run after each move in the sequence, and then the post-game code at the end?

No, the Post-Move code is run after the completion of all the moves.

But then I don't understand how the code in the tutorial can work, because promotion happens only in the second move, so that the first move should be flagged as illegal when you run the post-move code after it, because it still has the Pawn on last rank.

As I just mentioned, it doesn't work that way. It plays all moves and fills in the variables with data on the last move. However, a promotion does not count as a full move. So, it does not change the data already filled in for the previous move.

The variables that get filled in after a move are most useful when you are not making a series of different moves. For your purposes, it would be better to check each move individually. To do this, store the position in the Pre-Move code, restore it in the Post-Move code, and then make an array of the moves by using explode on $thismove, and go through them one-by-one. This is what multi-move variants do.

But if you do it this way, you may have to code some things differently, such as promotion. You will also have the choice of evaluating a move before playing it or after playing it. Pick one and stick to it consistently.


🕸Fergus Duniho wrote on Sun, Jul 19, 2020 05:06 PM UTC in reply to H. G. Muller from 08:21 AM:

The question is how the presence of suicides or freedrops in the input move is relayed to the post-move code so that it can check for their legality.

I just remembered that the variables $prevmoved, $prevorigin, and $prevdest will return the previous values of $moved, $origin, and $dest. I have also just added $prevcaptured for the previous value of $old. As long as you have no more than two moves per turn, these may give you the information you need.


💡📝H. G. Muller wrote on Sun, Jul 19, 2020 05:50 PM UTC:

OK, that is interesting, because at the moment the Diagram also has a limitation that it cannot handle more than a single locust victim or unloaded pieces. That is a limitation I was hoping to remove in the future, though. (The Lion Dog of the large Shogi variants can make up to two locust captures, in addition to a normal one.)

Just an idea: wouldn't it be possible to have a move generator generating the move strings for all pseudo-legal moves in the Pre-Move code, and have it do a string compare for each of those with thismove, to see if one matches? If there is one, it can just allow the entire move sequence to be performed without ever having to look at the origin or dest of any of the individual moves. The Post-Move code then would only have to test whether this left the King in check. For this it would basically run the same move generator for the opponent, except that it did not generate strings to compare, but tests whether any of the moves captures the King.


🕸Fergus Duniho wrote on Sun, Jul 19, 2020 08:13 PM UTC in reply to H. G. Muller from 05:50 PM:

wouldn't it be possible to have a move generator generating the move strings for all pseudo-legal moves in the Pre-Move code, and have it do a string compare for each of those with thismove , to see if one matches?

Presets have been programmed to generate a set of legal moves, and these get passed to JavaScript for the purpose of displaying legal moves. But these are stored as pairs of coordinates, not as longer strings with multiple moves. These sometimes miss crucial information about a move, such as a Pawn being able to capture by en passant, and they don't contain the complete move, such as what a Pawn promotes to on reaching the last rank.

Besides that, this gets done in the Post-Game sections, where it gets done only after checking whether all past moves are legal. What you're suggesting is to do it for every single move every single time it gets reprocessed, and to also do it in a more thorough manner than it normally gets done. This would be very costly, and it would get costlier with each move, possibly bogging down the script.


💡📝H. G. Muller wrote on Sun, Jul 19, 2020 09:16 PM UTC in reply to Fergus Duniho from 08:13 PM:

Pairs of coordinates are usually sufficient to describe a move. It would be very useful if there could be an arbitrary number of coordinates, though. It could then also describe moves that need more than two mouse clicks to be entered. The JavaScript could run through the list after every click, to get the sub-set of moves that start with the clicks that have already been made. (With only simple moves, after clicking a piece, this would leave you with the moves of that piece.) It could then highlight the 'next in line' click of each of those, so that the user knows which squares he can click next. If all clicks in a move would have been made, and no other moves start with the same sequence of clicks, the move can be considered entered. If there are still multiple options we can adopt the convention that one has to click the last-clicked square again to terminate the move without waiting for more clicks. E.g. for optional locust captures the second click could be on the locust victim, and the third click could be on the final destination.

Is the issue that to retrieve a position, each time all moves of the entire game have to be replayed? Even if this is the case, it would surprise me if it would take any measurable time at all. Chess engines typically search on the order of a million positions per second, generating all moves in each of these positions. Even if a scripting language would be 100 times slower, and a game on average has 100 moves, it would still only take 10 ms of CPU time to retrieve the game.

But for moves that are already part of the game, there isn't any reason to check their legality at all. This should have been done while they were first entered, and added to the game. Only newly submitted moves would have to be vetted. Older moves can simply be executed as stored. The only problem would be automatic side effects. But typically only very few moves have those. But locust captures or unloads generated from the Betza descriptions would never be automatic; they would always require full specification of the side effect in the input move. So the automatic side effects would remain limited to e.p. captures and castlings, which can be handled in the conventional way.


🕸Fergus Duniho wrote on Mon, Jul 20, 2020 01:27 AM UTC in reply to H. G. Muller from Sun Jul 19 09:16 PM:

Since GAME Code is Turing-complete, you can try to use it in ways I never have. However, I would suggest taking smaller steps toward what you want. Before you write code to write GAME Code, it would help if you first had some experience programming in GAME Code. Try programming some games with it to get that experience. As a second step, you could try programming a limited version that doesn't work with XBetza code that would require suicides or free drops. Once that is done, you would be in a better position to start your more ambitious project.

Is the issue that to retrieve a position, each time all moves of the entire game have to be replayed? Even if this is the case, it would surprise me if it would take any measurable time at all.

Yes, it has to replay all past moves to calculate the current position.

But for moves that are already part of the game, there isn't any reason to check their legality at all. This should have been done while they were first entered, and added to the game. Only newly submitted moves would have to be vetted. Older moves can simply be executed as stored. The only problem would be automatic side effects.

Normally, the cost of checking legality is very low. Checking for stalemate and checkmate is more costly, and that is reserved for the Post-Game section. The assumption is then made that the game didn't end in checkmate or stalemate on earlier moves. Checking for legality after each move has the advantage of handling side effects of moves with the same subroutines used to check legality.

You could conceivably check legality in the Post-Game section. This would check legality only for the latest moves. But the side effects wouldn't be lasting unless you rewrote the latest move to explicitly include all the side effects, or you wrote Post-Move code that handles side effects without checking legality.

I would suggest instead that you make use of the variables starting with $prev and not try to calculate all legal moves just to check the legality of the latest move.


💡📝H. G. Muller wrote on Mon, Jul 20, 2020 09:12 AM UTC in reply to Fergus Duniho from 01:27 AM:

Well, I will definitely start with something simple. But I don't want to paint myself into a corner from the start, so some advance planning of the strategy that will eventually be adopted seems useful.

The problem with using $prev is that it doesn't seem to offer any hope of expanding the capabilities to more than 1 move + 1 explicit side effect, something I would still like to do in the future. It would be possible to specify the side effects before the move, but that mostly subverts the effectivity of the allow command, as to allow both simple moves and combinations suicide + move one would have to allow moves + captures both as first and second move, and then it would not weed out cases where the user typed two normal moves. I could use the explode trick on every move on the off-chance that the user might have entered a move with a side effect, but the store and restore this requires to not mess up the game state must also be an order of magnitude more expensive than just testing pseudo-legality of a given move.

When I would specify allow moves 1 captures 1 promotions 2 freedrops 2 suicides 2 suicides 3 , I could test whether the input line did specify side effects by something like if != dest null and origin: . For simple moves moved and origin are reliable, and I could run the move generator only for the moved piece. Whether the move is compared in coordinate form or as text string really should not matter much. For composit moves I would either have to recover the moving piece through the explode trick, (because I don't know how many suicides followed it, so I cannot rely on prevorigin either), or generate moves for all pieces to see which one matches the thismove string.

It would have been very helpful, efficiency wise, if it could be tested whether the Pre/Post-Move code is run for a new input move, or just for a move that was already accepted as part of a game, and is now played to set up the current position. Is there a variable that holds the current game length? I suppose it would be possible to update a global counter in the Pre-Move section (initialized to 0 in the Pre-Game section) to keep track of the move number. If the move is not the last move in the game, the Pre/Post-Move code could be made to suppress any unnecessary (pseudo-)legality testing. In particular, composit moves would not have to be tested, as they would be guaranteed to not have any implied side effects (the very reason for them being composite being that they explicitly specify all their side effects).

[Edit] is this a matter of comparing movenum with mln ?


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 02:46 AM UTC in reply to H. G. Muller from Mon Jul 20 09:12 AM:

The problem with using $prev is that it doesn't seem to offer any hope of expanding the capabilities to more than 1 move + 1 explicit side effect, something I would still like to do in the future.

I'm thinking of providing more information, but it requires an array, and I'm still looking into how I might handle that.

the store and restore this requires to not mess up the game state must also be an order of magnitude more expensive than just testing pseudo-legality of a given move.

It's not that expensive. It is just copying variables. But it is not needed. There is a checkbox in the Edit menu called "Do Not Include Moves in Code". Check this if you want to handle moves on your own without having them performed automatically. I just did this for Extra Move Chess, and I got rid of the store and restore lines.

Is there a variable that holds the current game length? ... is this a matter of comparing movenum with mln ?

It is a matter of comparing mln with $maxmln. When they are equal, it is the latest move.


Greg Strong wrote on Tue, Jul 21, 2020 03:14 AM UTC in reply to Fergus Duniho from 02:46 AM:

What does Do Not Include Moves in Code do?


💡📝H. G. Muller wrote on Tue, Jul 21, 2020 10:19 AM UTC in reply to Fergus Duniho from 02:46 AM:

I'm thinking of providing more information, but it requires an array, and I'm still looking into how I might handle that.

It would already be very helpful if the 'origin' and 'moved' info was always available for the first move of the sequence. Without that, the following code seems to do what is required. (I did not want to use the Do Not Include checkbox, as the store / restore is only needed on the latest move of the game, while on all other moves it would come in handy if it is automatically performed.)

The underlying assumption is that implied e.p. captures and moves that generate e.p. rights ('double pushes') will never have other (explicitly specified) side effects, and will thus be entered as simple moves. (For castlings XBetza already guarantees that, but it is in theory possible to specify rights-generating moves that would also make a locust capture. It is hard to imagine any Chess variant would ever have that, though.)

Pre-Move:

if != mln $maxmln:
  store;
endif;

Post-Move:

if == mln $maxmln:
  // last move must be tested for legality
  store resultpos;
  restore;
  if == dest null or not origin:        // move is composit
    set mvs explode chr 59 thismove;    // split it
    eval join "MOVE: " trim elem 0 mvs; // get origin and moved of first part
    restore;
  endif;
  set legal false;
  set task 0;                  // specifies what subroutine genmoves should do with the generated moves
  gosub genmoves moved origin; // compare all moves of the piece to thismove
  if not legal:
    die "Illegal move";
  endif;
  restore resultpos;
  if unload:
      drop unload dropsqr;   // relocates another piece (also used for castling)
  endif;
  if locustsqr:
    capture locustsqr;       // removes another piece (also used for castling and e.p.)
  endif;
elseif != dest null and origin:
  // setting up game: guaranteed to be legal, apply implied side effects only
  if match dest epsqrs and ep:
    if or checkaleap origin dest 1 1  // code specifically generated to recognize
          checkaleap origin dest -1 1 // e.p.-capable leaps to empty squares
       and == moved P
       and not capture:
      capture #ep                     // and remove the victim
    endif;
  elseif match dest wcastle:
    if == moved K:  // code specifically generated to
      ...           // identify castling partner and move it
    endif;
  endif;
  set ep false;
  set epsqrs;   // empty array (?)
  if checkaleap origin dest 0 2   // code specifically generated to recognize
     and == moved P:              // e.p.-rights-creating leaps
    set ep dest;
    push epsqrs where origin 0 1; // add all e.p. squares
  endif;
  setflag dest;
endif;

The routine 'genmoves' would generate all moves of a given piece in a given location, in the context of the pre-move board position. In the process it would also build a list of side effects: squares that have to be cleared, or where the captured piece has to be dropped. For 'task 0', used here, it would build a string through

join moved chr 32 origin chr 45 dest chr 59

plus the required suicides and freedrops describing the side effects (e.g. ... chr 32 chr 64 chr 45 sideeffect), for comparison with thismove. On a match it would set legal true, and actually perform the suicide.


💡📝H. G. Muller wrote on Tue, Jul 21, 2020 12:55 PM UTC:

If the info on the first move on the sequence was always available, e.g. as firstmoves, firstorigin etc., and we would use the checkbox to suppress autoexecution of the move, it might be acceptably efficient to do the legality checking on all moves. That would certainly simplify the code a lot:

Post-Move:

set legal false;
set task 0; // specifies what subroutine genmoves should do with the generated moves
gosub genmoves firstmoved firstorigin; // compare all moves of the piece to thismove
if not legal:
  die "Illegal move";
endif;
eval join "MOVE: " thismove; // make the move and its specified side effects
if unload:
  drop unload dropsqr;       // dropsquare and unload set by genmove for castlings
endif;
if locustsqr:
  capture locustsqr;         // locustsqr set by genmoves for castlings and e.p. captures
endif;
setflag firstdest;           // moved piece is flagged as non-virgin

The need to store / restore has disappeared. The subroutine genmoves compares the moves of the moved piece in the pre-move position stringwise with thismove, and detects the cases where we are dealing with castling and regular e.p. capture. The implied side effects of these are then flagged by setting unload, dropsqr and locustsqr (which otherwise remain at false). Non-implied side effects are explicitly specified by the move, and thus already executed when we make thismove. So only these implied side effects have to be made afterwards (if the move proved pseudo-legal).

The subroutine genmoves would handle testing and setting of the e.p. info by itself; global variables ep and epsqrs would be involved in that.

Because the code is color-independent, it would probably be best to put it in a subroutine, and have both Post-Move sections just call that subroutine. Since it is also not dependent on the specifics of the variant, it could even be put in an include file. If the routine genmoves would be 'table-driven', it would also be variant-independent, and could also go into that include file. The data to drive it could then be supplied by variant-specific functions for each piece that would return an array describing the moves they could make. It would be the definitions of these funcions that would be generated by the Play-Test Applet, and would have to be copy-pasted to the corresponding preset. (To the Pre-Game section?)

I suppose the info about the first move of the sequence could be extracted 'by hand', by repeated explode, fist on a semicolon, then on a space to separate piece ID from move (already providing moved), and finally the move part on hyphen to get origin and dest.


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 03:23 PM UTC in reply to Greg Strong from 03:14 AM:

What does Do Not Include Moves in Code do?

Game Courier normally creates a program that includes the moves made by players as lines of code. Checking this will keep it from including the moves in the code, which will keep them from being played automatically. If you check it and do nothing else, you will be unable to move pieces. If you do use it, then you have to write code that will play the moves. This is useful if you want to allow multiple moves, because it allows you to handle one move at a time in a multi-move sequence.


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 03:53 PM UTC:

If you were to test the legality of a move before it is made, you would not need the variables that tell you the effects of a move after it has been made. It would also be easier to reuse the same code for both potential and actual moves, and it would make writing code for divergent pieces simpler.

Calculating all legal moves to compare the value returned by thismove with a list of legal moves is really overkill. All you have to do is calculate the legality of the current move. If you test the legality of a move before it is made, you can just get the complete move from thismove and run it through the appropriate tests. This will also allow for some variation in how a move may be entered.

Also, if you want to use the value of a user variable in a command, you need to prepend the variable name with #.


💡📝H. G. Muller wrote on Tue, Jul 21, 2020 05:32 PM UTC in reply to Fergus Duniho from 03:53 PM:

The problem is that it is not always easy to know what exactly one should test. XBetza could allow moves that go through meandering paths to strange destinations, and deducing the path from just the origin and destination square could be problematic. Even with a comparatively simple piece like the Sissa, a move from e4 to g4 could have gone through e5-e6-f5, f5-g6-g5, e3-e2-f3 or f3-g2-g3. With doubly-bent moves (e.g. a Tenjiku Shogi 'area move') it is even worse. The simplest way is often to generate all moves according to the XBetza prescription, and picking out the one that hits the desired destination.

Note that I don't want to generate all moves. Just all moves of one piece. But for that I have to know which piece, and where it starts.

I agree that for simple slides and leaps this might be overkill, and testing those with checkaleap or checkaride (or even checkleap or checkride, if you know the piece to be fully symmetric) would be far simpler. You cannot see from the input move whether that is possible though; the mentioned Sissa move from e4 to g4 looks like a Rook move, but in fact has nothing to do with it. But during interpretation of the XBetza description it can be seen which moves consist of only a single leg. So perhaps the strategy should be to generate direct checks for those (which then for many pieces would handle them completely), and supplement that with a routine to generate all multi-leg moves of a given piece, and only run that to compare these moves to thismove when the simple tests have failed.

But this is basically optimalization. The point is that a routine to generate all moves (even not just of one piece, but of all pieces) is needed anyway, for the purpose of setlegal. Once that function exists, it is trivial codewise (albeit a bit inefficient timewise) to use it to compare the moves with the input move. The best strategy for getting something that works seems to start with the codewise simple method. Once that works it can be optimized by generating dedicated code for some of its tasks.


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 06:21 PM UTC in reply to H. G. Muller from 05:32 PM:

Note that I don't want to generate all moves. Just all moves of one piece. But for that I have to know which piece, and where it starts.

You can get that information yourself. Just play each move under program control, then store the information after each move. Alternately, you can evaluate a move before making it, and the information you need to evaluate it will be on the board.

Even with a comparatively simple piece like the Sissa, a move from e4 to g4 could have gone through e5-e6-f5, f5-g6-g5, e3-e2-f3 or f3-g2-g3.

A Sissa is not a good example in support of what you want to do. All a Sissa function has to do is determine whether there is a path it may legally take to its destination. This can be done without calculating all possible moves for that piece. Besides that, the player would just enter the origin and destination of the piece, not the path that it takes. So, generating paths to compare with the move entered by the player wouldn't work.

The point is that a routine to generate all moves (even not just of one piece, but of all pieces) is needed anyway, for the purpose of setlegal.

Because this is used to check for checkmate and stalemate, it has to be run after the move has been played. You're proposing doing it an additional time. Moreover, it doesn't have to generate detailed information about each move. It just has to cover the first move a piece may make in a sequence of moves. When extra moves have to be entered for a piece, the continuemove command can be used, as it is in Extra Move Chess. But this presumes that you are handling moves one-by-one and not letting them play all at once.


💡📝H. G. Muller wrote on Wed, Jul 22, 2020 05:57 AM UTC:

Would it be an idea to tick the checkbox and take charge of the parsing of the move ourselves? E.g. with code like:

  set mvs explode chr 59 thismove;
  set parts explode ws trim elem 0 mvs;
  set i count mvs;
  if > i 2:
    die "move must be piece ID plus board step";
  endif;
  set sqrs explode chr 45 trim elem dec var i parts;
  if != 2 count sqrs:
    die "board step does not mention two squares";
  endif;
  set myorigin elem 0 sqrs;
  set mydest elem 1 sqrs
  if not onboard myorigin or not onboard mydest:
    die "the board isn't that large";
  endif;
  set mymoved space myorigin;
  if != mymoved elem 0 parts and == 1 i:
    die join "there is no " elem 0 parts " at " myorigin;
  endif;


This seems more efficient than storing and restoring the game state all the time to undo what the system does automatically. And it could also be extended to understand more elaborate move formats, like origin-ep-dest or even origin-ep1-ep2-dest for moves that make a locust captures on ep / ep1 / ep2. Of course we would have to make the move ourselves, at some point, (after the legality testing) by something like

  empty myorigin;
  capture mydest;
  add mymoved mydest;


💡📝H. G. Muller wrote on Wed, Jul 22, 2020 09:30 AM UTC:

A general question: do the logical operators and and or also accept numbers as operands, and do they consider 0 false and any other value true, like in C? Or do I explicitly have to convert them to logical values by comparing the numbers with 0?

And am I correct in assuming there is a distinction between using inc (or empty) as an operator in an expression or as an independent command, where only in the latter case it alters its argument? (I.e. is let a inc var a; the same as inc a; ?)


🕸Fergus Duniho wrote on Wed, Jul 22, 2020 01:28 PM UTC in reply to H. G. Muller from 05:57 AM:

Would it be an idea to tick the checkbox and take charge of the parsing of the move ourselves?

Yes, you could do that. But bear in mind that any move with three or more elements must be entered by hand. Game Courier passes legal moves to JavaScript as pairs of coordinates, because when players move by clicking the mouse or tapping the screen, it interprets two clicks or taps on different spaces as a complete move and immediately submits it as the move. It keeps the interface more user-friendly when players are able to move by mouse click or screen tap.

Of course we would have to make the move ourselves, at some point, (after the legality testing) by something like

 empty myorigin;
 capture mydest;
 add mymoved mydest;

Moves entered by players should normally be processed with the MOVE: command. This name is case sensitive and includes the colon. It should not be confused with the move command. However, the MOVE: command expects no more than two coordinates to a move. If you bypass it, you will also be bypassing the benefits of banning types of input, and you would have to handle all bad input on your own.

Once again, I see you referring to variables simply by name. This works only when assigning a value to a variable. When you want to access the value of the variable, you need to prepend it with #, or, if you need the value in an expression, precede the variable name with the var keyword. These work differently. #myorigin would replace the string "#myorigin" with the value of myorigin while preprocessing the line. This is useful for commands that do not evaluate expressions. In an expression, var myorigin would return the current value of myorigin each time it evaluates the expression. This is useful in functions, which normally need the most up-to-date value of a variable. Using #myorigin in a function definition would insert the then-current value of myorigin into the function, and it would continue to use that value even if the value of myorigin later changed.


🕸Fergus Duniho wrote on Wed, Jul 22, 2020 01:41 PM UTC in reply to H. G. Muller from 09:30 AM:

A general question: do the logical operators and and or also accept numbers as operands, and do they consider 0 false and any other value true, like in C?

Yes, GAME Code is written in PHP, which is written in C. So, in inherits some features of its grandparent language. Like in PHP, which is its parent language, variables are untyped. So, any empty, zero, or null value is false, and any non-false value is true.

And am I correct in assuming there is a distinction between using inc (or empty) as an operator in an expression or as an independent command, where only in the latter case it alters its argument?

Yes, that's correct. Commands may change the values of variables, but operators in expressions just return values without changing them.

is let a inc var a; the same as inc a; ?

let is not a command in GAME Code. You want to use set. With that change, yes, though using the inc command will be more efficient.


💡📝H. G. Muller wrote on Wed, Jul 22, 2020 09:34 PM UTC in reply to Fergus Duniho from 01:41 PM:

OK, thanks. I never used PHP, so it takes a bit of getting used to. The 'let' must have been a sub-conscious confusion with BASIC. What also confuses me is that the # / var do not seem to be needed on origin, dest and such. Is that because these are really subroutines rather than variables?

The need to handle the implied side effects is a bit of a pain. XBetza could potentially define e.p. capture through Gryphon or Sissa moves. Also, to test the pseudo-legality of the latest move of the game, the preceding move would have to correctly set the e.p. rights. The best strategy seems to include a 'stripped' move generator in the GAME code, which generates only moves with implied side effects (i.e. e.p. capture, moves that create e.p. rights, and castlings). This would then be run for every simple move (the mentioned moves are never composit). This would be rather cheap, as most pieces don't have any such moves at all, so it would not generate anything when these move. In most CVs it would only generate something when a Pawn or a King moves, and it would then only generate the double-push if it was a 2nd-rank Pawn,  the e.p. capture if an e.p. square was created on the previous move, and in range, and sometimes one or two castlings. The few moves it generates could then be compared to origin and dest, and if one of them matches, all the side effects of it indicated by the move generator (i.e. e.p.-victim removal, Rook movement, or setting of the e.p. rights) would then be applied to the board.

For the latest move a complete move generator would generate all moves of the moved piece, and compare those to the input move. This is not optimally efficient, but it is easy and requires very little code that wasn't needed already for other purposes. And it is still very much cheaper than generating all legal moves in the final position for the purpose of setlegal: it has to be done only for a single piece, and the full legality has to be tested only for the move that matches the input. While setlegal requires the pseudo-legal moves of all pieces, and has to test each and everyone of those for legality. So there really wouldn't be any significant gain in optimizing it further, just a far larger code complexity.


🕸Fergus Duniho wrote on Thu, Jul 23, 2020 02:35 AM UTC in reply to H. G. Muller from Wed Jul 22 09:34 PM:

What also confuses me is that the # / var do not seem to be needed on origin, dest and such. Is that because these are really subroutines rather than variables?

These are early system variables that I made available before I started making system variables available with $ prepended to them. You can now access them as $origin, $dest, and so on. If I had to do it over, you would not be able to use them just by name, but if I changed it now, it would break lots of code. I recommend using them with $, because that makes it clearer that they are variables.


💡📝H. G. Muller wrote on Thu, Jul 23, 2020 07:56 AM UTC:

Just to be sure: lines in subroutines are only 'pre-processed' when they are executed, but functions when they are defined? So in subroutines var and # would be equivalent?

I slowly start to converge on a design. The idea is that the Post-Move code would always only contain only the line gosub HandleMove false; (for white) or gosub HandleMove true; (for black). Similarly, the Post-Game code would only contain gosub GameEnd true/false; . The routines would be universally applicable code, which could go into the Pre-Game section, or into a file that would be included from there.

The rules would then be described in the Pre-Game section by a large initialized array 'legdefs' of integer numbers, encoding all the moves, functions for each piece type returning where the move data for that piece type starts in legdefs. Plus statements to set a number of parameters, like what the royal type for each player is, whether stalemate is a win or draw, what King destinations imply castling, where the castling partners are located, how large the promotion zone is, what you can promote to on various ranks, which pieces van promote and stuff like that. Defaults for those parameters could be set in the included file, but the CV-specific code could overrule those settings after the include. It is this Pre-Game code that would be generated by the Play-Test Applet.

A rough draft of the code for such a design is this:

// the following arrays and functions are variant-specific, and would be defined in Pre-Game:

set legdefs (....); // a (very large) array of numbers, describing the moves of all pieces
                    // each move is a sequence of 'legs' (leaps or slides in one direction)
                    // each leg is described by 4 numbers in legdef:
                    // range, sideway step, forward step and 'mode'.
                    // the mode packs bit flags describing what must be at the end of the leg
                    // a move with 0 legs is used to indicates the list for that piece ends

def P cond #0 223 45;  // functions map piece types on their move definition in legdefs
def p cond #0 235 70;  // each piece has two move definitions: e.p.&castling-only, or all their moves
def K ...

set many wroyal K broyal k;
...

// the following code is generic, and can be handled as a Pre-Game include

sub GotMove orisqr destsqr:
  // process the move specified by the params and the globals like locustsqr
  if == 0 #task:      // apply side effects of a matching move
    verify == #orisqr origin and == #destsqr dest:
    if #locustsqr:
      empty locustsqr;
    endif;
    if #dropsqr:
      add #unload #dropsqr;
    set hit true;    // abort further generation

  elseif == 1 #task: // test input move for pseudo-legality
    verify == #orisqr origin and == #destsqr dest:
    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;
    endif;
    set hit true;    // we found a matching pseudo-legal move

  elseif == 2 #task: // accumulate all pseudo-legal moves
    setlegal #orisqr #destsqr;

  elseif == 3 #task: // test whether move captures king (for check test)
    if == #royal space #destsqr:
      set hit true;
    elseif #locustsqr:
      set hit == #royal space #locustsqr;
    endif;

  elseif == 4 #task: // find one legal move (for mate test)
    my victim locustvictim;
    set victim space #destsqr; // save old values
    // make the move
    if #locustsqr:
      set locustvictim space locustsqr;
    endif;
    if #dropsqr:
      add #unload #dropsqr;
    endif;
    move #orisqr #destsqr;
    // test whether in check
    gosub InCheck #side;
    // unmake the move
    move #destsqr #orisqr;
    if #dropsqr:
      empty dropsqr;
    endif;
    if #locustsqr:
      add #locustvictim #locustsqr;
    endif;
    set hit not #hit; // continue when in check, stop when not

  endif;
endsub;

sub NextLeg togo legindex startsqr cursqr iso:
  // this routine is the heart of the move generator
  // it generates the destinations of one leg,
  // and then calls itsef recursively for the remaining legs
  // 'togo' tells how much legs still have to be done; when 0 we have a complete move
  // 'legindex' tells where the leg descriptions start in the 'legdefs' array
  // 'startsqr' is where the piece that must make the move starts
  // 'cursqr' is where any previous legs brought us
  // 'iso' is the number of leaps taken in an earlier riding leg
  if #togo: // move not complete yet; attempt next leg
    my range dx dy mode to;
    // retrieve leg description (next 4 elements in 'legdefs')
    set range elem #legindex #legdefs;
    set dx elem + 1 #legindex #legdefs;
    set dy elem + 2 #legindex #legdefs;
    set mode elem + 3 #legindex #legdefs;
    if & #mode i_FLAG:                    // initial move only
      verify not ?startsqr;               // suppres it for non-virgin piece
    endif;
    // simple example, handling only (divergent) leaps
    if == 1 #range:                       // leg is leap
      set to where #cursqr #dx #dy;       // calculate destination
      set victim space #to;               // look what is there
      verify != void #victim:             // abort if off board
      if == @ #victim:                    // empty target
        if match #to #epsqrs and
           & mode e_FLAG:                 // move is valid e.p. capture
          set locustsqr #ep;              // flag that it will capture last mover
          set implied true;               // this is an implied side effect
        else:
          verify & #mode m_FLAG;          // m_FLAG etc. are in fact hard-coded constants like 1, 2, 4, 8...
        endif;
      elseif != #side islower #victim:    // foe
        verify & #mode c_FLAG;
      else:                               // must be friend
        verify & #mode d_FLAG;
        set unload #victim;               // remember what we 'captured'.
      endif;
      gosub NextLeg dec #togo + 4 #legindex #startsqr #to #iso; // do nex leg
    else:                                 // leg is slide
      ...
    endif;
  else: // move finished successfully; process it
    GotMove #startsqr #cursqr;
  endif;
endsub;

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
  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
    set many locustsqr 0 dropsqr 0;   // default is no locust capture or unload
    set implied 0;                    // generated e.p. or castlings set this
    gosub NextLeg #legcount #index #sqr #sqr 0;
    set index + #index * 4 #legcount; // skip to the next set of legs (= move)
  loop until hit;
endsub;

sub GenAll black:
  if #black:
    def friends onlylower;
  else:
    def friends onlyupper;
  endif;
  for (from piece) fn friends;
    gosub GenMoves #piece #from 1;
  next;
endsub;
 
sub HandleMove player:
  gosub ParseMove thismove; // this extracts origin, dest, moved, suicide, freedrop, dropped
  set hit false;
  if == mln $maxmln:
    set task 1; // request legality test
    gosub GenMoves moved origin 1; // match all moves
    if not #hit:
      die "a " moved " cannot move that way!";
    endif;
  endif;
  set task 0; // request execution of implied side effects
  gosub GenMoves moved origin 0;   // only tries e.p. and castling
  eval join "MOVE: " thismove;     // make the move
  setflag dest;
endsub;

sub InCheck player
  set task 3; // request king-capture test
  set hit false;
  set royal cond #player #broyal #wroyal;
  gosub GenAll not #player;
endsub;

sub GameEnd player:
  gosub InCheck player;
  if #hit:
    die "that move would put you in check!"
  endif;
  set task 4;  // request one legal move
  gosub GenAll not player;
  if not #hit: // could not find one
    gosub InCheck not player;
    if #hit:   // checkmate!
      won;
    elseif #staledraw: // stalemate
      draw;
    else:
      won;
    endif;
  endif;
  ... // draw stuff
endsub;

 


💡📝H. G. Muller wrote on Thu, Jul 23, 2020 03:43 PM UTC:

Below is how the GAME code generated for the Pre-Game would have to look for orthodox Chess. This assumes 'smart' generation, which realizes that most pieces are symmetric, so that white and black can use the same table entries for those, and that the Bishop is just the final part of the Queen. Most likely it would be too dumb to see the latter, and then a separate Bishop section would be added. If the pieces were asymmetric, or it was not smart enough to realize they are symmetric, all pieces sections would have to appear in duplicat: one for white, one for black.

include betza.txt
set legdefs
 1  1  0  1  3 // King (0)
 1  1  0 -1  3 // 3 = m_FLAG + c_FLAG
 1  1  1  0  3
 1  1 -1  0  3
 1  1  1  1  3
 1  1  1 -1  3
 1  1 -1  1  3
 1  1 -1 -1  3
 2  9  1  0  8 // castling (40)
    1  2  0  3
 2  9 -1  0  8
    1 -2  0  3
 0
 1  9  0  1  3 // Queen (59)
 1  9  0 -1  3
 1  9  1  0  3
 1  9 -1  0  3
 1  9  1  1  3 // Bishop (79)
 1  9  1 -1  3
 1  9 -1  1  3
 1  9 -1 -1  3
 0
 1  9  0  1  3 // Rook (100)
 1  9  0 -1  3
 1  9  1  0  3
 1  9 -1  0  3
 0
 1  1  2  1  3 // Knight (121)
 1  1  2 -1  3
 1  1  1  2  3
 1  1 -1  2  3
 1  1 -2  1  3
 1  1 -2 -1  3
 1  1  1 -2  3
 1  1 -1 -2  3
 0
 1  1  0  1  1 // white Pawn (162), 1 = m_FLAG
 1  1  1  1  2 // 2 = c_FLAG
 1  1 -1  1  2
 1  1  1  1  4 // e.p. capture (177), 4 = e_FLAG
 1  1 -1  1  4
 2  1  0  1 577 // double push, 577 = m_FLAG + i_FLAG + rights creation
    1  0  1  1
 0
 1  1  0 -1  1 // black Pawn (197)
 1  1  1 -1  2
 1  1 -1 -1  2
 1  1  1 -1  4 // e.p. capture (212)
 1  1 -1 -1  4
 2  1  0 -1 577
    1  0 -1  1
 0;

def K cond #0   0 40;
def k cond #0   0 40;
def Q cond #0  59 58; // 58 = empty move set
def q cond #0  59 58;
def R cond #0 100 58;
def r cond #0 100 58;
def B cond #0  79 58;
def b cond #0  79 58;
def N cond #0 121 58;
def n cond #0 121 58;
def P cond #0 162 177;
def p cond #0 197 212;

set pzs 1;             // promo zone depth
set rooks a1 a8 h1 h8; // castling partners
set wchoice (Q R B N);
set bchoice (q r b n);
set stalemate 1;
set wroyal K;
set broyal k;

 


🕸Fergus Duniho wrote on Thu, Jul 23, 2020 04:29 PM UTC in reply to H. G. Muller from 03:43 PM:

Game Courier offers two ways of evaluating moves. I usually default to using the mathematical functions, which treat the board as a grid whose spaces have mathematical relations to each other. But I have also provided functions for logical evaluations of moves. These represent the board through logical relations between spaces rather than mathematical relations. To use these, you define various directions in terms of which space you will go to if you move in that direction from a particular space. Using these may fit better with how you are trying to go about evaluating piece movement. See the Programming Piece Movement in Game Courier tutorial for more about this.


💡📝H. G. Muller wrote on Thu, Jul 23, 2020 05:28 PM UTC:

Well, this is definitely a powerful method, and allows handling of boards of any topology. But I don't see how it would simplify things in this case. The Interactive Diagram can only handle grid boards consisting of squares. Perhaps with some straightforward wrapping rules (periodic boundary conditions, such as cylinder or torus). Betza notation would be meaningless in boards with irregular topologies.

The code example doesn't alllow for wrapping yet. I guess that when the where operator produces an off-board result, it should really test mode to see whether the move is supposed to wrap (o_FLAG). If it does I guess I would be in for some cumbersome arithmetic on separate file and rank of the startsqr. That would also mean that I cannot use ray for the riding legs, but would somehow have to extend the ray after wrapping.


🕸Fergus Duniho wrote on Thu, Jul 23, 2020 05:42 PM UTC in reply to H. G. Muller from 05:28 PM:

I wasn't suggesting it for use with unusual topologies. I'm thinking it could make it easier for a program to translate Betza code into finetune distinctions using logical directions rather than mathematical relations.


💡📝H. G. Muller wrote on Thu, Jul 23, 2020 05:59 PM UTC:

It is true that XBetza uses directions and relative directions a lot. But the Diagram script already translates that to absolute grid vectors in a compilation step. The legdefs array is almost exactly what the Diagram uses as internal representation (except that dx, dy, range and mode there each have their own array, but that is a minor detail). So the only thing it has to do when someone would hit the would-be button 'Show GAME code' would be to dump those tables for the pieces that were chosen to participate in the desired format, and remember where the data for each piece started. It can be easily checked during the Betza-to-table compilation whether a piece is totally symmetric. (Not done yet; the Diagram only makes tables for white pieces during the compilation, and when it later generates moves for black pieces, it just flips the sign of all step vectors it retrieves from the table. But it seems faster to tabulate the black pieces separately, flipping their steps already in the table, if they were asymmetric.)


Carlos Cetina wrote on Fri, Jul 24, 2020 05:21 AM UTC:

Configuring the applet to play test my variant called Cetran Chess 3, I find that something is wrong after inserting the HTML code on a web page because images of certain pieces are not uploaded. Five are the ones that fail: Amazon, Marshall, Archbishop, Knight-Wazir and Knight-Ferz.

Play-test applet

 

files=12 ranks=8 promoZone=1 promoChoice=AMZ Q S GRY AAN M A DK DH NW NF graphicsDir=/graphics.dir/alfaerie/ squareSize=52 graphicsType=gif pawn:P:ifmnDfmWfceF:pawn:a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,,a7,b7,c7,d7,e7,f7,g7,h7,i7,j7,k7,l7 queen:Q:Q:queen:h1,,h8 archbishop:A:BN:knight--bishop:l1,,l8 chancellor:M:RN:knight--rook:a1,,a8 amazon:AMZ:QN:knight--queen:d1,,d8 sissa:S:mavsiQ:snake:f1,,f8 gryphon:GRY:FyafsF:gryphon:k1,,k8 aanca:AAN:WyavsW:dragon:c1,,c8 knight wazir:NW:WN:wazirknight:g1,,g8 knight ferz:NF:FN:ferzknight:j1,,j8 dragon horse:DH:BW:promotedbishop:b1,,b8 dragon king:DK:RF:promotedrook:i1,,i8 king:K:KisO4:king:e1,,e8
The Snake represents the Sissa.

Regardless of this small inconvenience, I can not but congratulate you for having developed such an extraordinary applet and I hope it is not complicated to fix the problem.


💡📝H. G. Muller wrote on Fri, Jul 24, 2020 06:32 AM UTC:

Umm, there seems to be a mismatch between the naming of the scalable (SVG) pieces used in the Applet, and the fixed-size 50x50 (GIF) bitmaps in the alfaerie directory. E.g. the wazirknight does not show up because for the alfaerie bitmaps it is actually called knightwazir. The Archbishop / Chancellor / Amazon are my own fault; the SVG renderer used by the Applet creates such compound images 'on the fly', by referring to them as knight--bishop, knight--rook and knight--queen, while in the 50x50 alfaerie set they are of course called cardinal, chancellor and amazon. I should have had the Applet script replace those names when it dumps the design as a diagram using the standard image set.

Thank you for reporting this; it will certainly be fixed one way or the other. For now you can work around it by editing the Diagram description to replace the faulty filenames of the missing pieces by the correct ones. An alternative would be to keep the names, but change the graphicsDir from /graphics.dir/alfaerie/ to http://winboard.nl/my-cgi/fen2.cgi?s=50&p= and the graphicsType to an empty string (just graphicsType= ), to get the same anti-aliased images as the Applet uses (but 50x50). But then you would be using off-site images, and that is really against CVP policy.

For the editors:

In connection with this, it is perhaps a good time to bring up the following issue: wouldn't it be a good idea to improve the availability and/or quality of piece graphics on CVP? The rather ragged-looking alfaerie 50x50 GIF bitmaps in /graphics.dir/alfaerie/ are still the site's standard piece set. Isn't it time to replace those with anti-aliased PNG images, or at the very least provide such a set next to it (e.g. in /graphics.dir/alfaeriePGN/)? I suppose it would be easy to copy the same index page on alfaerie to that other directory, to showcase the pieces.

I would also be happy if there could be a 35x35 alfaerie image set; for the Applet I am currently using an off-site SVG renderer. Of course I could upload a set of 35x35 images myself, even defvote a member-submitted article to them, but then they would be hidden in /membergraphics/MSalfaerie-33 (say), and no other person but me would ever find them there. To get good use of the graphics we have, they really should be provided as options in places where people could decide to use them.


Greg Strong wrote on Fri, Jul 24, 2020 03:54 PM UTC in reply to H. G. Muller from 06:32 AM:

I think changing over to anti-aliased pieces is certainly a good idea and it is something that I have wanted to do for quite a while, but it is a large undertaking. The Alfaerie set is huge, but even getting the most common pieces would be worthwhile. It is unlikely we'd ever get them all converted. I know you have done a lot of work converting Alfaerie images to SVG already. I did some work converting the Abstract pieces but stopped, although I am happy to resume. I want to upgrade the graphics in ChessV as well.

I do not want to replace existing images - I think we make a /graphics.dir/alfaeriePGN/ and /graphics.dir/alfaeriePGN35/ and fill them with upgrade images as they become available. I don't want to replace the existing ones because, for my games at least, I would not want to mix-and-match. I would only switch over to anti-aliased graphics if they were available for all the pieces I was using.


Carlos Cetina wrote on Fri, Jul 24, 2020 05:11 PM UTC:

Okay, no rush. While fixing the issue, I'm using this other setup which is very useful to study the tactical possibilities that Sissa offers within the context of standard chess when replacing Queen for Sissa.

files=8 ranks=8 promoZone=1 promoChoice=S R B N graphicsDir=/graphics.dir/alfaerie/ squareSize=52 graphicsType=gif pawn:P:ifmnDfmWfceF:pawn:a2,b2,c2,d2,e2,f2,g2,h2,,a7,b7,c7,d7,e7,f7,g7,h7 knight:N:N:knight:b1,g1,,b8,g8 bishop:B:B:bishop:c1,f1,,c8,f8 rook:R:R:rook:a1,h1,,a8,h8 sissa:S:mavsiQ:snake:d1,,d8 king:K:KisO2:king:e1,,e8

💡📝H. G. Muller wrote on Fri, Jul 24, 2020 05:31 PM UTC in reply to Carlos Cetina from 05:11 PM:

It should now be fixed for new Diagrams generated by the Applet. But it might still be easier to just edit the image names in the Diagram you already made than redoing it from scratch. While fixing the issue I was baffled by the fact that the Applet had stopped working completely; its board mysteriously disappeared. After a lot of debugging it turned out that it was upset that another Diagram had appeared on the same page, in the Comments. The Applet needed to change some settings after initialization, but the way I had programmed that was not resistent to the betza.js file being read a second time, undoing some of the changes. I guess it was a very bad idea to have some of the standard initialization code execute unconditionally when the script gets loaded, in a script that could be loaded multiple times. Eventually I modified the script such that custom post-initialization code can be executed after all Diagrams on the page have done their initialization, rather than just the first one.

I also made the Applet close the ad side bars when the board has more than 10 files. This should prevent the compression we see in the screenshot you posted.

BTW, I noticed that you are using piece IDs of more than one letter. The Diagram was not really designed for that. In particular, it confuses its detection of which promotions are allowed. Because you use both K and DK, and put DK amongst the promotion choices, it now thinks K is also an allowed choice, because there is a K in DK. I am not sure how this can be cured without breaking already existing diagrams.

@Greg:

OTOH, having one or two ugly pieces among good-looking ones would provide a really good incentive for creating the missing SVG. :-) The variants you authored do not seem to feature that many pieces for which we have no SVG yet.


Greg Strong wrote on Fri, Jul 24, 2020 05:50 PM UTC in reply to H. G. Muller from 05:31 PM:

Where can I download the latest set of SVGs?


💡📝H. G. Muller wrote on Fri, Jul 24, 2020 06:29 PM UTC in reply to Greg Strong from 05:50 PM:

You already put those on this website, at /graphics.dir/svg/ . I haven't made any new ones since then, as it seemed not much was happening with them, and almost everything that I imagined I would ever need was already done.

There is an identical set on the winboard.nl server, where I have the SVG renderer as CGI program. I use them in the Diagram of the Applet through that renderer, but the Applet first looks in the /graphics.dir/svg/ directory on CVP to see what pieces exist. (Browsers do not allow peeking at a website other than where the main HTML page comes from.) The piece table of the Applet contains everything that is there, plus some compounds that the renderer creates on the fly.

There are no SVG for these compounds (or for rotated pieces, or red / green pieces), but since the renderer can supply all those as PGN it should not be too difficult to download those one by one and put them in the PGN sets.


Greg Strong wrote on Fri, Jul 24, 2020 07:05 PM UTC in reply to H. G. Muller from 06:29 PM:

Ok, I opened wqueen.svg with Inkscape and was able to save it as a 50x50 PNG with no problems. But making the black piece isn't working quite right. The object "inside" the path doesn't go all the way to the edges so when I change the fill color there is still a thin white border. Am I doing something wrong or do I need to edit this shape? Or should I not be using Inkscape at all but your online renderer?


Carlos Cetina wrote on Sat, Jul 25, 2020 07:06 PM UTC:

Okay, thanks. The issue about images has been fixed as can be seen in the following diagram:

files=12 ranks=8 promoZone=1 promoChoice=Z Q S G D M A L H W F graphicsDir=/graphics.dir/alfaerie/ squareSize=52 graphicsType=gif pawn:P:ifmnDfmWfceF:pawn:a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,,a7,b7,c7,d7,e7,f7,g7,h7,i7,j7,k7,l7 queen:Q:Q:queen:d1,,d8 archbishop:A:BN:cardinal:a1,,a8 chancellor:M:RN:chancellor:l1,,l8 amazon:Z:QN:amazon:i1,,i8 sissa:S:mavsiQ:snake:f1,,f8 gryphon:G:FyafsF:gryphon:h1,,h8 dragon:D:WyavsW:dragon:c1,,c8 wazirknight:W:WN:knightwazir:e1,,e8 ferzknight:F:FN:knightferz:j1,,j8 dragon horse:H:BW:promotedbishop:k1,,k8 dragon king:L:RF:promotedrook:b1,,b8 king:K:KisO4:king:g1,,g8

The applet works fine with mirror symmetry but something is wrong with asymmetric setups since after uploading the applet to a webpage they are distorted duplicating some images.

Play-test applet 2

files=12 ranks=8 promoZone=1 promoChoice=A Q S G D M C R B N H graphicsDir=/graphics.dir/alfaerie/ squareSize=52 graphicsType=gif pawn:P:ifmnDfmWfceF:pawn:a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,,a7,b7,c7,d7,e7,f7,g7,h7,i7,j7,k7,l7 queen:Q:Q:queen:b1,,e8 archbishop:C:BN:cardinal:l1,,g8 chancellor:M:RN:chancellor:h1,,l8 amazon:A:QN:amazon:j1,,f8 sissa:S:mavsiQ:snake:f1,,i8 gryphon:G:FyafsF:gryphon:g1,,d8 dragon:D:WyavsW:dragon:c1,,k8 wazirknight:N:WN:knightwazir:e1,,c8 ferzknight:H:FN:knightferz:i1,,j8 dragon horse:B:BW:promotedbishop:k1,,a8 dragon king:R:RF:promotedrook:a1,,b8 king:K:KisO4:king:d1,,h8

I am already labeling the pieces with single letters.

On the other hand, while playing vs the applet's AI at one point it castled Fischer-style, which is problematic in this variant because I am proposing there be no castling. It would be nice if in asymmetric setups one could choose the option "do not cast", but if implementing it requires to spend too much time, please do not worry, for me it is not something urgent, do it when you can.


💡📝H. G. Muller wrote on Sat, Jul 25, 2020 09:21 PM UTC:

OK, I see what the problem is. The diagram assumes by default that the symmetry is 'mirror', while I thought it would assume 'none'. When symmetry=mirror, when setting up the initial position it automatically places a black piece opposit to every white piece it places. So that you only have to specify the locations of the white pieces. This can overwrite any black piece it placed before. If the position was really symmetric, that would not matter, because it would be the same piece. But otherwise it depends on the order the pieces are placed which black pieces are overwritten, and which not.

The Applet should have included symmetry=none in the HTML description of the diagram when the 'asymmetric' checkbox is ticked, to suppress this behavior. I will make the Applet do that, but you can fix your existing diagram by just adding this line.

As for the castling: the default move for a King (as it is specified in the piece table) is KisO2 (or on wider boards KisO3 or KisO4). The isOn means castling with n King steps. I you don't want castling, the King would have to have just K as move. There is no non-castling King in the table, so you would have to alter its move. The Applet does allow you to alter the default move of a piece; for many pieces there even isn't a valid default move. E.g. I would not know how an Ox moves. (Perhaps there should be a separate non-castling King in the table, as this seems a case that would be frequently needed, just like there is also a shatranj Pawn without double push. But then I could not start with two Kings on the board, as they might be the wrong type of Kings...)


💡📝H. G. Muller wrote on Mon, Jul 27, 2020 09:20 PM UTC:

These are just some dummy messages for forcing Carlos' comment off the page. Problem is that his comment contains a link to the betza.js script without a ?nocache=true suffix, and it appears after the article. So the loading of the cached script this causes overwrites the updated script loaded in the article. Which contains a new feature essential for making the generation of GAME code work...


💡📝H. G. Muller wrote on Mon, Jul 27, 2020 09:20 PM UTC:

dummy 2


💡📝H. G. Muller wrote on Mon, Jul 27, 2020 09:21 PM UTC:

dummy 3


💡📝H. G. Muller wrote on Mon, Jul 27, 2020 09:21 PM UTC:

dummy 4


Carlos Cetina wrote on Wed, Jul 29, 2020 02:40 PM UTC:

OK, thanks; issues of symmetry and castling have been fixed.

I have a question about labeling pieces: I see that 4 are prepended by a + sign [tokin, promoted lance, promoted knight and promoted silver], could the applet handle IDs prepended by an asterisk (*)?


💡📝H. G. Muller wrote on Wed, Jul 29, 2020 07:28 PM UTC in reply to Carlos Cetina from 02:40 PM:

The only thing the diagram uses the piece IDs for (apart from printing, for which they could be anything), is to check which promotions are allowed, by testing whether the ID occurs in promoChoice. When I wrote the code for that I imagined piece IDs would always be single characters, so I did not take the trouble to require any separator characters between piece names in promoChoice. E.g. for Chess I it would just be NBRQ . It just looks whether the piece ID is a sub-string of promoChoice. This is why multi-character Ids can give problems, expecially when mixed with single-character Ids. If all IDs were two characters, and they were separated by spaces (or whatever punctuation) in promoChoice, there would not be any problem. Only if the ID of one piece would be a sub-string of that of another it could be confused, and even then it is only a problem if you want to allow promotion to the long name, but not to the short name.

In Shogi variants promotion is usually controlled by promoOffset, which defines a fixed promoted form for each promotable piece. In that case promoChoice is ignored, and there never can be a problem, no matter what the piece IDs are. This is why the Shogi custom of indicating promoted pieces with a + prefix to the unpromoted ID is never harmful.

Using a * or ! as prefix in a piece ID is the most problematic of anything you could do, because these symbols have a special meaning in the promoChoice string: a *L there would mean you can promote to L, but only if you have an L in hand (usually because it was captured before). Other prefixes (e.g. #L) would probably be harmless, as long as you don't want to use them to distinguish an L from a #L, and want to allow choosing a #L but not an L.


Carlos Cetina wrote on Thu, Jul 30, 2020 08:41 PM UTC:

Thanks for answering. Actually, I was only interested in what is related to printing, that is, how the movements are described and listed suitable to be read by anyone. I am not concerned if a pawn can not be promoted to a piece whose label includes a special sign.

I have noticed that currently, when copying and pasting the applet's HTML code into a webpage, only is displayed an empty board, piece images are not uploaded. Is this because of a bug? Or did you temporarily put a lock on it so that your work on the GAME code table-driven move generator is not affected?

The applet that I'm posting on Sac Chess, since several days ago I already had it stored in another point of the cyberspace.


💡📝H. G. Muller wrote on Thu, Jul 30, 2020 09:53 PM UTC:

Oops, my bad. Because we now have anti-aliased Alfaerie pieces on this website, I had changed the HTML for the diagram it prints to use those, instead of the old ones. But I forgot to change the graphicsType from gif to png.

This is fixed now. To fix it in diagrams you already made, just change 'gif' into 'png', and they should work.


Carlos Cetina wrote on Fri, Jul 31, 2020 01:29 AM UTC:

OK, don't worry and thanks!


Greg Strong wrote on Sun, Aug 2, 2020 08:28 PM UTC:

Checking Stalemate is a win doesn't seem to generate any extra stalemate code. Also, the stalemate options aren't mentioned on the interactive diagram page. I'm guessing I just need to add stalemate=win?


💡📝H. G. Muller wrote on Sun, Aug 2, 2020 08:53 PM UTC:

You have to press the 'Apply' button to make anything you changed above the diagram take effect. Then it would add stalemate=win. (In fact any setting other than draw would have the same effect.)

I suppose I could attach handlers to the checkboxes that trigger on a state change. But there are also text entries there, and for those it usually leads to trouble when you don't wait until the user is done typing.

The Diagram would not make the exception that stalemating with a lone King is a draw. But this seems a silly rule anyway. The only practical case I know where a bare King delivers stalemate is in defending against promotion of a Rook Pawn, preventing the supporting King to step away from the edge. But that only works if the strong side chooses to stalemate himsef by pushing the Pawn. You cannot force him to do that. The rule is as pointless as an extra rule that a checkmate in KNNK would count as a draw in orthoChess.


Greg Strong wrote on Sun, Aug 2, 2020 11:33 PM UTC in reply to H. G. Muller from 08:53 PM:

Here's a bug - the code it generates doesn't show any piece graphics. I think it is because the pieces have .png after the image name. When I remove the extensions, it works. I think maybe it is because it also includes graphicsType=png, maybe resulting in it looking for "pawn.png.png"?


💡📝H. G. Muller wrote on Mon, Aug 3, 2020 09:22 AM UTC in reply to Greg Strong from Sun Aug 2 11:33 PM:

Indeed. This crept in when I changed the diagram on the page from using the renderer (which requires the piece name without extension) to using the on-site PNG image files; the internal names used in the diagram already have the graphicsType extension on them, and when creating the HTML code for display I was just copying them from that table. I fixed it now.


💡📝H. G. Muller wrote on Thu, Aug 6, 2020 12:10 PM UTC:

The feature that allows you to dump the rules of the diagram as GAME code for creating rule-enforcing presets now seems to be at a stage where it could start to be useful. The code in the include file now would handle most CVs satisfactorily. Support of all the moves that can be described in XBetza and handled by the Interactive Diagram should be no problem, except for the Imitator. It now also tests for checkmate and stalemate, the 50-move rule, and repetitions. It can handle all the promotion rules that the Applet can be configured for. (I.e. piece-type-dependent zone depth, deferral, and promotion to captured pieces only.) Shuffling of pieces to get a start position also works.

There are some minor issues; testing for repetitions does ignore the virginity flags. The GAME-code implementation has a flag for every board square, but for any given CV most of the flags would be irrelevant, because the piece on that square (if any) would not have any initial moves defined on it. It is a bit of a chore to figure out which flags are relevant. This seems mostly a cosmetic problem, though; in virtual every variant the only relevant flags would be for castling and e.p. capture, and repetition loops in which you have those rights in the first occurrence, and then destroy them in the loop are very rare, and usually deserve to be draws anyway. Who cares if they are 2-fold or 3-fold repeats? Having the server declare a draw is a violation of FIDE rules anyway; these only say that the players can claim a draw in those situations.

Other things I have not implemented yet:

  • Testing the highlighted moves for legality; currently all pseudo-legal moves are highlighted.
  • Recognizing passing through check as illegal.
  • King baring as a winning condition.
  • Creation of e.p. rights by oblique lame leaps (Betza n on a W or F).
  • Imitators.
  • Crooked and circular pieces (Betza z and q).

All of that can be added through updating the GAME code in the include file, and would not affect operation of this Applet.

 


A. M. DeWitt wrote on Tue, Aug 18, 2020 12:40 AM UTC:

There is a bug in the rule-enforcement subroutines. The code won't allow any piece to be moved - it just exits with the error message "You cannot move opponent pieces." Luckily, tweaking the cond statement that controls this exit point should fix it easily. When using cond its important to know that it will evaluate the second and third operands before the first operand unless they are encapsulated in parentheses. I'm only guessing here, but I think if you change cond #player islower #mover isupper #mover to cond #player (islower #mover) (isupper #mover) it should work as intended.


💡📝H. G. Muller wrote on Tue, Aug 18, 2020 09:08 AM UTC in reply to A. M. DeWitt from 12:40 AM:

The code won't allow any piece to be moved - it just exits with the error message "You cannot move opponent pieces."

This is weird, because all the test presets I made that use the betza.txt include file work fine. I agree that cond is treacherous, and that it would be good defensive coding practice to always enclose its last two arguments in parentheses; this code was from before I knew that, though. But in this case it should make no difference, because islower and isupper have no side effects. So it is perfectly fine to evaluate both of these, and then just take the result indicated by the first operand and discard the other. So the parentheses should make no difference.

Can you give me the URL to the case where you encountered this behavior?

As an afterthought: are you sure you called HandleMove with the correct argument (false | true) for the section you put them in? If you would have inadvertantly swapped that, this would evoke the behavior you report. You aren't by any chance trying to make the first move for 'black' (i.e. the player that handles the lowercase pieces)?


A. M. DeWitt wrote on Tue, Aug 18, 2020 01:56 PM UTC in reply to H. G. Muller from 09:08 AM:

I simply recreated my game Yangsi in the applet, clicked on the button for showing the Game Code, and copied the code into a makeshift preset for it. When I tried to move a piece, the program exited with the error message "you cannot move opponent pieces." I tried it as normal and after swapping the Post-Move sections, but the error persisted.


💡📝H. G. Muller wrote on Tue, Aug 18, 2020 02:01 PM UTC:

Both presets I can (indirectly) reach through that link work fine for me.


A. M. DeWitt wrote on Tue, Aug 18, 2020 08:56 PM UTC in reply to H. G. Muller from 02:01 PM:

Those presets were made long before this Play-Test Applet was a thing. What I meant in my last comment was that I recreated the setup and rules of Yangsi in the Play-Test Applet, clicked Start Position, clicked Game Code to get the code, and edited the Yangsi preset to make a fake preset using that code. After that, I tested the fake preset, and after moving a piece, the error showed up.


💡📝H. G. Muller wrote on Tue, Aug 18, 2020 09:00 PM UTC in reply to A. M. DeWitt from 08:56 PM:

Well, as long as I don't have a link to that preset, there is nothing I can do about it. All presets I made that link to that same code work fine. (At least they did until the JavaScript was changed; now only moves without side effects work). I never get the error message you mention, unless I am indeed moving a piece of the opponent.


A. M. DeWitt wrote on Wed, Aug 19, 2020 08:17 PM UTC in reply to H. G. Muller from Tue Aug 18 09:00 PM:

Here's a preset I made using code from the Play-Test Applet:

Yangsi


🕸Fergus Duniho wrote on Wed, Aug 19, 2020 08:27 PM UTC in reply to A. M. DeWitt from 08:17 PM:

I just tried it out in solitaire mode. It displayed legal moves by White's pieces, but whenever I tried to move a piece, it gave the error message "you cannot move opponent pieces."


💡📝H. G. Muller wrote on Wed, Aug 19, 2020 11:25 PM UTC in reply to A. M. DeWitt from 08:17 PM:

Tick "Do not include moves in code".

I guess I should differentiate the error message between moving opponent pieces and empty squares.


Greg Strong wrote on Sat, Oct 10, 2020 06:01 PM UTC:

I am trying to make a preset for I-Chess with this, but when I try to open the preset, I get the message "BANNED INPUT: gosub GameEnd true; on turn 1". I tried checking Do Not Include Moves in Code, but that only changed the error slightly. What am I doing wrong? The preset is here:

http://play.chessvariants.com/pbm/play.php?game%3DI-Chess%26settings%3Dstandard


💡📝H. G. Muller wrote on Sat, Oct 10, 2020 09:28 PM UTC in reply to Greg Strong from 06:01 PM:

You pasted the call to GameEnd for black in the "Initial Moves" section, instead of the Post-Game2 section.


Greg Strong wrote on Sat, Oct 10, 2020 09:45 PM UTC in reply to H. G. Muller from 09:28 PM:

Ok, that was definitely wrong! But fixing that didn't solve my problems. Now I get "move must be piece ID plus board step"


💡📝H. G. Muller wrote on Sat, Oct 10, 2020 10:20 PM UTC in reply to Greg Strong from 09:45 PM:

That is weird. It also says:

And for general reference, here is the complete list of moves:

1. gosub GameEnd true;

So it thinks the GAME code in the Post-Game2 section is a move?! That surely explains why it complains about the move syntax. It baffles me how it could ever start to parse its own code as if it were a move. Perhaps Fergus has an idea how this can happen? I suspect the presence of this in the Initial-Moves section did some persisting damage to the entire preset.

It is midnight here now; if the problem still exists tomorrow I can look at it further.


Greg Strong wrote on Sat, Oct 10, 2020 10:48 PM UTC in reply to H. G. Muller from 10:20 PM:

I suspect the presence of this in the Initial-Moves section did some persisting damage to the entire preset.

Yes, this was my thought as well, but I downloaded the php file and found no traces of it...


🕸Fergus Duniho wrote on Sun, Oct 11, 2020 01:15 AM UTC in reply to H. G. Muller from Sat Oct 10 10:20 PM:

Perhaps Fergus has an idea how this can happen?

Since the "MOVE:" command is the only command that would add something to the moves list, I searched for it in betza.txt and found this code:

  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;

I haven't analyzed it, but I don't know what else would be responsible.


💡📝H. G. Muller wrote on Sun, Oct 11, 2020 07:49 AM UTC:

Are you sure you saved the code twice, after you moved the gosub GameEnd from the Initial-Moves section to Post-Game2? Very often changes become only effective after the second time. I have had to go through dozens of times through the sequence Play - Bug manifests itself - Menu - Edit - Fix the bug - Save - Menu - Play - Bug still manifests itself - Menu - Edit - (Inspect code, bugfix is already there) - Save - Menu - Play - Bug no longer manifests itself. If you saved only once, chances are that the preset still thinks the gosub is in the Initial-Moves section, even though the Edit function does no longer show it there. With Game Courier, what you see is not always what you get.


Greg Strong wrote on Sun, Oct 11, 2020 03:20 PM UTC:

I was aware of this problem and saved several times, but it still didn't work. I created new settings, just to be certain, and that worked. The Initial Moves section always appeared to be empty, but wasn't. Apparently, when you put something in there, you can never get rid of it. I overlooked it before, but the following was in the php code:

$default['movelist'] = <<<'NOW'
1. gosub GameEnd true;
NOW;
$default['movenum'] = <<<'NOW'
1
NOW;

So now I'll fix the php manually and clean up my extra settings file. Thanks for the help!


Greg Strong wrote on Sun, Oct 11, 2020 03:29 PM UTC in reply to H. G. Muller from 07:49 AM:

How do I make en passant work? I added an e to the pawn move for "fmW*fceF" but that doesn't seem to do it. Is that not right?


💡📝H. G. Muller wrote on Sun, Oct 11, 2020 05:15 PM UTC in reply to Greg Strong from 03:29 PM:

Yes, you did that right; it is supposed to work that way. But I had not implemented setting of e.p. rights by a W* move in the betza.txt include. (Which needs other code than that for setting the rights on a lame leap, which sets them on jumped-over squares rather than visited squares.) In fact I had not implemented the W* at all, yet. The Betza compiler encodes this special case by specifying a range of -1, but the interpreting GAME code should then of course recognize this special case, to recalculate it as the distance of the fromSqr to the board middle. I quickly added the code for that yesterday evening, when I saw you would need it.

I added the code for setting the e.p. squares now, and tested it in the preset you made.


Greg Strong wrote on Sun, Oct 11, 2020 07:21 PM UTC in reply to H. G. Muller from 05:15 PM:

Very nice! Almost perfect. I think my last problem is promotion. It only shows queen, rook, bishop, and knight as options, but I put "QRWEBN" in the Promotion Choice field.


Greg Strong wrote on Sun, Oct 11, 2020 07:24 PM UTC in reply to Greg Strong from 07:21 PM:

Ok, I found the issue. For some reason, it put "N n B b R r Q q e e w w" as the options (the E and W were both lower-case for some reason.)


💡📝H. G. Muller wrote on Sun, Oct 11, 2020 08:07 PM UTC in reply to Greg Strong from 07:24 PM:

Well, the JavaScript in the wizard page that flushes the GAME code uses this line for generating the promotion array:

        if(choice[i] != 3) psupply += ' ' + ids[i] + ' ' + ids[i].toLowerCase();

The array ids[] contains the piece IDs. It does not take them directly from the promotion string you typed; this just determines the content of the array choice, encoding what type of promotion this is (e.g. to captured pieces only). Only the second occurrence is forced to lower case, and if the IDs already where lower case, the first one stays that. Normally the Diagram takes the IDs as first letter of the name (when not explicitly given in the piece definition), capitalizing it. But in the Play-Test Applet you then in general change the name and the ID (and move). So the likely explanation is that you typed a lower case ID when altering ID / name and move for Wolf and Eagle.

I suppose I should just write ids[i].toUpperCase() for the first occurrence, to exclude this. Or perhaps already convert the ID to upper case in ids[] when you alter it.

I looked at the code in the preset, and I still see one issue: the castling partners do not seem to be defined correctly (e1 e1 e12 e12) instead of (a1 l1 a12 l12). I don't know how that could have happened. This game has castling, does it not? The Interactive Diagram made by Aurelian defines the King move as KisO3.


Greg Strong wrote on Sun, Oct 11, 2020 09:01 PM UTC in reply to H. G. Muller from 08:07 PM:Excellent ★★★★★

It says KisO4 in the list, which is correct, but I didn't update that one. I had guessed that it defaulted to that based on the board size. But I didn't put the king on the board either - it starts there (if that matters.)

I updated those values and now castling works correctly too.

This is VERY impressive. It is now possible to make presets for typical variants with no writing of GAME code at all. Thank you for making this!


💡📝H. G. Muller wrote on Mon, Oct 12, 2020 08:46 AM UTC in reply to Greg Strong from Sun Oct 11 09:01 PM:

The Play-Test Applet indeed adapts the default King move to the board width, by making the castling end as usual w.r.t. the corners. Identifying the castling partners is a bit tricky, though. Originally the Interactive Diagram allowed castling with corner pieces and Rooks (which in some variants start closer to the King). For the AI this was not acceptable, so I added code to scan the board to locate the piece that can castle, look how wide the rank is that it is on (the board could be irregular, or have holes, e.g. Omega Chess), and defines the extreme squares as 'corners'. If those squares are empty, it scans the rank towards the King to find a piece. Later I implemented the j modifier to explicitly shift the castling square inward (so the AI could also do Omega Chess, where the square behind the Rook is not empty).

In the Wizard Tutorial I state that if you are not interested in the FEN, you can just put one piece of every type you need on the board. I realize now that this is wrong: You need to put the someting at the edges on the King rank to get the correct castling partners. I guess I should alter the Diagram script to entirely rely on the j (and board holes, if any) for identifying the castling partners, irrespective of whether these are empty in the initial position. That makes the generated GAME code less dependent on the initial setup. The King would still have to be in the right place, though.

I am glad you like it. For variants with less-typical rules, such as the Jumping Chess, one still has to write GAME code. But often that can be limited to code to implement the non-standard rules. I try to make this as simple as possible, though. Confinement to board zones (at the pseudo-legal level) can now be enforced by just defining a single function for vetoing moves based on the square coordinates of those. I am not entirely happy with that yet, because it does not pass the location of any hopper mount. So it cannot be used to implement the Janggi rule that Cannons cannot jump over Cannons. In the Diagram hops are treated transparently, though: you don't have to indicate the mount when entering the move. As a consequence there can be an arbitrary number of them. Perhaps I should have the move generator remember what was the last piece hopped over, and also pass that to the user-supplied routine.

For larger flexibility I guess it would be good to allow a user-supplied callback for the move generator, so make it easy to call it for your own purposes. Like testing whether there exists a move that is mandatory (by whatever criteria you want).


💡📝H. G. Muller wrote on Mon, Oct 12, 2020 06:12 PM UTC:

It would be even nicer if instead of a button that shows you the GAME code so that you can copy-paste it, there would be a button 'Create Preset'. Which would send the HTML requests to the server (through AJAX calls) that are needed to open the preset edit page, and deposit the the code there as if the Save button was pressed. This should be technically possible, as the pages are on the same server.

Of course the user should then have to supply the name of the variant, and the name of the settings file first. But there could be text entries for those. The Wizard could in response display the link through which you can edit the created preset. Or perhaps open that preset in edit mode itself, in another browser window. The user would then only have to adapt the settings for the graphics (color, piece theme...).


Greg Strong wrote on Mon, Dec 14, 2020 10:16 PM UTC:

I need to make a rule-enforcing preset for Brouhaha. Does this support making GC presets with Brouhaha squares? I know there's a function (BadZone?) I can use to disallow moving to the border, but I would need to allow it in the case of a capture.


💡📝H. G. Muller wrote on Mon, Dec 14, 2020 11:10 PM UTC in reply to Greg Strong from 10:16 PM:

I have forgotten how exactly I implemented this, but there is an variable 'brouhaha' which is set to an empty array in the include code. I suppose that setting it would work, and that the Play-Test Applet generates the code to set it, when you created it with Brouhaha squares. (At the bottom of the piece table there is a button that allows you to black out squares rather than place pieces. You should do that first, and then later move a piece to the blacked-out square to make it a Brouhaha square.)

[Edit] I checked it out, and the GAME code in the betza.txt include file simply tests in HandleMove whether the origin square is in the defined 'brouhaha' set and is evacuated (i.e. not also a drop, like in a swap move). If so, it deletes the cell as part of move making. (Which happens before testing whether the move was fully legal.)

It doesn't remove the Brouhaha square during testing for full legality for the purpose of highlighting. In theory this could cause highlighting of moves with pieces that are pinned on Brouhaha squares. (E.g. if c0, d0 and e0 are Brouhaha squares, and your King is on c0, your Bishop on d0 and an enemy Rook on e0, moves with the Bishop would still be highlighted.) It also doesn't remove the Brouhaha square when the piece on it is locust-captured. The latter should be easy to fix, if the need ever arises.


Greg Strong wrote on Thu, Dec 17, 2020 07:28 PM UTC:

How can I make a King castle 3 squares short and 4 squares long? The l and r modifiers are relative to the player, so it seems I need the ability to specify a different betza for white and black.


💡📝H. G. Muller wrote on Thu, Dec 17, 2020 09:56 PM UTC in reply to Greg Strong from 07:28 PM:

The l and r modifiers are relative to the player, so it seems I need the ability to specify a different betza for white and black.

You can specify an extra parameter castleFlip=1 in the Diagram to swap the meaning of l and r on castlings.

I am not entirely happy with that; I guess a neater solution would be to apply the l <-> r swap on all of black's moves. And perhaps this should be applied automatically based on the specified symmetry (none, mirror, rotate), where mirror then should do it, and none / rotate not.


Greg Strong wrote on Thu, Dec 17, 2020 10:13 PM UTC in reply to H. G. Muller from 09:56 PM:

Varying the directions based on a symmetry setting is what ChessV does. They symmetries are called rotational, mirror, and none.

But this castleFlip option doesn't help for generating a Game Courier preset, right?


💡📝H. G. Muller wrote on Thu, Dec 17, 2020 11:10 PM UTC in reply to Greg Strong from 10:13 PM:

Indeed, there is no way to specify it in the Applet. Making it automatic would solve that. Except that there isn't really a way to specify 'rotate' symmetry either. But I suppose you could use 'none'.

The easiest way is probably to generate tables for a symmetric King, and then change one of the castling distances by editing the generated code. The tables get comments to indicate what piece they are for, and you will easily recognize that castling range in the King section. E.g. for O2 castling you will get something like

1  1  0  1     3 // king(84)
1  1  1  1     3
1  1  1  0     3
1  1  1 -1     3
1  1  0 -1     3
1  1 -1 -1     3
1  1 -1  0     3
1  1 -1  1     3
2 99  1  0    72
   1  2  0     9
2 99 -1  0    72
   1 -2  0     9

just change the -2 on the last line to -3 to get 3-step Q-side castling.


Greg Strong wrote on Thu, Dec 17, 2020 11:36 PM UTC in reply to H. G. Muller from 11:10 PM:

This is strange. I've put all the contents into the preset, and things mostly work, but a Bishop keeps disappearing. Whichever side to move's bishop disappears!

https://www.chessvariants.com/play/pbm/play.php?game%3DJanus+Kamil+Chess%26settings%3Dstandard


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 09:40 AM UTC in reply to Greg Strong from Thu Dec 17 11:36 PM:

This is weird indeed. But it already happens in the 'menu' page, and I am not sure any of the supplied GAME code (in particular the Pre-Game code) is already activated there. And since this is not a shuffle game the Pre-Game code should not do anything other than assigning to the parameters that later will define the behavior when vetting moves. It is also not caused by the movepiece.js script; the Bishop is already missing in the Page Source. And Game Courier itself is aware that the Bishop is missing, as it displays it as a 'captured piece'.

What happens when you comment out the betza.txt include? Or when you only put in the include, and leave out the variant-specific assignments? There is a lot of code in betza.txt, but it is almost all subroutine definitions, which should only be invoked from the Post-Move / Post-Game sections. And these should not be activated when it is just displaying the initial position on the menu page. (I doubt that even Pre-Move would be activated there.) The only code that executes on include is a few assignments, none affecting the board position.


Greg Strong wrote on Fri, Dec 18, 2020 02:50 PM UTC in reply to H. G. Muller from 09:40 AM:

Remove the include file and the problem persists. If I replace it and remove the rest of the pre-game code, it crashes "function P is not defined".

I think some game code is definitely being run even by the 'menu' page because it shows this warning:

NOTICE: The setup shown here has been modified from the original setup thanks to running code for this game. If this game randomizes the setup, then you may expect to see a different setup when you actually play the game.


100 comments displayed

Earlier Reverse Order LaterLatest

Permalink to the exact comments currently displayed.