The site has moved to a new server, and there are now some issues to fix. Please report anything needing fixing with a comment to the homepage.



The Chess Variant Pages




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

Comments/Ratings for a Single Item

Later Reverse Order EarlierEarliest
The Fairychess Include File Tutorial. How to use the fairychess include file to program games for Game Courier.[All Comments] [Add Comment or Rating]
Daniel Zacharias wrote on 2023-01-12 UTC

There was some delay in fixing betza.txt, because it is not in the includes directory, and I didn't see the bug report on it until my computer was off

That's my fault I suppose. I should have mentioned it together with the other problems.


Fergus Duniho wrote on 2023-01-12 UTC

Very nice that you can simplify your stalemate routine in the fairychess include file

It was more extensive than one routine, and it wasn't about simplifying it. As my previous comment indicated, this was about removing the cause of error in that routine and others with similar code. The problem was that using two separate variables for storing the legal moves had allowed bugs to creep into existing code.

but please don't do it in such a way that it breaks presets of others through changing the underlying behaviour of GAME code or Game Courier.

I kept on top of what needed to be fixed, and I fixed everything in a timely manner. There was some delay in fixing betza.txt, because it is not in the includes directory, and I didn't see the bug report on it until my computer was off, and I was in bed with my Likebook Mars. Now that you're an editor, I suggest that you move betza.txt to the /includes/ directory and replace the other ones with stubs that just include it from the includes directory.

So if you want an array that contains the legal moves as text rather than coordinates, and also contains special moves, just give it a new name, and use it by that name in the user code

What I wanted was for the $legalmoves array to contain all the legal moves, because various stalemated subroutines were using setlegal to build a list of legal moves and then checking whether there were any legal moves by checking the count of $legalmoves with a line like this:

return cond count system legalmoves false true;

The bug I described earlier was caused by splitting the legal moves between two variables. The $extralegal array was a kludge I created for the sake of storing some legal moves as strings while storing other legal moves as coordinate pairs. However, I was combining them into a new array called $legalList for use with forms and JavaScript, and this array listed all legal moves as strings. Creating another array would not have helped with anything.


H. G. Muller wrote on 2023-01-12 UTC

@Fergus: Very nice that you can simplify your stalemate routine in the fairychess include file, but please don't do it in such a way that it breaks presets of others through changing the underlying behaviour of GAME code or Game Courier. If you do not maintain backward compatibility at all times, you are bound to break stuff.

So if you want an array that contains the legal moves as text rather than coordinates, and also contains special moves, just give it a new name, and use it by that name in the user code you want to simplify, so that existing presets that use the method you want to deprecate continue to function.


Fergus Duniho wrote on 2023-01-11 UTC

Because GAME Code was storing legal moves in two separate variables, and I wasn't always keeping this in mind, the stalemated subroutine in the fairychess include file was returning the wrong result for positions like this one:

It was claiming this was checkmate when the check could be prevented by capturing the Queen with a Pawn or blocking with one on g1. This was because the Pawn moves, which included a promotion, were being stored in $extralegal instead of in $legalmoves, which stored legal moves only as coordinate pairs, and the stalemated subroutine, as well as other similar subroutines, checked only the value of $legalmoves. To keep things simpler, I abolished the $extralegal variable, and I stored all legal moves in $legalmoves as strings using notation, and not as arrays of coordinates. With this change made, I was able to slim down the findmates subroutine to this:

// Finds each mating move in current position.
// Parameters:
// side: which side is moving
sub findmates side:
    local enemyking king mates moves mv;

    if match #side 1 white White first:
        set king #Kpos;
        set enemyking #kpos;
    else:
        set king #kpos;
        set enemyking #Kpos;
    endif;
    set mates ();
    ban none;
    setsystem maxmove 0;
    store main;
    setsystem legalmoves ();
    if not sub stalemated #king:
        set lglmvs $legalmoves;
        foreach move #lglmvs:
            set moves explode chr 59 #move;
            foreach mv #moves:
                set mv trim #mv;
                eval "MOVE: {#mv}";
            next;
            if sub checked #enemyking:
                setsystem legalmoves ();
                if sub stalemated #enemyking:
                    push mates #move;
                endif;
            endif;
            restore main;
        next;
    endif;
    setsystem legalmoves #mates;
endsub;

