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 Latest Comments Only For Pages | Games | Rated Pages | Rated Games | Subjects of Discussion ]

Comments/Ratings for a Single Item

LatestLater Reverse Order EarlierEarliest
Play-test applet for chess variants. Applet you can play your own variant against.[All Comments] [Add Comment or Rating]
🕸Fergus Duniho wrote on Fri, Jan 1, 2021 08:17 PM EST in reply to H. G. Muller from 02:52 PM:

It seems resign doesn't have the new behavior in this context: it terminates execution of the current subroutine, but not of the GAME code. It happily continues with the caller.

Would you set up a sample preset that exhibits the bug you're describing?


💡📝H. G. Muller wrote on Fri, Jan 1, 2021 02:52 PM EST in reply to Greg Strong from 01:37 PM:

My bad, I wrote elsif: instead of elseif: somewhere. And I didn't test, as I figured that 'resign' would only work when you are actually playing a game. But it seems I can actually type 'resign' in Play mode. But this produces very strange behavior. I have this code in ParseMove now:

  if != 2 count #sqrs:                               // must give 2 squares
print . count= count #sqrs;
print thismove;
    if == resign thismove:
print ok;
      resign;
    elseif == drawn thismove:
      drawn;
    endif;
    die "board step does not mention two squares";
  endif;


When I enter 'resign' it prints 'count=1', 'resign' and 'ok' as expected. Then, however, it survives the 'die', and continues until it later dies with the complaint that 'resign' isn't even pseudo-legal for a Pawn.

[Edit] It seems resign doesn't have the new behavior in this context: it terminates execution of the current subroutine, but not of the GAME code. It happily continues with the caller.


Greg Strong wrote on Fri, Jan 1, 2021 01:37 PM EST in reply to H. G. Muller from 05:34 AM:

It still didn't work, but now there's a new message:

Syntax Error on line 24

Misplaced endsub.


💡📝H. G. Muller wrote on Fri, Jan 1, 2021 05:34 AM EST in reply to Greg Strong from Sat Dec 26 2020 04:48 PM:

Yes, you should probably allow "drawn" too. Players will discuss a draw in comments and then one will enter the drawn command.

This should be fixed now, without any impact on the preset's efficiency: I only do the test for resign and drawn at the point where it otherwise would have given the error message about the move syntax.


Greg Strong wrote on Sat, Dec 26, 2020 04:48 PM EST in reply to H. G. Muller from 03:43 PM:

Yes, you should probably allow "drawn" too. Players will discuss a draw in comments and then one will enter the drawn command.


💡📝H. G. Muller wrote on Sat, Dec 26, 2020 03:43 PM EST in reply to Greg Strong from 10:51 AM:

Ah, OK. I guess ticking the checkbox to not include moves in the GAME code also applies to 'resign'. I will let my move parser recognize it.

Should I expect similar problems for draw offers?


Greg Strong wrote on Sat, Dec 26, 2020 10:51 AM EST in reply to H. G. Muller from 03:45 AM:

The error is "board step does not mention two squares". Isn't that message generated by your code? I think even when commands are banned, that one is still allowed.


💡📝H. G. Muller wrote on Sat, Dec 26, 2020 03:45 AM EST in reply to Greg Strong from Fri Dec 25 05:29 PM:

Here's a small problem: the generated GC presets don't recognize or allow the command "resign"

Isn't that by definition a Game Courier / GAME code problem? I would think that resigning should always be possible in any game in any situation. It also seems that 'resign' should be considered a move, rather than a command; it is one of the possible things a player can (always) do when it is his turn.

The include file bans commands. I don't want the preset to allow commands in general, just to be able to process 'resign'.


Greg Strong wrote on Fri, Dec 25, 2020 05:29 PM EST:

Here's a small problem: the generated GC presets don't recognize or allow the command "resign"


Greg Strong wrote on Sun, Dec 20, 2020 12:06 PM EST in reply to H. G. Muller from 03:52 AM:

Thanks! Updated Janus Kamil presets have been published. I plan to, over time, update older presets with this technology. Hopefully I'll be able to streamline the process so it doesn't take too long.


💡📝H. G. Muller wrote on Sun, Dec 20, 2020 03:52 AM EST in reply to Greg Strong from Sat Dec 19 07:19 PM:

I think the issue is probably that some of the abstract pieces are smaller than the square size.

