Comments/Ratings for a Single Item
So far, I have programmed the square-table rendering method to handle moves by entering the destination first. It works like this. When you click or tap on the destination first, it highlights the pieces that can move there. If you then click or tap on one of those pieces, it will then complete the move. But no matter what order you begin in, it will put the notation in the correct order. So, this doesn't change what notation can be entered through clicking or tapping.
Indeed, this is how it should normally work. Notation should be unique. But if this mechanism is used as a kludge to indicate a move has a possible side effect, you could leave the squares swapped in the notation to indicate that side effect.
There is already a simple solution available, which is to give the castling move to the Rook when the King moves one space. It's best to not allow players to enter reverse notation with mouse clicks, because it would rarely have any use, and it would more frequently just mess up regular moves. Also bear in mind that the JavaScript used to make moves is a simple client-side mechanism that cannot connect with the server-side code used for enforcing rules except by submitting a form. It does not have the rules programmed into it, and it has to operate on its own, its only data being a list of legal moves and a representation of the board.
Ah yes, you are right! In fact this is what Jocly uses, in Wildebeest Chess. That is for free castling, but it would be equally suitable for fast castling.
Now that you mention it, that's the game I did it that way for with Game Courier.
I have made a few tweaks to how clicking on an empty space first works. When there is only one legal move to that space, it highlights that space, fills it in as a move by the piece that can move there, and let's you complete the move by clicking on the same space again. To cancel the move, click on the piece rather than on the space. If multiple pieces can move to the same space, it highlights each of them, and you have to complete the move by clicking on one of them. You can cancel the move by clicking on any empty space.
I removed thespaces, since I couldn't find any use of it. Unlike spaces, which returned the keys to the $space array, it returned the $space array itself. In place of it, I made $space a readable and writable system variable.
I removed the answered operator and made $answered a readable and writable system variable. This variable gets set by ask and askpromote when they are answered. It is useful for writing code that stops asking the same question again and again after it has already been answered. I am going to update the White_Pawn and Black_Pawn functions to use it, so that I don't have to resort to the kludge of inserting "P-dest" or "p-dest" when a Pawn doesn't promote.
I just documented the baseurl operator. It returns the baseurl of the the Game Courier script.
I added and just documented the capturedpieces operator. This calculates and returns an associative array of the currently captured pieces. This replaces the use of $capturedpieces as a readable system variable with the system operator. It may still be overwritten with setsystem though, and it may also be accessed as a variable with a dollar sign before it. But this will return a value only if it has already been set, since Game Courier does not set the $capturedpieces variable until it has run through all the moves in a game.
Fergus,
In the fairy chess file you write for the charging knight :
def Black_Charging_Knight cond > rank #0 rank #1 (checkleap #0 #1 1 2) (checkleap #0 #1 1 1 or checkleap #0 #1);
Is it the case that you missed the directions (1 0) for the final case?
def Black_Charging_Knight cond > rank #0 rank #1 (checkleap #0 #1 1 2) (checkleap #0 #1 1 1 or checkleap #0 #1 1 0);
I modified cond to work properly, and I updated the section on recursive functions. Since cond mimics the operation of ?: in PHP, I had written it using ?:. I rewrote it using if and else, and it is now able to work in recursive functions, because it no longer evaluates code that it shouldn't evaluate.
There are two ways of getting the value of a variable. One is to prepend the variable name with the # symbol. This works by replacing the #var_name with its value during preprocessing. This is useful for commands that do not provide any evaluation of expressions. It can be used on any line, regardless of the command.
The other way works only in expressions, and it is to precede the variable name with the keyword var. In some instances, it doesn't matter which you use. But in function definitions it does. Consider these lines of code:
def test1 join "a" #v; def test2 join "b" var v; print fn test1; print fn test2; set v x; def test3 join "c" #v; print fn test1; print fn test2; print fn test3; set v y; print fn test1; print fn test2; print fn test3;
Here is their output:
a#v b a#v bx cx a#v by cx
As you can tell from examining the output, the method of prepending a variable name with # works only when a function is defined, and it will insert the current value of that variable into the function definition without enabling the function to use the most recent value of the variable on subsequent function calls. But the var keyword will always retrieve the current value of the variable everytime the function is called. For this reason, it is important to use the var keyword in function definitions whenever there is any chance that its value may change. The preprocessing method of retrieving variable values may be used in a function definition only for variables that have already been set and will not change.
The same should apply to prepending constant names with @ or prepending system variables with $. You're probably okay prepending a constant name with @, because its value is not supposed to change. Some system variables change regularly, and some do not. For those that do change, it is better to use the system keyword to retrieve their value in function definitions.
I cannot find the definition of where here, as it is used in the definition of griffin and aanca.
Edit I have found it now. Sorry for the spam :(!
I fixed a bug in the pop command. When it pops off an array element from an array, it is supposed to remove it from the array, not just copy it to a variable. I fixed it so that it will modify the array when it pops off a value.
I'm making a rule-enforcing preset for Shatranj Kamil X and I'm almost done but for one minor annoyance I don't understand.
In addition to pawn promotion, the Ferz also automatically promotes to a W on the last rank. So, in Post-Move I added:
if and == $moved F == rank $dest 9:
add W $dest;
endif;
This works fine, except that after the promotion, it shows the Ferz in the "captured pieces" which isn't really accurate. So I added a line:
if and == $moved F == rank $dest 9:
add W $dest;
setelem capturedpieces F dec elem F capturedpieces;
endif;
I think this should work but it does not... Any thoughts appreciated.
I changed subroutines to copy arguments as my variables instead of local variables. This removes the ability of child subroutines to see the arguments passed to parent subroutines. I made this change for the following reasons:
- my scope variables are accessed more quickly than local scope variables.
I never made use of the ability that treating arguments as local variables conferred.- This ability would be useless in recursive subroutines, since a recursively called subroutine will have the same parameters as its parent subroutine.
- Using this ability makes code harder to follow. It is usually keeps things clearer when you pass as arguments the specific values that a subroutine needs.
[Edit: While three of the reasons still apply, it turns out that I did previously make use of the ability of child functions to see arguments passed to parent subroutines. This broke some code, and I switched it back to how it was.]
The capturedpieces array is generated automatically after all moves have been played through. So, it is not available for you to tinker with in the code. Instead, you have to construct the entire capturedpieces array. When you have already created it in your code, it doesn't get automatically generated from your final game position.
Ok. After reading this comment I was wondering how it was that promoting a pawn in Chess doesn't make the pawn a "captured piece", but it turns out that it actually does (and I just never noticed). So I guess I do not need to worry about this since the behavior of promoting the ferz is consistent with how pawn promotion works.
Here's a result I find surprising. First the code I ran:
def countdown fn countdown dec #0 onlyif #0;
def coontduwn fn coontduwn dec #a onlyif #a =a;
sub countdown cnt:
if #cnt:
return sub countdown dec #cnt;
else:
return #0;
endif;
endsub;
stopwatch reset;
print fn countdown 10000;
stopwatch;
stopwatch reset;
print fn coontduwn 10000;
stopwatch;
stopwatch reset;
gosub countdown 1000;
stopwatch;
stopwatch reset;
set a 10000;
do while #a:
dec a;
loop;
print #a;
stopwatch;
Then the results:
0
Elapsed time: 0.12341594696045 seconds
0
Elapsed time: 0.14718699455261 seconds
Elapsed time: 0.50130391120911 seconds
0
Elapsed time: 0.17237901687622 seconds
The first two tests show that function recursion is slightly faster with native subroutine variables instead of with user variables. That's not surprising, because there is more overhead in using user variables.
It's also not surprising that function recursion is faster than subroutine recursion. Though I do wonder why it's by such a high margin. I had to reduce the countdown by a factor of 10 just to test subroutine recursion speed, and it still took more time than function recursion. While using a user variable may be a factor, it is even slower than the coontduwn function that uses user variables.
What is surprising is the last result, which shows that a do loop was slower than function recursion. The countdown is the same, but the loop took more time.
The do while loop calls the same PHP function as function recursion does each time it iterates the loop, because it uses it to evaluate the expression after while. Plus, it has a bit more overhead for operating the looping mechanism. So, that may explain why it's slower.
I just added this code:
stopwatch reset;
foreach a fn range 0 10000:
next;
stopwatch;
And it got the fastest result:
Elapsed time: 0.039952039718628 seconds
It saved a lot of time by never trying to evaluate a as an expression.
Since the subroutine had a wrong variable name in it, I did it again and got slightly better results. First, the corrected code:
sub countdown cnt:
if #cnt:
return sub countdown dec #cnt;
else:
return #cnt;
endif;
endsub;
stopwatch reset;
gosub countdown 1000;
stopwatch;
Then the result:
Elapsed time: 0.50052809715271 seconds
Trying again with var instead of #:
sub countdown cnt:
if var cnt:
return sub countdown dec var cnt;
else:
return var cnt;
endif;
endsub;
stopwatch reset;
gosub countdown 1000;
stopwatch;
Elapsed time: 0.51695919036865 seconds
This slowed it down slightly. The curious thing is that #cnt
calls evalvar() first, and this then calls getuservar(), whereas var cnt
calls getuservar() directly. Based on this, I was expecting it to be faster. Factors that could explain the opposite result are #cnt
is handled while parsing the line, while var cnt
is handled by evaluating an expression, and var cnt
is a longer string than #cnt
, which means reading the line takes longer.
Trying var cnt
with a function:
def countdown fn countdown dec var a onlyif var a =a;
stopwatch reset;
print fn countdown 10000;
stopwatch;
Elapsed time: 0.20279908180237 seconds
This also slowed things down, and it was by a lot more compared to the earlier result, which was 0.14718699455261. In the function for evaluating polish notation expressions, evaluation of prepended variables is handled before operators, but the extra line parsing shouldn't make as much of a difference, because the function definition is executed only once.
I added a section on Control Flow in Functions.
I have some problems using sort. I have an array sqrs with 3 squares in it, and want to know what the middle square is. I had expected this could be done by
set sqrs sort #sqrs; set middle elem 1 #sqrs;
This does not work, however. If I do printr sqrs; before and after the sort, the order of the elements is altered. But the order of the keys (0, 1, 2) is altered too, so that each element is still associated with the same key. And elem apparently retrieves the elements by key, so elem 1 #sqrs is still the same as it was without the sort.
Array ( [1] => a1 [0] => e1 [2] => h1 )
How can I retreive the e1 from the above array, if I do not know its key, but only that it is the second element?
I have now implemented shuffling for the Applet-generated rule-enforcing GAME code. Because this involved some subroutines that could be of general use, I placed the code in a separate include file, which can also be included in hand-crafted presets, through:
include /membergraphics/MSply-test-applet-for-chess-variants/shuffle.txt;
To make the variant into one with a shuffled initial position, one then only has to specify (in the Pre-Game section) an array of what pieces have to be shuffled, and call the master shuffling routine. E.g.
set shuffleset (B N Q); gosub ShuffleSetup;
would randomly shuffle all Bishops, Knights and Queens. Black would normally be shuffled the same way as white, unless you specify a shuffle for black separately:
set shuffleset (B N Q); set blackshuffle (b n q); gosub ShuffleSetup;
would independently shuffle the white and black pieces.
There are some ways to restrict the shuffle, for instance for the purpose of ensuring the Bishops stay on opposite shades. For that purpose there are some extra arrays you could specify. In particular, piece types mentioned in the array 'shaded' will be kept on the shade they were orignally on. In that case those pieces should not be mentioned in the shuffleset. E.g.
set shuffleset (N R Q K); set shaded (B); gosub ShuffleSetup;
If black is to be shuffled independently, it must have its own 'blackshaded' for this purpose.
An even more severe restriction one can impose is that certain piece types must remain positioned (left-right) symmetrically. This is useful if you don't want to shuffle the King-side and Queen-side wings independently, but preserve the overall symmetry. E.g. to optionally cause swapping of the Bishops with King and Queen you can do:
set shuffleset (K Q); set symmetrized (B); gosub ShuffleSetup;
In orthodox chess this would then result in one of the back ranks RNBKQBNR, RNBQKBNR, RNKBBQNR or RNQBBKNR. Currently this mode of shuffling cannot be combined with shade-preserving shuffles; you should not define 'shaded' and 'symmetrized' both. The blackshuffle would use an equivalent array 'blacksym'.
There finally is a possibility to restrict the shuffle in such a way that one piece will end up between two others. For this an array 'centralize' has to be defined, with two or three piece types, the first of which must occur only once, and there must be exactly two of the others in the setup. That first-mentioned piece will then always end up between the two others. This is useful in Chess960, where we could do
set shuffleset (N R Q K); set shaded (B); set centralize (K R); gosub ShuffleSetup;
So far for the simple applications. It is also possible to specify a complex sequence of shuffles. This is mainly intended for interpreting Pre-Game code generated by the Play-Test Applet. But it is not so complex that it is impossible to specify such a shuffle by hand. The idea is to provide an array of arrays 'shufflespecs', where each shuffle is specified by three consecutive elements of the 'outermost' array. These three elements are then used as the shuffleset, symmetrized and shaded settings for that shuffle step. If some of those are not needed, they should be set to 0. E.g.
set shufflespecs ( (A C) // shuffleset 1 (N) // symmetrized 1 0 // shaded 1 (absent) (Q A C) // shuffleset 2 0 // symmetrized 2 (absent) 0 // shaded 2 (absent) (N) // shuffleset 3 (B) // symmetrized 3 0 // shuffleset 3 (absent) 0 // make symmetric );
The final 0 requests that black's position should be the mirror image of white's. If you want to shuffle black independently, you must omit that 0. But then you would have to specify all the shuffle steps in the array also with black pieces, or black would not be shuffled at all. In the example (starting from the setup of Capablanca Chess) you would force swapping of the B and N on both wings, or leave them unaffected, to decide whether super-pieces go onto the b- and i-file or the c- and h-file. The second shuffle would then permute all three super-pieces over the assigned locations. Finally, the Knight and Bishop might be swapped on both wings, or not at all.
Since it looks like you're the first person to use sort, I modified it to use sort() instead of natsort(), and I also modified it to read all remaining arguments as an array if the first argument is not an array. I also added the following functions:
- asort
- Sorts an associative array, preserving the keys. Takes only one argument, which should be an array.
- natsort
- Sorts an associative array in a natural order, preserving the keys. Same as sort used to be. Takes only one argument, which should be an array.
- isort
- Sorts an array in a natural, case-insensitive manner. Will sort remaining arguments if first one is not an array.
- values
- Returns the values of an array. Mainly useful for placing the values of an associative array into a numeric array.
Thanks. To be sure: for sorting square coordinates it would be best to use isort, so that a2 is sorted before a10? With the old sort I was finally able to work around the problem by using pop to access the elements; this did pop the elements in the reverse order as printr printed them. I was a bit surprised anyway that the array I tried to sort was treated as an associative array. It was created as a merge of two arrays that were built by repeated push.
To prevent mishaps like this (people not ticking "Do not include moves in code". I stressed this should be done in the tutorial, but failed to mention it in the instructions on the Appler page itself), I could of course make the move parser detect the condition of an empty origin and the mentioned piece already on the destination, and point out the user should still do this in the error message. And adapt the text on the Applet page. But it would be nice if it was not possible to make this mistake at all.
Can we get a GAME-code command or variable that would enable the program to 'tick' this option under program control? Presumably Game Courier uses some PHP variable as a boolean to indicate whether it should execute the input moves, and all that would be needed is allow access to that as a system variable. Then I could set that option in the Pre-Game code.
25 comments displayed
Permalink to the exact comments currently displayed.
Something like that would make it easier to do fission moves in Fusion Chess. However, what you suggest for one-space castling would also require a difference in notation between the two moves.