I did notice and correct one problem after this. It was recording some moves as belonging to the @ piece, which is the piece symbol used for empty spaces. This was because it was running the function for converting to notation as soon as setlegal was called, which happened to come before restoring the position. To correct for this, I had it get the piece type from the destination space if the origin space was empty, and if both were empty to not include the piece type. In the future, it would help to call setlegal only after restoring the position or to explicitly spell out the move if it will be anything out of the ordinary.


Fergus Duniho wrote on 2023-01-11 UTC

I have now written a subroutine that can solve mate-in-one problems for games using the checked and stalemated subroutine in the fairychess include file. When you compose a mate-in-one problem and click on Solve, it will tell you whether it has found a single solution to your problem and what it is. If it has, it will be the only legal move displayed. After making the move, you can click on Compose to enter the solution into your composition. Here is the subroutine:

// Finds each mating move in current position.
// Parameters:
// side: which side is moving
sub findmates side:
    local enemyking extramates king mates moves mv;

    setsystem showoutput true;
    if match #side 1 white White first:
        set king #Kpos;
        set enemyking #kpos;
    else:
        set king #kpos;
        set enemyking #Kpos;
    endif;
    set mates ();
    set extramates ();
    ban none;
    setsystem maxmove 0;
    store main;
    setsystem legalmoves ();
    if not sub stalemated #king:
        set lglmvs $legalmoves;
        foreach move #lglmvs:
            move #move.0 #move.1;
            if sub checked #enemyking:
                setsystem legalmoves ();
                if sub stalemated #enemyking:
                    push mates #move;
                endif;
            endif;
            restore main;
        next;
        set extmvs ();
        if isarray $extralegal:
            set extmvs unique $extralegal;
        endif;
        foreach move #extmvs:
            set moves explode chr 59 #move;
            foreach mv #moves:
                set mv trim #mv;
                eval "MOVE: {#mv}";
            next;
            if sub checked #enemyking:
                setsystem legalmoves ();
                if sub stalemated #enemyking:
                    push extramates #move;
                endif;
            endif;
            restore main;
        next;
    endif;
    setsystem legalmoves #mates;
    setsystem extralegal #extramates;
endsub;

This works by trying all legal moves. For each move, it first tests whether it checks the enemy King, and if it does, it additionally checks if it leaves the opponent with no legal moves. When it's finished, it writes its solutions to the variables that will be used to create the $legalList array, which will be used to display legal moves and populate the Moves field with possible values to enter with it.

Since the $legalList variable is not populated until after the GAME Code program has finished running, this sets $legalmoves and $extralegal separately. The $legalmoves array lists legal moves as coordinate pairs, and the $extralegal array lists them as notation, which is helpful when a move includes more than just a single move from one space to another.

One of the challenges in writing this was figuring out how to execute a move written as notation. When I initially tried it, it wouldn't allow it. What I eventually did was set $maxmoves to zero and turn off all bans. Since this subroutine is run at the very end of the GAME Code program, this doesn't hurt anything. This let me execute the move with the eval command.


Fergus Duniho wrote on 2023-01-11 UTC

Would the fairychess include file work with hexagonal boards, or might there be difficulties with that?

The main difficulty is that the piece definitions in the include file are designed for boards with square spaces. If you wrote new piece definitions for hexagonal boards, it may work for hexagonal boards.


Daniel Zacharias wrote on 2023-01-11 UTC

Would the fairychess include file work with hexagonal boards, or might there be difficulties with that?


Fergus Duniho wrote on 2023-01-10 UTC

I just modified the stalemated subroutine to list each Pawn promotion as a separate legal move. This will affect how Pawn promotions are handled. Instead of loading another page with an image of each piece, it will pop up a requester asking you which move you want to make. To accommodate this, the promotion move identifies the space by its coordinate and not by the keyword dest.

To make use of this for promotable pieces besides Pawns, you need to set the value of promotable to a list of your promotable pieces. If you don't, your code should simply work as it has previously worked before, still going to another page to ask what to promote the piece to.

I have done this for the sake of getting a complete list of legal moves for the purpose of using it with code for finding the solutions to mate-in-one problems. In time, I hope to do mate-in-two problems as well, but I have to start with what is simpler.