Indeed, the Abstract images have variable size. The movepiece.js script copies their URL from cell content to background style, and apparently the default mode for background is to tile, starting in the upper-left corner.

This was easy to fix: in the loop that does the image copy I now also set the background-repeat and background-position styles to 'no repeat' and 'center center'. You would probably have to append a ?nocache=true parameter to the movepiece.js URL to make sure the new version is used.


Greg Strong wrote on Sat, Dec 19, 2020 07:19 PM EST in reply to H. G. Muller from 01:45 AM:

It seems there's an issue with the optional javascript. It works with alfaerie, but when I change it to abstract it only appears OK until I move a piece.

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

I think the issue is probably that some of the abstract pieces are smaller than the square size.


Greg Strong wrote on Sat, Dec 19, 2020 10:11 AM EST in reply to H. G. Muller from 01:45 AM:

You defined too many rank labels.

Thank you!  Must have made this from an earlier preset.  Sorry for the trouble!


💡📝H. G. Muller wrote on Sat, Dec 19, 2020 01:45 AM EST:

You defined too many rank labels.

Automatic detection of the castling partners should now also work again in the Applet. It is invoked every time you press the 'Start Position' button. It does assume white and black have their castling partners on the same files.


Greg Strong wrote on Fri, Dec 18, 2020 03:17 PM EST in reply to Greg Strong from 02:41 PM:

Hmmm... So I found where this is handled in the PHP code and it looks correct:

       case "lastfile": // Returns numeric index of last file
           array_push ($output,  count($file)-1);
           break;
       case "lastrank": // Returns numeric index of last rank
           array_push ($output,  count($rank)-1);
           break;

So I'm not sure why this is happening.


Greg Strong wrote on Fri, Dec 18, 2020 02:41 PM EST in reply to H. G. Muller from 02:38 PM:

Ok, so lastrank is returning the last file and not the last rank.


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 02:38 PM EST in reply to Greg Strong from 01:55 PM:

It seems I can modify & test the preset as well, even though it is not mine, through Edit, Test, Play. I tried

print lastrank; die;

as first thing in the Pre-Game code. This prints 11...


Greg Strong wrote on Fri, Dec 18, 2020 01:55 PM EST in reply to H. G. Muller from 01:42 PM:

I don't know how to test that. I tried:

tell lastrank; tell var lastrank; tell #lastrank;

None of them work...


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 01:42 PM EST in reply to Greg Strong from 12:37 PM:

I don't understand that. The * range is encoded as -1 in the tables, which is then dynamically replaced by the actual range in the move generator:

    switch #rng:
      case -1:
        set rng cond < 0 #dy rank #cursqr - lastrank rank #cursqr;
        set rng - >> lastrank 1 #rng;
        set rng max 1 #rng;

In infix notation this reads

rng = (dy > 0 ? RANK(cursqr) : LASTRANK - RANK(cursqr)); // start rank (flipped for black)
rng = (LASTRANK >> 1) - rng; // distance from board half.
rng = max(1, rng); // minimally 1

On a 10-rank board MAXRANK = 9, so LASTRANK>>1 should be 4. That should give you 4 steps from the back rank (rank 0 for white and 9 for black). From their starting rank it should be 3 steps. I don't see anything wrong here. In particular, I don't see how white and black Pawns could behave differently.

Can the GAME-code variable 'lastrank' actually return the number of board files (minus 1)?


Greg Strong wrote on Fri, Dec 18, 2020 12:37 PM EST in reply to H. G. Muller from 12:12 PM:

Ok, I remade it and the problem is gone and I have castling working the way a I want. Unfortunately, I have a new problem. The unmoved pawn can move up to four spaces. So, I used the Omega Pawn which should allow it to move up to the center. I'm sure this used to work, but now the white pawn can move one square too far and the black pawn ends one square too soon. (In the generated GC code, not sure if this affects the diagram/AI.)


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 12:12 PM EST in reply to Greg Strong from 12:00 PM:

It seems there is a bug in the Applet for generating this 'partners' array. I am pretty sure it worked before. But I had a regression at some point in the Diagram script, when I apparently uploaded a 'fix' applied to an older version, and this probably lost the code for identifying castling partners.Castling doesn't even work in the Diagram itself. (Not obvious, as for legacy reasons it always allows the user to castle with a Rook. But the AI cannot do it anymore.)

