-
Notifications
You must be signed in to change notification settings - Fork 45
Rules Package
Here follows a brief description of how the Rules package works, and how the different files interact. It is highly encouraged that you read all documentation in the Rules package before attempting to modify code; this page is merely here to help provide some insight on the structure of this package, not as a substitute for reading the documentation.
Every chess game will have a single Rules object for each player, which will contain objects to model the different types of customizable rules. These types each have their own class.
AdjustTeamDests determines which moves are legal for a player given the other possible moves. AfterMove determines what must be done after a player's move is finished. CropLegalDests, which is similar to AdjustTeamDests, determines what moves are legal for a particular piece, but does not take legal moves for other pieces into account. EndOfGame is responsible for deciding when the game is over and notifying the rest of the program. GetBoard determines onto which board the move will take place. In classic chess there is only one board, but some variants require multiple boards, so game play make take place on one of several boards. GetPromotionSquares is used for deciding which squares a piece may promote on; in classic chess, only the back row squares are promotion squares. NextTurn decides which player is to move next. ObjectivePiece provides access to the piece whose capture results in the end of the game. Finally, Promote is responsible for determining to what type of piece a piece promotes.
You may have already noticed that these types of rules actually seem more like methods than classes. In a way, this is so. In some cases, however, it is nice to be able to use multiple of these "methods" for a single chess game. For example, we may want to do more than one thing after a game is over, depending on the way the variant has been set up. In order to encapsulate this, each of the rule type's classes has one method for every feature, and then the class has a list of methods to perform, using reflection. Each class has an "execute" method, which calls all the appropriate methods for the particular object, and has an interface providing the ability to add to this list of methods. This is done at runtime, when the user chooses to play a particular chess variant.
Each method has a corresponding "undo" method, necessary because players are able to undo moves, and because in order to check whether a move would place a player in check, it is necessary to first perform the move, then undo it. There is a similar list of "undo" methods, which are set at runtime using reflection.
As noted above, each Rules object contains an object for every type of rule. Whenever that rule needs to be applied (or undone), it uses the corresponding object to do so. This class really does very minimal work; it has getters and setters for each of the objects, and calls the execute and undo methods, but delegates most of the real work to its instance variables.
The purpose, of course, of having these classes for types of rules is convenience in implementing variants. In order to add a new variation, one has to simply determine what "type" of rule it is, and add two methods to that class, one for implementing the rule and another for undoing the rule. As such, each class has several variants it currently supports, as well as room to grow in supporting other variants. Note that every class must have at least one "variant" - to allow standard chess to be played; also notice that these variants can be mixed and matched, often even within the same class.
AdjustTeamDests currently has only one variant, which allows users to write a variant in which any legal capture move is mandatory. However, other variants could be written in this class with very little effort. For example, it would not be difficult to modify AdjustTeamDests to allow a custom piece which normally moves as a pawn to move as a queen if the queen is unable to legally move.
AfterMove has several variants, as many variations of chess require something to be done after the turn would normally be over, in standard chess. In fact, this is one of many rule types in which the classic chess variant's method is completely empty, as nothing needs to be done after a move in classic chess. The current variants swap the color of any captured pieces, so that by "capturing" a piece, a player acquires an extra playing piece; return captured pieces to their originating square, removing permanently any piece unlucky enough to be on that square; allow the capturer to place captured pieces anywhere; change the color of the capture piece AND allow the capturer to place the piece anywhere; and remove all pieces surrounding a capture except pawns.
CropLegalDests currently supports only a single variation, which requires the objective piece to remain stationary throughout the entire game.
EndOfGame has a few variants, as another common feature in custom games is changing the rules on how to win. Current variants cause the end of the game to happen when all pieces of a particular type are captured; when a team has been placed in check a user-defined number of times; when a team has lost all of its pieces (constitutes a win, not a loss); or when a team captures all the opposing pieces to win. Notice that each player may only use one of these objectives, but there is no reason why the players need to have the same objective. For example, one team could be playing to capture all the opposing pawns, while the other must check three times in order to win.
GetBoard has only one variant, and is likely to remain that way. The only variant supported allows for play on two different chess boards, so that every turn a piece will move from one board to another. It's unlikely to expand as a class, however, because most users simply won't want to play with more than two boards; game play on even two boards can be confusing, so adding a third, or fourth or nth board would be only confusing to players, as well as being very difficult to display properly!
GetPromotionSquares has only one variant currently, but probably will not stay this way. Right now the only variation turns off promotion entirely, so that nothing can promote on any square. Another variant that could be added allows for the user to define which pieces can promote, and where they promote.
NextTurn has a few variants, but they are all fairly similar. In these variants, both teams may have more than one turn, and the number of turns each player can make increases by some increment amount. The different variants are there to account for whether black and white have the same number of turns and the same increment amount.
ObjectivePiece has only two variants. The first allows the user to define which piece is the objective, but only allows a single objective piece. The second one allows for games with NO objective piece. This is used in variants where EndOfGame may be something different, such as capturing all pieces of a specific type, or losing all pieces.
Promotion has only a single variant, but like GetPromotionSquares, this is likely to change. Its own variant is a parallel to GetPromotionSquares, which does not allow promotion for any piece. An additional variant could allow users to define which pieces can promote and what they may promote to. For example, perhaps a custom piece promotes to a knight only. Note that this is closely linked to GetPromotionSquares, so that in order to make these changes, GetPromotionSquares would also have to be modified.