[ List Earliest Comments Only For Pages | Games | Rated Pages | Rated Games | Subjects of Discussion ]
Check out Janggi (Korean Chess), our featured variant for December, 2024.
Check out Janggi (Korean Chess), our featured variant for December, 2024.
Indeed it works now. And I changed the plans a little. As e.p. capture cannot be done without creating e.p. rights, and this creation is a side effect of regular leaps and rides, implementing generation of the latter is the logical next step. To get some idea of whether the code is working, it will be used for highlighting pseudo-legal moves. Because such highlighting has to be done from the Post-Game sections, we first have to fill those, with gosub GameEnd false; and gosub GameEnd true; for white and black, respectively. As Game Courier wants to have the complete list of moves for all pieces in advance, we also need a routine GenAll that calls GenMove for all pieces of a given player (which is the opponent of the player passed to GameEnd). This is pretty much standard:
For now the only task of the GameEnd routine is to use this 'all-moves' generator for filling the array of legal moves; a new task (2) is defined in GotMove to do a setlegal #orisqr #destsqr there. In a later stage this would only have to be done for moves that need explicit specification of side effects; we don't want to encourage the user to click the destination of such moves without typing the side effects! The routine GameEnd just specifies the task, and inverts the player.
That is all pretty straightforward. The real work is done by NextLeg, which is now expanded to:
The task is to generate all possible realizations of one leg of the move, where the leg is a ride that is specified in the legdefs table (at legindex) as its range, x-y step and 'mode'. The latter is a set of bit flags packed into an integer, which specifies what the leg can do (e.g. capture). For most legs the destination will be unique, e.g. because they are leaps, or because the mode requires a certain kind of occupant on the destination. And by definition a ride can only have one occupied square in it, at which it must terminate. The only case where a leg as several alternative destinations is thus when a true rider makes a non-capture move. In this case NextLeg has to loop over the destinations, and generate a move for each of them.
The algorithm of NextLeg roughly has three parts. First it determines the farthest square of the ride, taking into account the board size and occupation, the range of the leg, and whether a specific length was requested (to match that of an earlier leg). Then, if the mode allows non-captures, it loops over all squares up to that final square, which are guaranteed to be empty. Finally it determines if a move to the final square is possible, given the occupant and the mode. This can (in a non-final leg) still lead to two different realizations, one that captures the occupant, and one that uses it as a screen to hop over.
In phase 3 of the project we only handle simple moves, consisting of a single leg. For every realization of the leg NextLeg then calls GotMove to process the move. In multi-leg moves it might have to call itself recursively at those points, to attempt the remaining legs, but for now we can leave out these recursive calls. The only modes we handle is capture, non-capture and friendly capture. (The castling code of phase 2 goes into that latter section.) It is ignored whether a leap is lame, and the more exotic features of XBetza, such as move induction and unloading of victims are not implemented either. Hopping, locust capture, and bent riders are intrinsically two-leg phenomena, and won't work either.