The only way to remove a piece is to capture it (and only pseudo-legal moves can capture!).


Greg Strong wrote on Fri, Dec 18, 2020 12:00 PM EST:

Oh, ok. Glad you were able to figure it out! I'm going to try to generate the game with the designer again...

How do you remove the King that starts on the board automatically? I don't see any obvious way to remove a piece that has been placed. (General question - not needed for this game.)


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 11:53 AM EST in reply to Greg Strong from 11:40 AM:

Note I edited my posting before your latest one!

P.S. I think we had problems before removing a section, when you accidentally had misplaced some of the function calls. This seems a general problem of the GC preset editor. This might explain why 'removing' the Post-Game section has no effect.


Greg Strong wrote on Fri, Dec 18, 2020 11:40 AM EST in reply to H. G. Muller from 11:33 AM:

Removing post-game does not fix it. Also removing post-move also does not fix it. This is a real head-scratcher. I don't understand at all...


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 11:33 AM EST:

Ah, I think I got it. In the generated Pre-Game code this is fishy:

set partners (f1 d1 f10 d10); // 'rook' locations for castling

This mentions the Queen as possible castling partner, and apparently the move generator doesn't explicitly test for the occupant of the King target, as it assumes the King could not 'see' the Rook when that square is occupied in the first place. (Note that Fischer castling is not supported.) The move take-back during legality testing for highlighting purposes (which does run in the initial position!) apparently counts on the King target being empty, and doesn't put the victim back.

I am not sure how the Applet could have generated this partner set. The values are strange; they seem to apply to the 8x8 board, in absence of any pieces. (By default it is the most-distant piece.)

Another thing that is fishy is that the King table also contains vertical castlings. You must have forgotten to put the s modifier on the O3. This doesn't really hurt, as the piece in front of the King is not in the 'partner' set. It just wastes some time.


Greg Strong wrote on Fri, Dec 18, 2020 09:50 AM EST in reply to H. G. Muller from 04: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.


💡📝H. G. Muller wrote on Fri, Dec 18, 2020 04:40 AM EST in reply to Greg Strong from Thu Dec 17 06: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 Thu, Dec 17, 2020 06:36 PM EST in reply to H. G. Muller from 06: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 Thu, Dec 17, 2020 06:10 PM EST in reply to Greg Strong from 05: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 05:13 PM EST in reply to H. G. Muller from 04: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 04:56 PM EST in reply to Greg Strong from 02: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 02:28 PM EST:

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 Mon, Dec 14, 2020 06:10 PM EST in reply to Greg Strong from 05: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 Mon, Dec 14, 2020 05:16 PM EST:

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, Oct 12, 2020 02:12 PM EDT:

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


💡📝H. G. Muller wrote on Mon, Oct 12, 2020 04:46 AM EDT in reply to Greg Strong from Sun Oct 11 05: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).


Greg Strong wrote on Sun, Oct 11, 2020 05:01 PM EDT in reply to H. G. Muller from 04: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 Sun, Oct 11, 2020 04:07 PM EDT in reply to Greg Strong from 03: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 03:24 PM EDT in reply to Greg Strong from 03: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.)


Greg Strong wrote on Sun, Oct 11, 2020 03:21 PM EDT in reply to H. G. Muller from 01: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.


💡📝H. G. Muller wrote on Sun, Oct 11, 2020 01:15 PM EDT in reply to Greg Strong from 11:29 AM:

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 11:29 AM EDT in reply to H. G. Muller from 03: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?


Greg Strong wrote on Sun, Oct 11, 2020 11:20 AM EDT:

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!


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

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.


🕸Fergus Duniho wrote on Sat, Oct 10, 2020 09:15 PM EDT in reply to H. G. Muller from 06: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.


Greg Strong wrote on Sat, Oct 10, 2020 06:48 PM EDT in reply to H. G. Muller from 06: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...


💡📝H. G. Muller wrote on Sat, Oct 10, 2020 06:20 PM EDT in reply to Greg Strong from 05: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 05:45 PM EDT in reply to H. G. Muller from 05: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 05:28 PM EDT in reply to Greg Strong from 02: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 02:01 PM EDT:

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:

/play/pbm/play.php?game%3DI-Chess%26settings%3Dstandard


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

Tick "Do not include moves in code".

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


