Comments/Ratings for a Single Item

Sounds awesome. Only problem is that returning 512 for the promomtion it doesn't work like it should. Instead of burning adjacent pieces it simply burns the moving piece as if you returned 251 for the promotion.

Strange. I had not tried it for WeirdPromotion, but I did now, and it works for me. The version on the CVP website has exactly the same size as the one I am using locally.
[Edit] Try refresshing the browser cache. Before I did that I had the same behaviour as you describe in the Diagram above.

satellite=desert
files=8
ranks=8
promoZone=1
promoChoice=QRBN
graphicsDir=/graphics.dir/alfaeriePNG/
squareSize=50
graphicsType=png
lightShade=#ffff80
darkShade=#bf998c
rimColor=#077208
coordColor=#ffff40
borders=0
firstRank=1
useMarkers=1
newClick=1
atomicCapture=0
pawn::::a2-h2
knight:N:::b1,g1
bishop::::c1,f1
rook::::a1,h1
queen::::d1
king::::e1
|
|
The Queen burns like a Fire Demon here.

It works now.

The Queen burns like a Fire Demon here
Did you mean including passive burning as well? Only active burning is working for me (though Adam's Tenjiku diagram seems to implement passive burning too so clearly it's implementable as you described)

The Diagram I posted only does active burning. Sorry I was unclear about that.
Adam implemented the burning by embedding a custom script for WeirdPromotion. Where he first tests whether a piece lands next to a burner (and in that case returns 251 as promotion code to make it a kamikaze move), and otherwise returns 512 when the moved piece is a burner.
I only used the captureMatrix parameter in my Diagram. There is no formalized way yet to specify passive burning by Diagram parameters; you would have to supply a JavaScript extension.

satellite=burn
files=8
ranks=8
promoZone=2
maxPromote=3
promoOffset=6
royal=6
graphicsDir=/graphics.dir/alfaeriePNG/
squareSize=50
graphicsType=png
lightShade=#ffff80
darkShade=#bf998c
rimColor=#077208
coordColor=#ffff40
borders=0
firstRank=1
useMarkers=1
newClick=1
trackPieces=1
atomicCapture=0
pawn::::a2-h2
bishop::::c1,f1
rook::::a1,h1
knight:N:::b1,g1
queen::::d1
king::::e1
steward::mWcF::
horse::BW:promotedbishop:
dragon::RF:promotedrook:
|
|
This Diagram lets the Queen burn both actively and passively. It uses trackPieces=1 to track the Queen, so WeirdPromotion() can efficiently get her location, and mark the adjacent squares as the burn zone, to destroy all pieces that land there.
(Refresh the browser cache, as there was a bug in the standard script w.r.t. kamikaze moves: these did set the 'non-virgin' flag on the resulting empty square, so the Diagram would treat it as an invisible white piece rather than an empty square. For now I solved that by making all pieces resulting from promotion virgin. Which is of course incorrect, but much less harmful.)

