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


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

Comments/Ratings for a Single Item

Later Reverse Order EarlierEarliest
The Fairychess Include File Tutorial. How to use the fairychess include file to program games for Game Courier.[All Comments] [Add Comment or Rating]
🕸📝Fergus Duniho wrote on Thu, Apr 11 01:02 AM UTC in reply to Daniel Zacharias from Wed Apr 10 11:51 PM:

I still don't get why the previous way wasn't working since I wasn't changing the pawn subroutine which seems to modify promotion options before the last rank.

The Pawn subroutines are only for actual moves, but nothing was being done to handle variable values of wprom or bprom for potential moves. The stalemated subroutine was supposed to provide a list of all legal moves, but it was omitting moves where someone declines promoting a Pawn. By having functions that dynamically calculate what a piece may promote to, it is now able to provide an accurate list of legal moves for games with variable promotion rules, such as Gross Chess has.

Anyway, this reveals another, but more minor, problem, which is that when a pawn gets to the promotion zone the text in the option selection box is large enough that the lines overlap slightly.

I increased the line-height and made some changes to the borders.


🕸📝Fergus Duniho wrote on Thu, Apr 11 12:33 AM UTC in reply to Fergus Duniho from Wed Apr 10 07:57 PM:

For Obento Chess, you might use functions like these:

def White_Pawn-Promote elem - rank #0 9 ((FP) (FP) (F));
def Black_Pawn-Promote elem rank #0 ((f) (fp) (fp));

That should be this:

def White_Pawn-Promote elem - rank #0 9 ((F P) (F P) (F));
def Black_Pawn-Promote elem rank #0 ((f) (f p) (f p));

Daniel Zacharias wrote on Wed, Apr 10 11:51 PM UTC in reply to Fergus Duniho from 07:57 PM:

Thank you, that does work better; although I still don't get why the previous way wasn't working since I wasn't changing the pawn subroutine which seems to modify promotion options before the last rank.

Anyway, this reveals another, but more minor, problem, which is that when a pawn gets to the promotion zone the text in the option selection box is large enough that the lines overlap slightly.


🕸📝Fergus Duniho wrote on Wed, Apr 10 07:57 PM UTC in reply to Daniel Zacharias from 01:28 PM:

In looking into this, I tested Gross Chess to see if it had the same problem, but before I could tell, I encountered another problem with it. I realized that for a game like Gross Chess it wouldn't do to use bprom and wprom as though they had static values. So I rewrote the fairychess include file and the Gross Chess code to support dynamic values for what a piece is allowed to promote to on a given space.

This makes use of some new functions that end with "-Promote". Here are the default functions for the Pawns:

def White_Pawn-Promote var wprom;
def Black_Pawn-Promote var bprom;

For backwards compatibility with the original way of handling promotions, these just return the value of wprom or bprom. And for additional backwards compatibility, the stalemated subroutine will use these functions only if the piece is not in the promotable array. So, to enable the use of these functions for providing dynamic values for what a piece can promote to, you should unset promotable or set it to an empty array. I added this line to Gross Chess after including the fairychess include file.

unset promotable;

Since the default functions return static values, they need to be rewritten for the particular game they are for. Here are the functions I wrote for Gross Chess:

def White_Pawn-Promote merge intersection var cap elem - rank #0 9 ((B N V W) (B N V W C R S) (B N V W C R S A M Q)) elem - rank #0 9 ((P) (P));
def Black_Pawn-Promote merge intersection var cap elem rank #0 ((b n v w c r s a m q) (b n v w c r s) (b n v w)) elem rank #0 (() (p) (p));

Since what a Pawn may promote to in Gross Chess depends upon the rank it is on, I used the rank value for black (or a value calculated from the rank value for white) as the index for a couple of arrays from which it extracted a particular value. For example, black can promote on ranks 0-2, as they are designated internally. So, this code will return the element of the array with the same index as the rank value:

elem rank #0 ((b n v w c r s a m q) (b n v w c r s) (b n v w))

Since white promotes on ranks 9-11, I subtracted 9 to get a value from 0 to 2 for any rank promotions are allowed on or a number that is out of range for any other rank. So, this works similarly:

elem - rank #0 9 ((B N V W) (B N V W C R S) (B N V W C R S A M Q))

Since the last rank for black is 0, and the last for white is 11, and 11-9 is 2, these list sets of promotion options in the reverse order from each other.

Since promotion options are limited to captured pieces, each function calculates the intersection of the value above with the captured pieces. This looks like this for black:

intersection var cap elem rank #0 ((b n v w c r s a m q) (b n v w c r s) (b n v w))

Finally, I get to the part that is relevant to Obento Chess. Whether it can promote to a Pawn as a way of declining promotion depends on the rank but not on what has been captured. So Pawns were not included in the main lists of promotion options. Instead, it merges the intersection calculated above with the value of another array element. Again, the specific array element is a function of the rank. Here is what it looks like for black:

elem rank #0 (() (p) (p))

Since declining promotion is not an option for black on rank 0, an empty array is provided for the element with an index of 0. This is not necessary for white, as the rank it cannot decline promotion on has a higher index.

elem - rank #0 9 ((P) (P))

For Obento Chess, you might use functions like these:

def White_Pawn-Promote elem - rank #0 9 ((FP) (FP) (F));
def Black_Pawn-Promote elem rank #0 ((f) (fp) (fp));

You could handle promotion for the other promotable pieces with similar functions for each specific piece.


Daniel Zacharias wrote on Wed, Apr 10 01:28 PM UTC in reply to Fergus Duniho from 12:56 PM:

I did copy from Gross chess. The descriptions should be fixed now


🕸📝Fergus Duniho wrote on Wed, Apr 10 12:56 PM UTC in reply to Daniel Zacharias from 03:56 AM:

Start by accurately writing the promotion rules in English. It looks like you copied the rules from Gross Chess even though Pawns in Obento Chess promote only to Flying Ox. I’ll check it out later when I’m on my desktop.


Daniel Zacharias wrote on Wed, Apr 10 03:56 AM UTC:

I'm having trouble with pawn promotion in this preset. I've set wprom and bprom and promotion does work, but it's not being optional like I expect. Instead it just auto promotes pawns as soon as they reach the promotion zone. As far as I can tell, there should be a promotion choice before the last rank even if there's only one item in wprom.


🕸📝Fergus Duniho wrote on Tue, Apr 9 04:41 PM UTC in reply to Daniel Zacharias from 03:16 PM:

That's now fixed. Thanks.


Daniel Zacharias wrote on Tue, Apr 9 03:16 PM UTC:

There's a small mistake in fairychess. Wizard-Desc says "The %s Wizard may move" which would result in duplicating the piece name if shown.


🕸📝Fergus Duniho wrote on Tue, Oct 17, 2023 01:44 AM UTC in reply to Daniel Zacharias from Mon Oct 16 10:52 PM:

It looks like you are misusing aliases. Aliases should not be set between names and labels. They should be set between names and codenames or between labels and notation. Look at the Piece Definitions and Piece Names sections, including the hidden details you need to click on to read.


Daniel Zacharias wrote on Mon, Oct 16, 2023 10:52 PM UTC:

I've been working on this game but something is wrong with the kings and I can't find the problem. Whenever I try to move a king I get an error like this.

There was no K on e1. The piece on e1 is a K.


🕸📝Fergus Duniho wrote on Thu, Feb 9, 2023 02:32 PM UTC in reply to Daniel Zacharias from 05:44 AM:

Does anything look amiss here?

   2 setconst T Tusker
   3 setconst t Tusker
   4 setconst J JumpingGeneral
   5 setconst j JumpingGeneral
   6 setconst M Minister
   7 setconst m Minister
   8 setconst H HighPriestess
   9 setconst h HighPriestess
  10 setconst E Elephant
  11 setconst e Elephant
  12 setconst Y WarMachine
  13 setconst y WarMachine
  14 setconst L BattleEngine
  15 setconst l BattleEngine
  16 setconst K King
  17 setconst k King
  18 setconst P White_Pawn
setconst p Black_Pawn
  19 setconst G Guard
  20 setconst g Guard
  21 setconst N Knight
  22 setconst n Knight

You're missing a semicolon after one line.


Daniel Zacharias wrote on Thu, Feb 9, 2023 05:44 AM UTC:

I'm trying to use the fairychess include file to enforce rules with this preset and it's giving an error I can't figure out.

The fn built-in function has not been given a valid function name or lambda function.

As well as I can tell, I have provided the proper functions for every piece.


Daniel Zacharias wrote on Thu, Jan 12, 2023 09:51 PM UTC in reply to Fergus Duniho from 05:55 PM:

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 Thu, Jan 12, 2023 05:55 PM UTC in reply to H. G. Muller from 08:42 AM:

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 Thu, Jan 12, 2023 08:42 AM 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 Wed, Jan 11, 2023 06:27 PM 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 Wed, Jan 11, 2023 02:49 AM 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 Wed, Jan 11, 2023 02:26 AM UTC in reply to Daniel Zacharias from 12:18 AM:

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 Wed, Jan 11, 2023 12:18 AM UTC:

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


🕸📝Fergus Duniho wrote on Tue, Jan 10, 2023 06:55 PM 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 Sat, Sep 24, 2022 10:17 PM UTC:

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


🕸📝Fergus Duniho wrote on Thu, Apr 7, 2022 02:25 AM 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 Wed, Mar 9, 2022 05:32 PM 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 Fri, Jun 26, 2020 09:39 PM 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.


25 comments displayed

Later Reverse Order EarlierEarliest

Permalink to the exact comments currently displayed.