🕸Fergus Duniho wrote on Wed, Aug 19, 2020 04:27 PM EDT in reply to A. M. DeWitt from 04: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."


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

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

Yangsi


💡📝H. G. Muller wrote on Tue, Aug 18, 2020 05:00 PM EDT in reply to A. M. DeWitt from 04: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 Tue, Aug 18, 2020 04:56 PM EDT in reply to H. G. Muller from 10:01 AM:

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 10:01 AM EDT:

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


A. M. DeWitt wrote on Tue, Aug 18, 2020 09:56 AM EDT in reply to H. G. Muller from 05: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 05:08 AM EDT in reply to A. M. DeWitt from Mon Aug 17 08:40 PM:

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 Mon, Aug 17, 2020 08:40 PM EDT:

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 Thu, Aug 6, 2020 08:10 AM EDT:

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.

 


💡📝H. G. Muller wrote on Mon, Aug 3, 2020 05:22 AM EDT in reply to Greg Strong from Sun Aug 2 07: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.


Greg Strong wrote on Sun, Aug 2, 2020 07:33 PM EDT in reply to H. G. Muller from 04: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 Sun, Aug 2, 2020 04:53 PM EDT:

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 04:28 PM EDT:

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?


Carlos Cetina wrote on Thu, Jul 30, 2020 09:29 PM EDT:

OK, don't worry and thanks!


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

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 Thu, Jul 30, 2020 04:41 PM EDT:

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 Wed, Jul 29, 2020 03:28 PM EDT in reply to Carlos Cetina from 10:40 AM:

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 Wed, Jul 29, 2020 10:40 AM EDT:

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 Mon, Jul 27, 2020 05:21 PM EDT:

dummy 4


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

dummy 3


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

dummy 2


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

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 Sat, Jul 25, 2020 05:21 PM EDT:

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


Carlos Cetina wrote on Sat, Jul 25, 2020 03:06 PM EDT:

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.


Greg Strong wrote on Fri, Jul 24, 2020 03:05 PM EDT in reply to H. G. Muller from 02: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?


💡📝H. G. Muller wrote on Fri, Jul 24, 2020 02:29 PM EDT in reply to Greg Strong from 01: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 01:50 PM EDT in reply to H. G. Muller from 01:31 PM:

Where can I download the latest set of SVGs?


💡📝H. G. Muller wrote on Fri, Jul 24, 2020 01:31 PM EDT in reply to Carlos Cetina from 01: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.


Carlos Cetina wrote on Fri, Jul 24, 2020 01:11 PM EDT:

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

Greg Strong wrote on Fri, Jul 24, 2020 11:54 AM EDT in reply to H. G. Muller from 02: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.


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

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.


Carlos Cetina wrote on Fri, Jul 24, 2020 01:21 AM EDT:

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 Thu, Jul 23, 2020 01:59 PM EDT:

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


🕸Fergus Duniho wrote on Thu, Jul 23, 2020 01:42 PM EDT in reply to H. G. Muller from 01: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 01:28 PM EDT:

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 12:29 PM EDT in reply to H. G. Muller from 11:43 AM:

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 11:43 AM EDT:

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;

 


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

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;

 


🕸Fergus Duniho wrote on Wed, Jul 22, 2020 10:35 PM EDT in reply to H. G. Muller from 05: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 Wed, Jul 22, 2020 05:34 PM EDT in reply to Fergus Duniho from 09:41 AM:

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 Wed, Jul 22, 2020 09:41 AM EDT in reply to H. G. Muller from 05: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.


🕸Fergus Duniho wrote on Wed, Jul 22, 2020 09:28 AM EDT in reply to H. G. Muller from 01: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.


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

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; ?)


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

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;


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 02:21 PM EDT in reply to H. G. Muller from 01: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 Tue, Jul 21, 2020 01:32 PM EDT in reply to Fergus Duniho from 11:53 AM:

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 11:53 AM EDT:

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


🕸Fergus Duniho wrote on Tue, Jul 21, 2020 11:23 AM EDT in reply to Greg Strong from Mon Jul 20 11:14 PM:

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.


💡📝H. G. Muller wrote on Tue, Jul 21, 2020 08:55 AM EDT:

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.


100 comments displayed

LatestLater Reverse Order EarlierEarliest

Permalink to the exact comments currently displayed.