I am getting less and less happy with the WeirdPromotion() and BadZone() extension system for the Interactive Diagram. It is inconvenient that these are two different functions, and a shortcoming of WeirdPromotion() is its limited power for adding side effects to the move, and that it gets passed only a single locust square (while the NewClick entry system allows arbitrary many locust victims). This has been somewhat ameliorated by the kamikaze and burn/atomic pseudo-promotion codes, but there still remain lots of things that cannot be done.
It would be much better to have a single user-supplied function AlterMove(move), which gets the internal move representation passed as the single argument. This move representation is an array, which contains the coordinates of all involved squares (origin, destination, all locust squares, all squares where e.p. rights are generated, the promotion piece...). And what is even better: AlterMove() could make changes in that, (like adding locust squares), which would affect the original. As, unlike scalar objects, when an array gets passed to a function it will be the real thing, not a copy. So it could directly alter the promotion choice in the move, rather than returning it as a result, and leaving it for the standard code to incorporate it in the move.
The return value then could be reserved for signalling only. Like indicating that the move or promotion choice is forbidden, so that the move should be deleted from the move list. Or that the move is winning (e.g. by reaching a goal square). Or that a move thought to be a non-promotion should unexpectedly offer promotion choice (making the standard script duplicate the move, this time with other promotion choices, subjecting these again to AlterMove() to test whether these are allowed, and add those to the move list when they are).
This would for instance also allow implementation of pieces like the Ultima Coordinator, which might need locust captures on distant squares at the intersection of its coordinate lines and those of the King. By switching the Diagram's tracking function on, the location of the King would be easily available, and the AlterMove() routine would just have to combine these with the coordinates of the destination on a Coordinator move, test whether there is an enemy there, and if there is, add it as a locust square to the move.
For backward compatibility the standard script could contain a default function for AlterMove(), which it invokes if the user has supplied a WeirdPromotion() or BadZone(), to call the latter two for the move in question, and translate the return values to the actions these request. (Like altering the promotion piece, or return the 'forbidden' code.) This seems a simpler and more powerful system. Perhaps some standard routines could be offered to simplify writing AlterMove(), like AddLocustSquare(move, x, y).
I am also wondering if I should devote some attention to configurable use of the trackPieces functionality in such a standard version of AlterMove(). Passive effects on adjacent pieces are not that uncommon in variants, especially immobilization. So where trackPieces=N now just serves to switch on the tracking for non-zero N, I could have N indicate a piece type for which the adjacent squares should automatically be marked in a neighbors[] array indexed by square number. And supply a new Diagram parameter neighbors, which could be given the values immobilize, pacify or burn, which then would activate to either forbid all moves with a piece standing on a marked square, forbid all its captures, or make moves to a marked square kamikaze moves, respectively. Then these rules could be implemented purely by configuration, without writing any script.

I think I will implement the following interface for extending the Interactive Diagram with user-supplied scripts:
The user can supply a JavaScript function xxxTinker(m), where xxx is the satellite name for the Diagram (default value: 'piece'), and m is an array describing the move. This array will contain the board coordinates (which always start counting at 0) for the squares involved in the move, the rank number following the file number of each square. The first square (in m[0] and m[1]) will be the origin, the second (m[2] and m[3]) the destination, and after that will come the locust squares in the reverse order as the XBetza description visited them. The element m[-2] will specify how many squares will be altered by the move. (So if there are no locust squares this will be 2: the origin and destination.) After the locust squares can come squares where e.p. rights are generated; these are not counted in m[-2]. It is not specified how many there are of those, and most moves do not have them.
The element m[-1] contains the promotion piece for the move (i.e. the piece that will appear on the destination square), but it might or might not be initialized.
This xxxTinker() funtion can then modify the m array in any way it wants. Likely modifications are altering or supplying a promotion piece in m[-1], or adding locust squares by writing those in the appropriate m[] elements, and increasing m[-2] correspondingly. When it is done tailoring the move, it should return a value to indicate to the standard script what it should do with that move. Possible return valueas ar:
-2 Terminates game immediately, as a win for the player that can do the move (as if the move captured a King). -1 Terminates the game as a win if the player making it survives the reply of his opponent (as with Shatranj baring). 0 Take the move as we now prepared it (which could be unaltered). 1 Discard the move; it is forbidden (e.g. due to zonal confinement, or improper promotion piece). 2 Suppress deferral of normal Shogi promotion (as per maxPromote and promoOffset). 3 Take the promotion we specified in m[-1], but also add a move that defers. 4 Perform a Chess-like promotion. Moves with every possible promotion type will be subjected to xxxTinker(), and can be rejected or accepted by it in the normal way (returning 1 or 0).
The value 4 should only be returned when the value of m[-1] was undefined (if(!m[-1])...), to make a move that otherwise would not promote at all offer a Chess-like promotion choice. If m[-1] does have a value > 0 the promotion choice has already been made, and we must only reject or accept it.