For now, the stalemated subroutine does not check whether each promotion is separately legal. This could matter if you had Korean Cannons in your game, because this piece captures by hopping over another piece but cannot hop over another Korean Cannon. In that case, what you promoted to could affect whether a promotion would put your King in check. But there is no possibility of this making a difference in Chess and most Chess variants, in which any possible promotion is equally legal. To avoid complication, the simpler scenario is assumed.

Here is the new subroutine:

// Goes through all possible moves, putting all legal moves into the array $legalmoves
// Returns false if any legal moves are found, and returns true if none are found.

sub stalemated kingpos:
    store;
    local cspaces friend friends from piece to movetype np prom;

    set movetype MOVE;

    if hasupper space #kingpos:
        // Array of pieces on same side
        set friends lambda (onlyupper);
        // Indicates whether a space is free to move to
        set free lambda (haslower #0 or not hasupper #0);
        set pzone lambda (not onboard where #0 0 var pzs);
        set cspaces var wcastle;
        set prom var wprom;
    else:
        set friends lambda (onlylower);
        set free lambda (hasupper #0 or not haslower #0);
        set pzone lambda (not onboard where #0 0 neg var pzs);
        set cspaces var bcastle;
        set prom var bprom;
    endif;

    // While the royal piece is called the King in these comments,
    // it may be any piece. These variables determine what the royal piece is.
    set royal space var kingpos;

    store;

 // Can any piece legally move?
    for (from piece) fn #friends:
        for to fn join const alias #piece "-Range" #from:
            if fn const alias #piece #from #to and fn #free alias space #to and onboard #to:
                move #from #to;
                if not sub checked cond == #from #kingpos #to #kingpos:
                    if fn #pzone #to and match #piece #promotable:
                        for np var prom:
                            setlegal "{#piece} {#from}-{#to}; {#np}-{#to}";
                        next;
                    else:
                        setlegal #from #to;
                    endif;
                endif;
            endif;
            restore;
        next;
    next;

    // Castling moves are handled separately
    if > count var cspaces 0:
        for to var cspaces:
            if sub castlepos #kingpos #to:
                setlegal #kingpos #to;
            endif;
        next;
    endif;

    setsystem autorules sub describe_rules;

    // All done. Set $legalmoves and return;
    return cond count system legalmoves false true;
endsub;

Jean-Louis Cazaux wrote on 2022-09-24 UTC

Would it be possible to add a Wildebeest (=Knight+Camel) to this fairychess? Thank you


Fergus Duniho wrote on 2022-04-07 UTC

I am currently in the middle of revising this tutorial. I have added a lot of new and updated content already, and the original material follows the revised text. I expect to continue it tomorrow.


Fergus Duniho wrote on 2022-03-09 UTC

Based on how I decided to handle the King in Eurasian Chess, I made some changes to the Chinese_General code. Here is the original Chinese_General function:

def Chinese_General checkride #0 #1 1 0
and == Chinese_General const alias cond empty #0 capture space #1
or checkleap #0 #1 0 1 and flag #1;

And here is the new one:

def Chinese_General 
== distance #0 #1 1
or == var movetype CHECK
and checkride #0 #1 1 0
and flag #1;

Both functions begin by checking whether the destination space is flagged, since the code flags every space within a palace. This keeps the piece from moving out of the palace, though it does allow a move from one palace to the other, which is what allows one general to threaten the other with check.

The main difference is how it handles this threat. It now uses the CHECK movetype instead of checking the identity of the other piece. The checked subroutine sets a local copy of movetype to CHECK. So, when movetype is CHECK, that means the function is being called from within the checked subroutine.

Another difference is that it only uses checkride, and it does not use checkleap. Instead of using checkleap, the final thing it checks is the distance of the move, and it checks that only if it has not been called from the checked subroutine.

I also changed the Chinese_General-Range function. It used to be this:

def Chinese_General-Range merge leaps #0 1 0 (var kpos var Kpos);

And now it is this:

def Chinese_General-Range leaps #0 1 0;

The reason for this is that -Range functions are called only by the stalemated subroutine for checking possible legal moves, and they are never called by the checked subroutine. Since a General can never legally move to the space occupied by the other General, there is no need to include the space of the opponent's General in the spaces a General may legally move. Its ability to move there is of concern only when checking for checking threats on a space a General might move to.

I tested multiple games of Chinese Chess without any problem occurring, and I made moves to specifically test that Generals were not allowed to oppose each other, that they couldn't move outside the Palace, and that they couldn't move two spaces within the palace. So, the code described above appears to be working.


Fergus Duniho wrote on 2020-06-26 UTC

I just moved up and rewrote the Actual vs Potential Moves section. I also revised the section called "A Real Example from Chess", which now follows it.


Greg Strong wrote on 2020-04-11 UTC

Excellent.  Thanks!


Fergus Duniho wrote on 2020-04-11 UTC

I just went with the other solution, which was to remove the $constants array from the current game logs for Opulent Chess.


Fergus Duniho wrote on 2020-04-11 UTC

Okay, I have done that. One more thing you need to do is change setconst to resetconst, at least temporarily. This is because constants get stored in game logs, and ongoing games will still use the old constant values if you use setconst instead of resetconst.


Greg Strong wrote on 2020-04-11 UTC

Ok, thanks.  I'm all set now.  You can update the fairychess include file.


Fergus Duniho wrote on 2020-04-11 UTC

It looks like you haven't set the constants for your Pawns.


Greg Strong wrote on 2020-04-11 UTC

I've updated this preset but it no longer works at all:

https://www.chessvariants.com/play/pbm/play.php?game=Opulent+Chess&settings=AbstractNew

It's not finding the -Range function for something, but the debug information is almost useless to me.  At a guess, maybe it is because I am trying to alias Knight to the Knight_Wazir and Knight has other meanings.  Just a guess.


Aurelian Florea wrote on 2020-04-10 UTC

I, too have mode the modifications and things are in order. Thanks!


Fergus Duniho wrote on 2020-04-10 UTC

I have now updated the documentation.


Fergus Duniho wrote on 2020-04-09 UTC

Using the fairychess-test include file, I updated Chess, Grand Chess, Gross Chess, and Chinese Chess to assign constants to the actual function and subroutine names instead of to aliases. They still make use of aliases for these names, but it is now only for display purposes. I am going to postpone copying the changes to the official fairychess include file to give Greg some time to update Opulent Chess without breaking it in the meantime. I haven't changed the documentation yet, but here is what you can do.

  1. Include fairychess-test instead of fairychess.
  2. Assign the constants to the actual function or subroutine names instead of the aliases.
  3. Add the Pawn alias for White_Pawn and Black_Pawn. (The main benefit of the change is that you can now do this.)
  4. Replace the if-elseif-else block for checking the legality of moves in each Post-Move section with the following code:
set codename const alias $moved;
if sub #codename $origin $dest and issub #codename:
elseif fn #codename $origin $dest and isfunc #codename and not issub #codename:
else:
set name alias #codename;
set errmsg list "You may not move your" #name "from" $origin "to" join $dest ".<BR>";
set desc join #codename "-Desc";
set errmsg str_replace "_" " " join #errmsg str_replace "%s" #name var #desc;
die #errmsg;
endif;

Once I know Opulent Chess is updated, I will copy fairychess-test to fairychess and switch back to including fairychess in my games. Then I'll notify Greg, who can do the same. I'm not going to worry about breaking Apothecary Chess, because that's still a work in progress anyway, but Aurelian should be doing the same things for his games too. This is just a quick how-to. I will update the documentation later.


Fergus Duniho wrote on 2020-04-09 UTC

After thinking about it, I think it makes more sense to assign constants to the names used in the code than it does to assign them to aliases. The alias can be calculated after the real name is returned by const. This allows the same alias to be used for a piece with different functions or subroutines for each side, such as Pawn as an alias for both White_Pawn and Black_Pawn. The way it is currently coded is suited only for using different aliases for different versions of the same piece definition, such as Minister and Elephant for Chinese_Elephant. But this is a bad example, because I have separate functions for the Elephant on each side anyway. So, I think there is more call for using one alias for multiple piece defintions than for using one piece definition with multiple aliases. I will update code and documentation tomorrow.


Aurelian Florea wrote on 2020-04-08 UTC

Ok, I'll take a look tomorrow. Thanks!...


Fergus Duniho wrote on 2020-04-08 UTC

This is because you copied old code that was still buggy. When I made a fork and copied in the new code from Chess, it worked fine. The new code is described in detail on this page in the Aliases section.


Aurelian Florea wrote on 2020-04-08 UTC

The 4 initial moves. The ones that the usual king does not have.


25 comments displayed

Later Reverse Order EarlierEarliest

Permalink to the exact comments currently displayed.