Comments/Ratings for a Single Item
This guide now describes the following new commands: setflag, unsetflag, copyflag add, move, replace if, else, elseif, endif, verify The verify command was already available, but it has now been greatly expanded. I created some of these commands for use with Crazyhouse, and I created others because of their similarity to other commands I was creating. In particular, the new Crazyhouse preset tracks Pawns with flags, uses verify to check the flag of a captured piece, then uses add to change it to a Pawn if it used to be one. Although I didn't use them, I also figured out how to implement nesting if, if-else, and if-elseif-else statements. I haven't thoroughly tested them out yet, but I expect they should work.
Is it possible to create a 'Stratego'-like game with the following characteristics? - each player can see his own pieces but not his opponents - players are able to choose the placement of their pieces before starting
Is it possible to create a 'Stratego'-like game with the following characteristics? - each player can see his own pieces but not his opponents - players are able to choose the placement of their pieces before starting
In preparation for a British Chess preset, I have added some new features to Game Courier that are now documented here. These are the path function and the foreach-next loop. The path function returns an array of all steps from one space to another. The foreach-next loop iterates through all the elements of an array. Although I could do it, I don't plan to add additional types of looping, since I don't want to provide the ability to create infinite loops. Foreach should be sufficient for any looping needs any preset has. Also, I am deprecating how endif currently works. In the future, endif will automatically close off all elseifs within the scope of the current if, which it will also close. There will no longer be any need to use numbers or the all keyword with endif. I could make the switch right away if everyone wrote endifs the same way I do, but just in case anyone has used endif arguments for shortcuts that close off multiple ifs, not just multiple elseifs and a single if, I am allowing time for transition before the old way of using endif breaks down. To make the transition, replace any use of 'endif all' or 'endif #' with 'endifs' and make sure that each 'endifs' statement closes off only one 'if' statement. The 'endifs' command works in the same way that 'endif' eventually will.
I've changed how next works since last night. It no longer uses any arguments. It just updates whatever loop it is for and loops back if it hasn't reached the end of the array yet. I have added the for command. It works much the same as the foreach command, but it uses a different syntax, and it uses an array expression instead of an array name. If you had in mind something like 'for x = 1 to 8', you would write it as 'for x range 1 8'. I have added the sub, return, and gosub commands for using subroutines. The sub and return commands mark the beginning and end of a subroutine. The gosub command goes to a subroutine. To prevent the possibility of infinite loops, the gosub command cannot be used from within a subroutine.
I have written a comprehensive postauto1 and postauto2 code (with perhaps a few bugs) which covers the 16 possibilities for Chess With Different Armies. (All there is to change in each preset is the title in 'game', the initial setup in 'code' and two arrays for possible promotions in 'pregame'.) Would it be possible to refer to a common postauto1 entry and a common postauto2 entry, instead of having to maintain 16 identical postauto1 entries and 16 identical postauto2 entries? It would also be useful when there are several presets for a same game.
After creating user defined functions, I discovered that my Polish Notation calculator wouldn't let recursive functions work. So I came up with some replacements for cond, called unless and onlyif. These work sort of like cond but with only two arguments instead of three. The expression 'cond x y z' is supposed to be equivalent to 'x ? y : z' but it evaluates both y and z, making it unsuitable for recursion. It ends up creating an infinite loop when used for recursion. Unlike previous functions in the PNC, unless and onlyif can break out of it, allowing recursion loops to be exited. I won't describe them in detail here, because I already did in the documentation. After creating these new functions, I realized the same principle could be applied to logical operators. So I updated and, or, nand, and nor to use either one or two arguments. When only one argument is available, these operators will stop evaluation of the expression when the truth value of the whole expression can be known from one value. For example, I can now write code like this: def Q checkride origin dest 1 1 or checkride origin dest 1 0; This function would evaluate the Rook moves before the Bishop moves, and if the Queen moved like a Rook, it would return true without bothering to check whether it moved like a Bishop. So, finally, logical operators can be used for flow control in expressions. They can also be used for exiting from recursive functions.
I've now brought together the new features I've been developing to write a new Chess preset in a new way. Most of the code is in an include file and can be viewed here: /play/pbm/includes/chess.txt The code makes use of user-defined functions and subroutines. I am currently using this new preset for the Chess preset with Abstract pieces. I will begin using it for the others after I have tested it more thoroughly.
I've debugged the code in the include file for Chess, and I've also made it more generalized. I've included a castle subroutine that can make castling much easier to implement, and I've generated arrays of which pieces a Pawn may promote to out of the array of piece keys, which is generated from the FEN code. I am now using this new version of the Chess enforcement code for the Alfaerie JPG Chess preset as well as for the Abstract Table preset. /play/pbm/includes/chess.txt With the improvements I've recently made to GAME Code, it may now have the computing power to spot checkmate, but it will still take someone to figure out how to do it. I have a general of how to go about it. First, check if the King is in check. If it is, then loop through the King's possible moves, checking if any are legal. If none are legal, identify the checking pieces. If there is more than one checking piece, it is checkmate. Otherwise, check if any piece can legally capture the checking piece. If it can't be captured, check if any piece can legally move to block the check.
I have been busy improving GAME Code this week. Here are some of the latest improvements. Instead of using explode to split a line of code into strings of non-whitespace, I have written some parsing functions. One parsing function checks whether a line of code is a move, returning each item in a separate argument. If it's not a move, a second parsing function is used. This function parses out quoted strings, arrays, and non-whitespace strings. Here's how it works. It goes through each character of a line. It normally skips over whitespace. When it finds a double quotation mark immediately after whitespace, it copies everything until the next one as a single string. When it find a left parenthesis, it copies everything until the next right parenthesis, then recursively calls the parsing function on this. This generates an array. Otherwise, it copies as a single argument whatever text falls between whitespace. Also, it does additional preprocessing only on unquoted nonarrays. So if you want to use 'origin', 'dest', or 'moved' as strings rather than as special variables, you can quote them to use the strings. This is required if you want to use setglobal to set the value of one of these variables. I've added target and check operators to the Polish notation calculator. These work sort of like switch and case. They are used for speeding up the search for pieces that might be checking the King. Details are in the documentation. The fn operator now accepts nameless functions as arrays, which allows the creation of nameless lambda functions.
Over the weekend, I added the ability to use parentheses for expressing arrays. For example, this will now set an array of all white pieces in Chess: set white (K Q R B N P); Arrays are parsed recursively, so that nested parentheses will yield multi-dimensional arrays. When lines are evaluated by the Polish notation calculator, the contents of arrays are not automatically evaluated. For example set a * (+ 4 5) (- 9 5) should not evaluate to 36. But arrays may be conditionally evaluated by the logical operators and, or, nor, nand, and cond, and also be eval and fn. For example, set a * eval (+4 5) eval (-9 5) would yield 36. When given arrays as arguments, the binary logical operators will evaluate the first array first, then evaluate the second only if its value is needed to determine the value of the expression. For example, set a or (== 4 4) (!= 4 7) will evaluate only (== 4 4) The cond operator is the equivalent of ?: in C or PHP. It will evaluate an expression, and if it is true, it will evaluate the array following the expression, but if it is false, it will evaluate the second array following the expression. For example, cond != 6 6 (== 7 9) (<= 9 7) will evaluate (<= 9 7) but not (== 7 9) Last night, there was still a problem with using parentheses with recursive functions. That problem is now fixed. It is now possible to write a recursive function like this one for finding a number's factorial: def fac cond equal #0 1 1 (* #0 fn fac dec #0); Note that #0 is now the first placeholder instead of #1. I changed all the placeholders in chess.txt to accomodate this. This particular function has been tested and shown to work. It first checks whether the value passed to it is equal to 1, with 'equal #0 1'. If it is 1, it returns 1. Otherwise, it evaluates the array (* #0 fn fac dec #0), which multiples the value passed to the function, #0, with a recursive function call of one less than the value passed, dec #0.
Control structure commands that introduce a body of code can now be ended with a colon instead of a semicolon. These include if, elseif, else, do, for, foreach, switch, case, and default. I did this, because I think it looks better. In other languages that end lines with semicolons, these commands normally do not end with semicolons. Semicolons are still allowed for backwards compatibility with old code. The program code is now broken up with a specialized parsing function instead of exploding on semicolons. The foreach command is now an alias for the for command. Both commands work much like foreach from Perl or PHP. By using an array instead of a string for naming the for variable, you can get both the key and the value of each array member. For example, the following code lists all the spaces of the board, assuming the 64-times limit of echo isn't exceeded: foreach (key val) spaces: echo #key #val; next;
I am currently developing code for checking whether a player is checkmated or stalemated. It is not all working right yet, but if anyone wants to take a look at it, you will find it here: /play/pbm/includes/checkmate.txt I am using it with a new version of the Chess preset: /play/pbm/play.php?game=Chess&settings=checkmate This preset is only for testing and should not be used for ongoing games. Also, so that single and double quotation marks can be entered in the form fields for GAME Code, I have switched to storing strings in settings files with the heredoc format. This will not affect current presets unless they are resaved.
This comment, which I accidently posted on the wrong page a couple days ago, belongs on this page: I added the following new functions to the Polish notation calculator today: checkmaxsteps checknsteps checkpath These all handle movement that may go along a winding, unobstructed path, such as the movement of some pieces in Jetan. The checkmaxsteps function checks whether a piece may move from one space to another within a specified number of steps from one adjacent space to another. The checknsteps function checks whether a piece may move from one space to another in exactly a specified number of steps. Both of these functions allow movement through the origin space and repeated movement through the same space. They are both handled by a recursive function that goes through all possible paths until it finds one that works. The checkpath function checks whether a piece can move from one space to another by following a specific path, given as a set of paired directions. To illustrate how these work, here are two alternate ways to handle the Squire from Holywar: Barring possible mistakes, here is the long way that uses 16 checkpath functions for all possible paths: checkpath origin dest (1 0 1 1) or checkpath origin dest (1 1 1 0) or checkpath origin dest (1 0 1 -1) or checkpath origin dest (1 -1 1 0) or checkpath origin dest (-1 0 -1 1) or checkpath origin dest (-1 1 -1 0) or checkpath origin dest (-1 0 -1 -1) or checkpath origin dest (-1 -1 -1 0) or checkpath origin dest (0 1 1 1) or checkpath origin dest (1 1 0 -1) or checkpath origin dest (0 1 -1 1) or checkpath origin dest (-1 1 0 -1) or checkpath origin dest (0 -1 1 1) or checkpath origin dest (1 1 0 1) or checkpath origin dest (0 -1 1 -1) or checkpath origin dest (1 -1 0 1); Here is the short way that uses checknsteps in combination with checkleap: checkleap origin dest 1 2 and checknsteps origin dest 2; The checkleap function makes sure that the piece is going to a space a Squire could move to, then the checknsteps function makes sure it can get there in exactly two steps.
I have now modified the Alfaerie-JPG version of the Chess preset to use the code I've been working on for identifying check, checkmate, and stalemate. For each of these, it will put an appropriate message above the board, and for checkmate and stalemate, it will automatically update the status. I have also created the commands won, drawn, and lost for updating the status. The <B>won</B> command declares the current player to be the winner, <B>lost</B> declares the current player's opponent to be the winner, and <B>drawn</B> declares the game drawn. Don't confuse this with draw, which is a command for drawing cards. The lost command is an alias for resign, to be used when a player has already lost without resigning.
Oh yes, this is a great addition for so many reasons... Thanks! I'm especially pleased that pieces can now be represented by the correct letters for the game, without requiring a proliferation of piece sets. The ability to use the plus-sign in the name for shogi pieces is a very nice touch, too. I would like to suggest something, though. Right now, when moving a piece you can either enter the piece type ('P e2-e4') or not ('e2-e4'). I always do the former, because it makes it easier for me to keep track of games. Some opponenets do, some do not. I would be nice if, when entering a simple single-move, like 'e2-e4', it would automatically add the 'P' or 'p'. Thanks for the consideration. You have done a lot of good work on improving the Game code recently! I need to get to work on presets using the new features for wildebeest chess, lions & unicorns chess, and others.
I am attempting to change the name of my recent submission from 'Chieftain Chess with Preset' to 'Chieftain Chess', now that a preset page is available. I am also trying to indicate it is multi-player, with 1-4 players per side, for a total of 2-8 players. I seem to be having 2 problems. First, when I try to do the name change, I get this error message: Error performing query: Duplicate entry 'MSchieftainchess' for key 1 Second, is there a way to indicate a range in the number of players per side? I will put in '1-4' and '2-8', but what comes up is '1' and '2'. Any information or assistance will be greatly appreciated.
cond
within a function defined with def
causes invalid results in all cases, not just in cases where the function is recursive.The doc says that the 'reverse' operator takes an array and returns a new array with the elements reversed. But whenever I try to use it, it's as if it doesn't even exist in the language. In other words, what I end up with on the stack is not a reversed array but the word 'reverse' and a copy of the array I'm trying to reverse!
Help?
Larry, You are correct about the user-defined placeholders beginning at #0. I looked at some of my own include files written in GAME Code, and I was routinely using #0 as a placeholder with the def command. I have updated the guide to correct this.
Larry, I believe I have code in which the cond operator is working properly. For example, it is used in /play/pbm/includes/ivorytower.txt and the code for Storm the Ivory Tower works. It is used in the code for Clodhoppers (C/c), for example, and in test moves I've made, only legal moves have been accepted. Cond is a useful operator for pieces with divergent moves, such as, for example, pieces that move one way and capture another way, or pieces that move differently depending on their position. Cond can be used to check which rules of movement apply to a piece's move and then to apply the correct rule of movement. To illustrate, I'll give an analysis of its use in this line of code: def C cond cond empty #0 (not capture) (empty #1) (checkride #0 #1 1 1 or checkride #0 #1 0 1) (checkhop #0 #1 1 1 or checkhop #0 #1 0 1) and fn legaldir #0 #1; Remember that evaluation begins at the end and proceeds backwards. First, it checks whether the move was made in a legal direction. This is a requirement for any move in this game, and it is not part of the cond statement. It just stops the move if it is in a direction no arrow points. This code has two cond statements. The inner cond statement, which sets the condition for the outer cond statement, checks whether the move was not a capture. I think I expressed it as a cond statement to allow the function to be used for hypothetical moves that get evaluated during the stalemate function. In a normal move, the origin space (#0) will not be empty, and it will just need to evaluate (empty #1) to tell whether the move was to an empty space (and hence not a capture). In a hypothetical move, the origin space might be empty, though my memory is hazy on this, and I can't pinpoint why this would be right now. Anyway, this inner cond returns true if the move was not a capture and false if it was. So, if it was not a capture, it evaluates whether it was a legal riding move, and if it was a capture, it evaluates whether it was a legal hopping move, because Clodhoppers capture by hopping but otherwise move by riding.
Hello Fergus,
I appreciate your help with this! I'll admit that the initial learning curve has been steep for me. It's been so long since I did anything with Polish notation that I'm basically starting over (but I'm learning to appreciate it again, too).
I will study your new example of the cond operator more closely. For right now, here is some code that I think will illustrate the problem I'm having with the reverse operator. And it may either be a bug or just my misunderstanding of how things should work.
set arrayvar ray a1 1 1; set reversedarray reverse #arrayvar; dump; exit;
What I was expecting to see in the dump was reversedarray having the same contents as arrayvar, but in reversed order. Instead, I get this:
[reversedarray] => Array ( [0] => Array ( [0] => b2 [1] => c3 [2] => d4 [3] => e5 [4] => f6 [5] => g7 [6] => h8 ) [1] => reverse )
I have another question, and I'm sorry if this is a trivial one.
I would like to use the shift
command, but it doesn't seem to accept an array, and I need to be able to give it a list of coordinates from an array. Is there any operator that will empty an array and put all of its contents back onto the stack? In other words, is there something that does the inverse of array
?
set stringvar list var arrayvar; shift #stringvar;
I hope I am not being a pain yet... Unfortunately, I still can't get things to work the way we expect. I think the point of failure is with the list operator (or how I'm using it). This snippet should reproduce the problem. It ends with strcoords
being empty--not an empty array, just nothing.
set arraycoords ray 0 1; set strcoords list var arraycoords; dump; shift #strcoords;
It still doesn't look like shift will take an array or a 'list'-ed string, but please don't worry about changing that urgently. I've had enough time to think about what I wanted to use shift for, and I think I can do it with a custom, recursive subroutine instead. If you think it needs 'fixing,' go ahead and fix it, but there is no need to do so on my account.
Thanks again for Game Courier. I haven't seen anything quite like it anywhere else on the Web.
'Thanks again for Game Courier. I haven't seen anything quite like it anywhere else on the Web.' - from the previous post I will second that. Thank you, Fergus. Also note that game Courier has some 600+ presets, found here and at the CVwiki. To the best of my knowledge, no one else matches that, and certainly no one else matches that in abstract [strategy] games. Is there any other site that comes close? Thanks also to those who have done presets. Jeremy Good, in particular, has some 100 presets to his credit. This does bring up the question of how we rate these things. The recognized games haven't been getting much recognition lately. Should we attempt to recognize more, and if so, just how? Game ratings can be somewhat subjective. I think we can see some need, with 600 games, to rate them in some manner. Even if it's something short, like: 'Excellent concept game. Unplayable.' The question is: should we try? Is it worth it, given likely results such as 'animated' discussions? George Duke expanded the criteria for 'the next chess', and we can look at possibilities, and compare them. We could rate games by first dividing them into categories, and rate games by types, rather than just seeing all games as in the 'variant' category. So you wouldn't have games like Pocket Mutation [my pick for best '00s CV] and Rococo going up against each other for the one initial spot of 'recognized'. Heh, what are the different categories of CVs?
Larry, It's not a problem with the shift command. It is a systemic problem with preprocessing. As the word suggests, preprocessing should be done before any other processing of a line of code, but I had combined preprocessing with line parsing. The undesired result of this is that it treats your list of arguments as a single argument. I will work on separating preprocessing from parsing, so that things work as they should.
set rowe join 'shift ' list ray a1 1 0; echo #rowe; eval #rowe;The first line creates the line of code for shifting pieces and copies it to the variable rowe. The second line shows you what that line of code looks like. The third line executes the line of code.
I have now modified the eval command to evaluate and execute as a command any Polish notation expression given to it. If given an array, it treats it as multiple lines of code and executes all of it. Here is an example of its use: eval join 'shift ' list ray a1 1 0; Since quotation marks will mess up code entered as a move, here is an alternate version someone could type as a move: eval join join shift ws list ray a1 1 0; ws (also whitespace) is a new unary operator that returns a space character. This will also work: eval join join shift chr 32 list ray a1 1 0;
I have finished programming some commands for restricting user input. I have rewritten the ban command to handle types of movement, I have introduced the allow command, and I have added a system variable for restricting the length of a full move. These changes do not affect any games that do not enforce rules. They are merely provided as options to help developers program better rule enforcement. Here is how they would generally be used together for Chess:
setsystem maxmove 2; ban commands allmoves; allow moves 1 captures 1 promotions 2;
I have added this code to the Chess include files, and I have added appropriate code to some of the other include files. So extraneous user input should now be banned in several games that enforce the rules. If you have programmed rule enforcement for your own presets that do not include any of my include files, then you will need to add this or similar code yourself.
If you program in GAME Code, you may want to take note of this. One internal change I made while programming these features was to separate user input from GAME Code commands. The result is that user notation can no longer be used inside of a GAME Code program as programming code unless the line is prepended with the keyword 'MOVE: '. In general, it is best to reserve user notation for the players and use only commands in the code you program.
I have written two presets: /play/pbm/play.php?game%3DBreakthrough%26settings%3DBreakthrough /play/pbm/play.php?game%3DSquirrel+Chess%26settings%3DSquirrelChess1 May I ask some questions about Game Courier / GAME code: 1. I observe that I can't enter comments starting with '//' in the Pre-Game part. I wrote: // comment setsystem maxmove 2; ... And I receive an error message: Syntax Error on line 0 // comment setsystem maxmove 2 is not a valid expression, because // is not a recognized piece, coordinate, command, or subroutine. Why is this? 2. What happens if I edit and save a preset if there are already players using it, e.g. when I remove a bug or add notification for mate / stalemate. Can this cause problems? 3. What happens if an operator needs more operands than are on the stack, or if there are two or more values left on the stack after evaluating an expression, or if an operator is given an operand with a senseless type, e.g.: set ep false; ... if equal where #ep 0 1 a3; ... endif; Are there rules how such cases are handled, or does the program behave in an undefined way? 4. am I right that a board position (like 'a4') is of type 'string', and also a piece type like 'n' or 'K'? Or are these special types on their own?
Thanks for your interest in GAME Code.
1. I've had the same problem, but I haven't taken the time to look into it. Maybe I will sometime.
2. Fixing a preset people are using should normally have no harmful effect on any ongoing games. It might break some logs if someone has made an illegal move and your bugfix corrects this. I can fix logs manually when this happens. Adding the ability to spot check, checkmate and stalemate is unlikely to break any logs unless someone continued a game past its natural end.
3. While there is no defined behavior, tests indicate that when the stack does not have all the operands required by an operator, the operator gets null values for the remaining operators. For example, '+ 1' returns 1, '* 1' returns 0, '- 1' returns 1, and '/ 1' complains of a division by zero error and returns nothing.
If there are more values on the stack after evaluating an expression, the expression will return a backwards array of all the values remaining in the stack. For example, set a + 5 6 - 8 3 sets a to the array (5 11). To get an array in the same order as the remaining operands, use the array operator, as in set a array + 5 6 - 8 3, which sets a to the array (11 5). Sub-expressions within a larger expression will use only as much of the stack as they need and return values to be used in the larger expression. For example: set a * + 5 6 - 8 3 would reduce to set a * + 5 6 5 then to set a * 11 5 and finally to set a 55.
Since GAME Code is loosely typed, it will convert a value given as one type to the type of value it is using. For example, a boolean value of false would be treated as zero by a math operator. In your example, 'where #ep 0 1' where ep is set to false, it apparently got interpreted as a1, whose index in the list of coordinates is zero. It is normally expected that you will write your code to give operators the types of operators they expect, and the results you may get from bad data are undefined.
4. The notation for coordinates and pieces are strings. In Game Courier, the board is represented by an array whose keys are coordinates and whose values are pieces, @ signs for empty space, and - signs for offboard locations. This array is called $space, and GAME Code lets you read the contents of its elements with the space operator.
Thanks for your explanations! I have suspected the problem with ep == false. I should correct my Squirrel Chess preset due to this.
I want to restrict user input so: setsystem maxmove 2; ban commands allmoves; allow moves 1 moves 2 captures 1 promotions 2; The purpose is to allow entering a generalized castling move, examples: e1-d1;a1-e1 e1-b1;a1-d1 But then the user might enter something like c1-f7;d2-d4 , the first part being illegal. The preset should reject this move, but it is difficult, because the system variables only reflect the (legal) second part d2-d4 : old = @ origin = d2 dest = d4 moved = P Is it possible to get info about the first move-part, or at least the info that the user has entered two parts?
In the presets for Extra Move Chess and Marseillais Chess, I stored the board configuration before the move, parsed the moves entered by the player, restored the board to its premove configuration, then evaluated the moves individually. You could do something similar. I recommend restoring the board and evaluating the moves separately only when there are multiple moves, allowing the preset to just go ahead and evaluate the single move when only one move has been made.
Another alternative is to allow the castle subroutine and require players to use it for castling. It is supposed to be able to handle free castling. Details are provided in the comments before the subroutine in the include file. The examples you gave could be rewritten like this:
e1-d1; castle e1; e1-b1; castle d1;
Sorry I have to pester you again: I'm writing a preset for Wildebeest Chess. Now I have a strange bug in the code which I can't understand. I have boiled it down to the following little procedure: sub test; my i; set i origin; do: if != space #i @: die X.; endif; set i where #i 0 1; loop until == #i dest; endsub; This is defined in the pre-Game part. In the Post-Move-1 part I call the procedure: gosub test; Then I enter a pawn move, e.g. f2-f5 and I get the error message 'misplaced endsub' at the line number where the procedure 'test' ends. Why is this?
The link to the preset: /play/pbm/play.php?game%3DWildebeest+Chess%26settings%3DWildebeest+Chess+with+rules The error occurs in the procedure 'checkkcastl' in the pre-game part. Near the end there is a do-until loop that checks if the king crosses attacked squares. This loop seems to cause the error. The error occurs when legally castling with the king over 2 or more squares (entered as a king's move, e.g. f1-h1). Then the said loop is not ended by the 'die' command but by the until-condition, and the error message is produced. If I castle over an attacked square, the 'die' ends the loop, and it works correctly.
Thank you! I'll look at the chess2 file and see how I can use it. I started to program Wildebeest Chess because it is a good practice in GAME Code and because there is not yet a preset with rule enforcement (at least I have found none).
I have looked at 'chess2.txt' as you recommended, and rewrote my Squirrel Chess preset to use it (because this was easier than Wildebeest Chess). Also I have experimented and looked at some other presets. Thereby I have found some bugs: The operator sign calculates the sign of the operand decremented by 1. In the preset for orthodox chess (and maybe in some others too) it is not tested if a rook to castle with has been captured. One should add unsetflag dest; at an appropriate place in the code. In the file 'chess2.txt': In function p: checkatwostep must have the arguments 0 -1 0 -1; Functions p and P allow captures to occupied squares only (except enpassant). Thus they are not suited to test if an empty square is attacked, and the subroutine 'castle' doesn't work correctly. It calls 'checked' to test for castling out of or through check, which in turn uses p and P. In sub stalemated: If a royal pawn captures en-passant, the captured pawn isn't removed. (also, 'store' and 'restore' are called more often than necessary.) In sub 'enpassant': The line set #pe join filename #to filename #from; should be replaced by local pe; set pe join filename #to rankname #from; In sub castle: near the end there should be 'subargs' instead of 'subarg'. Also I have some questions: Is there a difference between numbers and strings, or are numbers just strings consisting of digits only? In the following code: set wpr 2; if == rankname #from #wpr: ... endif; either rankname gives a number if the ranks are labelled with numbers, or numbers are strings, or numbers are implicitly converted to strings (or vice versa). Wouldn't it be reasonable to check the legality of the last move only? In all presets I have seen the legality of every move is checked, but if a preset rejects all illegal moves, all moves except maybe the last must be legal, if I don't overlook something. BTW: I plan to write a 'chess3.txt' include file which is more flexible and general, first to practice writing GAME Code and second because it might be of use for you and others. Before I begin, I should know if it can be a mistake to thest the legality of the last move only. This would improve efficiency in long games.
Thanks for your bug reports, Thomas. Here is a checklist of what I have dealt with.
The operator sign calculates the sign of the operand decremented by 1.
Fixed.
In the preset for orthodox chess (and maybe in some others too) it is not tested if a rook to castle with has been captured. One should add unsetflag dest; at an appropriate place in the code.
Yes, it allowed the King to castle with a Queen that captured a Bishop that captured the Rook. I fixed it in the Chess preset. To avoid editing numerous presets, I may modify the - operator to unset flags and create a system variable for turning this behavior off for games that use flags differently.
In the file 'chess2.txt': In function p: checkatwostep must have the arguments 0 -1 0 -1;
Fixed.
Functions p and P allow captures to occupied squares only (except enpassant). Thus they are not suited to test if an empty square is attacked, and the subroutine 'castle' doesn't work correctly. It calls 'checked' to test for castling out of or through check, which in turn uses p and P.
TO DO. I'm not sure if I can fix the functions, since the stalemated subroutine uses them to check whether any piece may move. What I should do is rewrite the castle subroutine to move the King one space at a time, checking whether the King is in check for each step of its move. Then these functions should work with the castle subroutine.
In sub stalemated: If a royal pawn captures en-passant, the captured pawn isn't removed.
I never anticipated royal Pawns. Since I don't know of any games with royal Pawns, and I don't think royal Pawns would make for a very good game, I have simply modified the comments to say that it doesn't work for royal Pawns.
(also, 'store' and 'restore' are called more often than necessary.)
The stalemated subroutine calls store once. It might call restore in one spot where it's not needed, but it doesn't hurt. Every time restore is used after a move, it is necessary.
In sub 'enpassant': The line set #pe join filename #to filename #from; should be replaced by local pe; set pe join filename #to rankname #from;
Fixed
In sub castle: near the end there should be 'subargs' instead of 'subarg'.
Fixed.
Thank you for the fixes and explanations. But you have overlooked that in sub 'enpassant' there is twice 'filename' used. It should be 'filename #to rankname #from'. To check if any piece or any empty square is attacked, one could use the following subroutine: // This subroutine checks whether 'square' is attacked by the given side: sub attacked square bywhite: local from piece pawn pdir; if #bywhite: def enemies onlyupper; set pawn P; set pdir 1; else: def enemies onlylower; set pawn p; set pdir -1; endif; for (from piece) fn enemies: if == #piece #pawn: if checkaleap #from #square 1 #pdir or checkaleap #from #square -1 #pdir: return #from; endif; elseif fn #piece #from #square: return #from; endif; next; return false; endsub;
Thank you for the fixes and explanations. But you have overlooked that in sub 'enpassant' there is twice 'filename' used. It should be 'filename #to rankname #from'.
Thanks for mentioning that. It's now fixed.
To check if any piece or any empty square is attacked, one could use the following subroutine:
This subroutine may work for Chess, but it would not work for games with other divergent pieces, such as Cannons. The best way to handle attacks on empty spaces that a King must pass through to castle is to move the King to each square before checking whether it is attacked, which I have now done. This works equally well for any divergent piece.
A better method than your subroutine to check whether an empty space is attacked is to temporarily fill an empty space with a piece then check for attacks on it. With an enemy Cannon on a player's first rank, this would not work accurately for castling, though it would give the right result for the wrong reason. Let's say that the first rank just has an unmoved King and Rook with an enemy Cannon on the other side of the King. Although the Cannon attacks the spaces between the King and Rook, it is not accurate to say that the King would be passing through check from the Cannon if it castled. After all, the Cannon attacks the space just to the other side of the King, using the King as the screen, but the King may legally move there, because there is no screen between the King and the Cannon. Still, castling would put the King in check, because the Rook would become a screen. So, castling would still be illegal. In most instances, using an attacked subroutine that temporarily places a piece on an empty space would work for castling. But if you had a game in which Rooks can block Cannon attacks, then castling would be legal, and this method of checking for attacks would not work for castling. Alternately, if you had a piece that can check the King but not any other piece, or a piece with an attack that only affects the King, such as the Kings' long range attacks on each other in Eurasian Chess, then whether or not this subroutine worked well with castling would depend in part on which piece is temporarily placed on the empty space.
Note that the changes I made to the castle subroutine in the chess2 include file are not needed in the chess include file, because that include file uses separate functions to determine whether the King is attacked.
Here I am again with one more bug ;) In file chess2.txt the 'stalemated' subroutine doesn't recognise en passant captures. I tested this with my Squirrel chess preset. In a position where the only legal move is an ep capture, it says 'stalemate'. By experimenting I found that it should work if in the functions P and p '#ep' is replaced by 'var ep'. It seems that '#' inside a function inserts the value of the variable at the time the function is defined, while 'var' is reading the value when the function is executed. But this seems not to be so for subroutines. Here # and var have the same effect (at least I haven't observed a difference yet).
Thanks for your bug report and your bug fix recommendations. I changed #ep in the p and P functions to var ep. You are right about the difference between the two in functions vs. subroutines. Functions and subroutines are very different things in GAME Code. A subroutine is made up of lines of code. When a subroutine is called, program execution jumps to the subroutine, and as the program goes through the subroutine, it executes each line of code afresh. In this context, it doesn't matter whether a variable's value is called by the var operator in an expression or with the # prefix. But in functions it does matter, because when a function is called, the program does not go back to the function definition and execute it afresh. Instead, it draws an already created function from a table of functions. If a variable in a function definition is accessed by the # prefix, then its value at the time of the function definition shapes the function. To use whatever value the variable has whenever the function is executed, the var operator needs to be used instead of the # prefix.
I'm done with four presets yet. They are automated and with rule-enforcement and detect the end of a game (but not by threefold repetition or 50 moves rule). I have tested them and they seem to be bugfree. Maybe you want to include them into the 'Games for Game Courier' list. Breakthrough: /play/pbm/play.php?game%3DBreakthrough%26settings%3DBreakthrough Wildebeest Chess: /play/pbm/play.php?game%3DWildebeest+Chess%26settings%3DWildebeest+Chess+with+rules Gess: /play/pbm/play.php?game%3DGess%26settings%3DGess+with+rules Playing gess is a nuisance without an automated preset, so I wrote one. To make the point-and-click movement usable, the preset expects that the origin and destination coordinates of the direction stone are entered. This is uncommon, normally a move is denoted by the coordinates of the center of a piece (= 3x3 area containing a stone in the direction of movement). Squirrel Chess: /play/pbm/play.php?game%3DSquirrel+Chess%26settings%3DSquirrelChess1 This variant I have made up myself. The difference to orthochess is only the 9x9 board and every side has an extra pawn and a squirrel which leaps two squares orthogonally or diagonally or like a knight (as described in the piececlopedia). Pawns promote to squirrels also. BTW: how can I uncheck 'exclude pieces not in setup' when editing a preset? Somehow it doesn't work. Is it possible to select some pieces out of a piece set and assign them names entirely of upper- or lowercase letters, so that 'isupper' and 'islower' can be used to identify pieces of a side?
This is good to know. But can someone please tell me how it is done? I can't log in. I just went to the 'Games for Game Courier' page, clicked 'edit' at the bottom right of the page (is this the right way to add more presets, BTW?), and after entering my username and PW, the login window just appeared again with my PW deleted. I used the same data as when saving a preset. Maybe it's because I'm not a member nor a contributor yet. What should I do next?
Hi, either I didn't get something, or I have found another bug. I put the following code in the Pre-Game part: set arr (x y); sub test: local a2; set a2 (); for i var arr: push a2 #i; next; for i var a2: echo #i; next; endsub; gosub test; gosub test; I believe the output of this should be: x y x y since test is called twice, and both times the content of arr is copied into a2 and then output. But the output is in fact: x y x y x y In the second call of test, the old content of a2 is seemingly not deleted, and the 'x y' is appended to it. If I make the variable a2 global (i.e. delete the line 'local a2;') then it works as it should.
100 comments displayed
Permalink to the exact comments currently displayed.