To make life easier for those who want to extend the Interactive Diagram with custom JavaSCript, I added a second argument to xxxTinker(): this gets passed the distance to last rank, corrected for piece color. Almost every WeirdPromotion() function I have ever written required calculation of that.
I added functions in the standard script to aid with other tasks: AddVictim(move, x, y) adds a locust square (x, y) to the specified move. And VetChoice(promoPiece, d) tests whether chess-like promotion to promoPiece would be allowed (as per promoZone and promoChoice) when you are d steps removed from last rank. You might want to fake a d within the zone in cases where the user script requests a promotion outside the zone.
The moving piece will always be stored in move[-6]. As an example, when you want to allow piece type 2 to promote when it arrives on last rank from the fore-last one, but not from a larger distance, you could use
function xxxTinker(m, d) { if(d != 0) return 0; // not to last rank if((m[-6] & 511) != 2) return 0; // not piece type 2 if(m[3] != m[1] + 1 && m[3] != m[1] - 1) return 0; // not a single step if(!m[-1]) return 4; // choice not yet made, request one return VetChoice(m[-1], 0); // return whether choice is forbidden (1) or not (0) }
If under the same conditions a shogi-like promotion to piece type 12 (different from what promoOffset would specify) should take place, things are simpler:
function xxxTinker(m, d) { if(d != 0) return 0; // not to last rank if((m[-6] & 511) != 2) return 0; // not piece type 2 if(m[3] != m[1] + 1 && m[3] != m[1] - 1) return 0; // not a single step m[-1] = 12 | m[-6] & 1024; // specify promoted type (adding color) return 3; // request choice between this and deferral }
Scripts like this are only needed to make the promotion dependent on the move; if it is just dependent on the square you move to, or what you capture there, the standard parameters morph and captureMatrix take care of the promotion for you. The way I have implemented it now these would have precedence over the user-supplied scripts. That is, when these specify a promotion, ban or game termination, this will be applied without question, and the xxxTinker() script will only be invoked when they don't specify anything special. So the script only has to handle the non-standard cases.
Although the script could now add as many locust victims to a move as it wants, and wherever it wants those, the trick to request burning or atomic capture through promotion code 512 will still work, and the standard script will add the locust squares in that case.

An Interactive Diagram using the new scripting interface is now available in the alternative script betzaNew.js. (Which, after sufficient testing, will replace the current betza.js). As a test case I used it to create the Ultima Diagram in the previous posting.
Ultima required a fair amount of scripting. Only the Long Leaper and the Withdrawer can be done purely with XBetza. The Immobilizer can be done with the aid of the new trackPieces=N and curse=freeze parameters. Pinching is a kind of burning, but since it is dependent on the burn victim being sandwiched, this has to be tested in a script before a 'selective burn' promotion can be issued. Coordinator capture needs to be performed entirely by the custom script (using the coordinates of the tracked King), by adding locust squares to Coordinator moves.
The Chameleon is of course a disaster; it needs to be able to do what all other pieces do, but in a type-selective way. Only the replacement capture can be implemented in XBetza, as kK, because the King happens to be royal. The other captures that can be described with XBetza need to be vetted for whether they capture the correct victim. I only did that for Long Leapers, and add capture of a Withdrawer as an extra locust square 'by hand'. The standard script now supplies the routine AddVictim(move, file, rank, mask, target) to facilitate that; the mask and target arguments are optional, and when omitted the square (file, rank) is only added if it contains an enemy piece. By setting mask = 0x4FF you can test for a specific colored piece type (the test is (board[rank][file] & mask) == target), and other pieces would not be affected.
The curse=freeze option would only freeze enemy neighbors of an Immobilizer, not the Immoblizer itself (of course). But if a Chameleon is frozen, it reciprocates the favor. So the custom script has to test the board for adjacent enemy Chameleons, and mark the Immobilizer square as freezing too when any are found. Al in all this gave me the following custom script:
var myNodes = 1e8; function ultimaTinker(m) { var s, p, v, k, x, y, xx, yy, type = m[-6] & 511, col = m[-6] & 1024; // mover and its color if(nodes != myNodes) { // new node; update burn map first myNodes = nodes; var q = loc[col+6], x = q & 7, y = q >> 7; // friendly immobilizer? if(q >= 0 && (board[y][x] & 0x4FF) == col + 6) { // yes! var l = (x ? x-1 : 0), r = (x == 7 ? 7 : x+1); // left and right boundary of surrounding for(var i=l; i<=r; i++) { // detect enemy chameleons next to it if((board[y][i] & 0x4FF) == 1029 - col) neighbor[q] = nodes; // on same rank if(y && (board[y-1][i] & 0x4FF) == 1029 - col) neighbor[q] = nodes; // on next-lower rank if(y < 7 && (board[y+1][i] & 0x4FF) == 1029 - col) neighbor[q] = nodes; // on next-higher rank } } if(neighbor[q] == nodes && type == 6) { freeze = 100; return 1; } // the current move should have been frozen } if(type == 1) { // pincher moved var p = 0, x = m[2], y = m[3], xcol = 1024 - col; // destination and enemy color if(x > 1 && (board[y][x-1] - 1 & 0xC00) == xcol && (board[y][x-2] - 1 & 0xC00) == col) p |= 0x40; // W if(x < 6 && (board[y][x+1] - 1 & 0xC00) == xcol && (board[y][x+2] - 1 & 0xC00) == col) p |= 0x04; // E if(y > 1 && (board[y-1][x] - 1 & 0xC00) == xcol && (board[y-2][x] - 1 & 0xC00) == col) p |= 0x10; // S if(y < 6 && (board[y+1][x] - 1 & 0xC00) == xcol && (board[y+2][x] - 1 & 0xC00) == col) p |= 0x01; // N if(p) m[-1] = p | 512; // request a selective burn through the promotion code } else if(type == 5) { // chameleon moved // long-leaper victims for(k=2; k<m[-2]; k++) { // at this stage all locust squares are long-leap captures v = board[m[2*k+1]][m[2*k]]; if((v & 0x4FF) != 1027 - col) return 1; // victim not long leaper; reject this move } // withdrawer victims x = m[0] - m[2]; y = m[1] - m[3]; // calculate unit step (should really be table lookup...) k = (x ? x : y); if(k < 0) k = -k; xx = x/k + m[0]; yy = y/k + m[1]; if(!((xx | yy) & 8)) AddVictim(m, xx, yy, 0x4FF, 1026 - col); // add withdrawer victim if on board // pincher victims if(!(x & y)) { // only on orthogonal moves p = 0, x = m[2], y = m[3], xcol = 1024 - col; if(x > 1 && (board[y][x-1] - 1 & 0x4FF) == xcol && (board[y][x-2] - 1 & 0xC00) == col) p |= 0x40; // W if(x < 6 && (board[y][x+1] - 1 & 0x4FF) == xcol && (board[y][x+2] - 1 & 0xC00) == col) p |= 0x04; // E if(y > 1 && (board[y-1][x] - 1 & 0x4FF) == xcol && (board[y-2][x] - 1 & 0xC00) == col) p |= 0x10; // S if(y < 6 && (board[y+1][x] - 1 & 0x4FF) == xcol && (board[y+2][x] - 1 & 0xC00) == col) p |= 0x01; // N if(p) m[-1] = p | 512; // request a selective burn through the promotion code } // coordinator victims k = loc[col + 7]; // king location (128*rank + file) AddVictim(m, k & 7, m[3], 0x4FF, 1028-col); // add locust square for coordinated coordinator AddVictim(m, m[2], k >> 7, 0x4FF, 1028-col); } else if(type == 4) { // coordinator moved k = loc[col + 7]; // king location AddVictim(m, k & 7, m[3]); // add locust squares for coordinated enemies AddVictim(m, m[2], k >> 7); } return 0; }
Issues in the interface that could still be improved:
- The standard script tests for freezing / burning before the custom script is consulted. So when the custom script adds a freezing or burning square, like it does here when the freezing is 'reflected' by a Chameleon, the move that consulted the script would have already passed the test if it happened to be the first move generated. The Ultima script above has to explicitly test for that.
- The standard script now automatically marks the 'blast zone' around the tracked piece (controlled through trackPieces=N). But it now always uses K steps for that. It might be useful to make this user-configurable, through an option blastZone, so that the default burning could take place only on W or only on F squares, or perhaps even on N squares.
- It could be useful to define the meaning of the bits in the promotion code for a selective burn (and the marking of the blast zone) relative to the player. That would allow asymmetric burning (e.g. only forward) to work the same for black and white.
- Perhaps it should be possible to specify 'shooters' expicitly. Entering the Withdrawer and Coordinator moves in the Ultima Diagram below feels a bit queer, as you have to specify the victim first. This will always happen with locust victims added by the script; you will have to click those in the reverse order from which they were added. The Long Leaper obviously is a 'trampler', so it is less strange there (and the locust squares were generated from the XBetza move). But since all these capture are all implicit side effects, it is silly they would have to be clicked at all. Perhaps there should be a third class of pieces ('burners'), that can only be defined by the user, which would then autocomplete after origin and destination are clicked.
There are times I think you are a magician, HG!

There is something wrong with the diagram for Desert Pub Chess. When the AI moves, it seems to spuriously remove pieces from the board in unpredictable ways. Furthermore, this bug also affects the desert pieces, causing them to not capture properly when they capture more than once.
Normal Move Bug Replication
Move each pawn forward one at a time, you should see the opponent's pawns add locust squares (the dull red highlights) when moving. Eventually the AI will make a Knight move that removes a friendly pawn.
Desert Piece Bug
Make the following moves manually:
1. e2e4 f2g4 2. Fc8d5
Then open the AI dashboard and move a white piece. You will see some very strange behavior (only one white pawn gets captured and the other is "moved" to a different square).

There is something wrong with the diagram for Desert Pub Chess.
This is fixed now. (Flush browser cache!) I had already fixed a similar bug in the betzaNew.js. Actually it was two bugs. One that it used the last square in the move array as the center of a burn, while the destination is always the second square. This only manifests itself on moves with locust squares.
The more subtle bug is why it would think it has to burn here at all. This was because the 512 bit in the promotion code that is used to request burning is used in the on-board pieces to indicate the piece is non-virgin. At some point the 512 bit in a promotion code has to be translated into extra locust squares, and normal promotions have to get ther 512 bit set to prevent they have their initial moves. This is done just before execution of the move, in the routine that calculates the score gained by the move. The problem was that the moves obtained from the AI have already been performed once, during the search. While for moves entered by clicking this still have to be done after the move is selected. The result was that moves from the AI were scored twice. So that a normal promotion got its 512 bit set the first time, and the second time than made it into a burn. And the Pawns appeared because some of the burn squares were actually empty, which for locust squares is interpreted as an unload of teh captured piece...
@ Aurelian
Off-Topic, a quick question:
Have you looked at the following link in the past (hopefully extensively) when searching for CVs to play on Game Courier at some point in time? - I'm thinking if I have preset(s) out there, one day, that haven't been published, maybe, hopefully, there's at least a small chance people might find them by using this link (if not my personal Settings files link). That's since I have a large backlog of ideas for CVs that might take ages to publish:
I have not looked there in a while! Why do you ask?

I now improved the piece-value guessing of the Diagram. This used to be based on the 'raw' moves delivered by the move generator, as specified by the XBetza notation. But now that user scripts can add locust victims, either directly or through a promotion code that requests burning, it has become important to first subject the move to this script before determining its power. Before, the values of the Ultima Pincher Pawn, Coordinator and Immobilizer were estimated as next to nothing, because the guessing only saw the mR or mQ part, and the Chameleon was given the same value as the Long Leaper (because the XBetza description was the same, and it did not realize that the leap-capture part was restricted to capturing Long Leapers only).
Guessed values based on the 'cooked' moves were much better; only the Immobilizer was still considered worthless, as even the cooked move never has any captures. So I added an ad-hoc bonus for a piece that puts a spell on its neighbors: 1000 for freezing, 600 for charming and 300 for burning. This makes the Immobilizer the most valuable piece in Ultima. (Which I believe it should be.) The Chameleon might still be underestimated, as no account is taken of the fact that it can freeze an Immobilizer. (Which of course has the repercussion that it then also gets frozen itself. But since the Immobilizer is worth more, this should be worth something to the Chameleon.)
I wonder if I should also support an opportunity for affecting the evaluation through a user script (say xxxEval()). Of course there is already the value=N parameter, which can be used to tune individual piece values. But the current evaluation doesn't take into account whether pieces are frozen. It might be very hard to program something sensible for this, though.
Hi Aurelian. I'm glad you have looked at that link (more than once, presumably) in the past. I meant to say I was pondering about making settings files/('unofficial' presets) for many CV invention ideas of mine, which I was thinking of not trying to publish at least for a while longer. I thought you might be a typical user of CVP site in some ways, so I asked you about the link (featuring a list of possibly played presets on GC) since I know you, and you are paying attention to the present thread (sorry my post is off-topic again).
I was hoping by people (e.g. one being me) playing at least one game with a given 'unofficial' (that is, unpublished) preset of mine, that preset might have at least a slim chance of being stumbled on by someone using that link I just asked you about (then such a someone could play or popularize said CV of mine, if I never got around much to either). Slim chance, yes, but better than if I just left said preset as an unplayed Settings File of mine (people might have an even slimmer chance of finding it that way, I thought, even though I am a known inventor). Publishing presets (plus rules pages) would be best, but that could take ages since for one thing I have over 20 CV invention ideas of mine stored away since 2019 (e.g. there was a limit of 9 submissions at a time [including a given preset or rules page] suddenly introduced during that period - so I just kept letting my ideas pile up).

I changed the name of the parameter to specify burning or freezing from curse into spell, and added parameters spellZone and blastZone. The latter can be used to define the area on which the spell (e.g. passive burning) and the active burning works, relative to the tracked or moving piece. They can be given the value K (the default), W, F or N.

Does trackPieces=N track the pieces around pieces of type N if spell is not set?

Yes, non-zero track always keeps track of the coordinates of all piece types, and type N is special by the adjacent squares getting the 'nodes' mark in the 'neighbor' array, so the user can test it, and do whatever he wants with moves that touch the spellZone in some way. Defining a spell only makes the corresponding action already performed by the Diagram script itself.
I guess I should add some more spell flavors: protect could make pieces standing in the spell zone uncapturable. And hide could make them transparent, allowing any piece to hop over them..

That's a really nice feature. For example, it saves a huge amount of time in the diagrams for Suzumu Shogi and Mitsugumi Shogi from not having to check nearly as many locations for Heavenly Tetrarches (which which immobilize non-Tetrarch pieces) during move vetting. I've now implemented the new code in the Rules pages for these games.
Also, can you approve the Rules pages for Suzumu Shogi and Mitsugumi Shogi? I've been waiting rather patiently, and their corresponding GC Preset pages have been approved, but the editors haven't seemed to notice the Rules pages, possibly due to the new sorting method for the Review New Submissions page.

Also, can you approve the Rules pages for Suzumu Shogi and Mitsugumi Shogi?
I don't know how to approve articles; I limit my activities as editor to inserting Interactive Diagrams in existing articles, and improving the infra-structure for doing this. I am the only editor working on this task, and it doesn't seem a good idea to reduce the time I can spend on it by also taking up tasks that other editors can do.

I don't know how to approve articles; I limit my activities as editor to inserting Interactive Diagrams in existing articles, and improving the infra-structure for doing this. I am the only editor working on this task, and it doesn't seem a good idea to reduce the time I can spend on it by also taking up tasks that other editors can do.
That's OK. I assume you passed that along to another editor, and they approved it themselves.
25 comments displayed
Permalink to the exact comments currently displayed.
Unfortunatey a general t modifier is a bit hard to implement. Which is a pity, as with the unload modifier it would make it possible to describe magnetic pieces and catapult pieces.
So for now I added capture of pieces adjacent to the destination as a standard feature, controllable through the capture matrix and from WeirdPromotion(), as internally it uses the promotion element of the move array to trigger it. An @ in the captureMatrix orders promotion to piece number 512 for that particular combination of attacker and victim (wher the latter can also be an empty square). Now this is an invalid piece number, and used as a kludge to indicate 'burning'. How exactly this burning works depends on a new parameter atomicCapture=N. For N=0 it does Tenjiku-type burning: only enemies get burned, and the capturer survives. For larger N is gives you explosion like in Atomic Chess: all adjacent pieces are destroyed, friend and foe alike, but the first N piece types from the table survive, while the capturer always selfdestructs.
Now this works the same when you return 512 from WeirdPromotion(). But you have additional control there. By returning 512+C (0 < C < 256) you also trigger the burning. But in that case it burns only the squares selected through the bits of C, where 1 = N, 2 = NE, 4 = E, 8 = SE, etc. So WeirdPromotion() could do additional testing on the board to decide whether an adjacent piece should be burned or not. This could for instance be used to implement Ultima Pincher Pawns, by checking whether there is a friendly piece behind the adjacent one.
All this only works with newClick=1, which unfortunately means that the move diagrams (using the old highlight code) would not show the burning. It is not easy to cure that, as the move generator doesn't know about it (as far as that it is just a promotion), and no clicks on the burn victims are required . (During hovering over the move diagram the highlighting is as if the hovered square had received the second click, and it shows where the third can go.)
BTW, I now added a link to the Extended Betza article.