OK, I see why it didn't work: Instead of downloading the file I had copy-pasted the text on the into Notepad, and saved that. But then I had to pick the filename myself. In the file-browse dialog that opens upon pressing Load, the file-type pulldown was by default set for *.js files. So I saved it with .js extension. But then I never saw the file, only folders.
Turns out the pulldown did not say .js, but .json, but that the "on" part was clipped off because of the button width. When it had .json extension as in the downloaded one, I had no trouble loading it into Jocly. I still haven't figured out how I could view the entire game, other than playing it in reverse through takebacks. But at least I can see the final position where the trouble manifests itself.
I think the problem is that Jocly's test for being in check (through base-model's cbCollectAttackers function) cannot see attacks through burning or area moves. So it happily plays on in this checkmated position. Which in the look-head by the AI of course leads to the King being captured. The Jocly code chokes on that, because it assumes that a King is always present. It keeps track of where it moves, but that tracking is left at the square where it was last seen before it got captured. But that square is then empty (code -1 on the board), and when it tries to update the hash key for a piece of that type it gets out of bounds in the Zobrist table, as -1 is not a valid piece type, so that no keys were defined for it.
The playing-on seems acceptable here, as officially Tenjiku games do not end by checkmate but by King capture. (Purists might complain that with normal checkmates, not involving burning or area moves, which Jocly does recognize, it really terminates the game one move too early.) That it then crashes is of course not acceptable. The pullreq branch contains a commit that fixes that; the evaluation in base-model now tests for presence of the King, and considers its absence a game-terminating condition as well. That prevents further processing of positions without King, and thus the crash. But of course the version you are playing here is not based on the pullreq branch. The tenjiku-chess-model.js still contains the original base-model.js. I could of course hack the patch for detecting King absence in there.
This touches on an issue that has bugged me from the beginning; the Jocly AI really is an extremely inefficient search engine, as far as chess engines go. Michel coding skills in JavaScript are uncountably many leagues above mine, but he obviously is not an engine programmer. The largest flaw is that in the search he generates legal moves only. This has enormous computational cost, as he does it by playing all pseudo-legal moves one by one, then looking with cbGetAttackers whether the King is under attack, and taking the move back. And then delete the move if it was illegal.
The point is that normally only a very small fraction of the moves puts your own King in check. So most of the time the test for this was a waste of time; the move is legal and you have to try it anyway to get its score. Almost all chess engines therefore use pseudo-legal moves in their search; if they occasionally try an illegal move the opponent will see he can capture the King, which gets maximum score, so that the illegal move will have maximum negative score, and would be discarded. On most moves this would not happen, and you would have saved the time for separately testing whether the move was legal; even in cases where the move was illegal it is a question of whether detecting that by letting the oponent generate all his pseudo-legal moves, than by using the dedicated check test.
Now the problem is that this cbGetAttackers function can get horrendously complex in a game with unconventional pieces. It works by reversely tracing all paths in the move graphs of all pieces that visit the square, to see if it finds the corresponding piece at the origin of that path. To this end it initializes a ThreatGraph, which combines these reverse paths into a tree (so that coinciding parts just before they hit the King only have to be traversed once). If you are dealing with orthodox Chess there might be some merit in this; you only have to deal with Knight jumps and Queen slides, the latter quickly finding an obstacle in their path when you step through them from the King, during most of the game. But even then the case for the Knight is dubious: you would have to test 8 squares around the King for Knight presence. The alternative method of just generating all opponent moves would make you generate 8 moves for each Knight, to test for King presence. If the opponent has two Knights, that is indeed twice as much work. But if he has none...
The point, however, is that when the variety of moves in the variant gets larger, this threat graph gets unweildly large. If Xiangqi Cannons participate, you cannot stop tracing the reverse path at the first obstacle, but will have to look beyond it for Cannons. If Tenjiku-style jumping generals participate, you have to trace the Queen moves all the way to the board edge. If Griffons participate you have to follow paths around corners. Camels, Zebras, Antelopes each give you 8 extra squares around the King to test. Before you know it, you have to test almost any square on the board for presence of a particular piece. And when you don't keep track of which pieces are stil present, (as Jocly doesn't), you have to keep doing that for the entire game, even if the pieces that could make these strange moves are long gone.
I think the Jocly AI would benefit enormously by just abandoning this legality testing, and let it search until King capture, the huge value assigned to the King taking care of the illegal moves never being preferred. For testing the legality of the user's move it would remain essential to do it, though. So there should be a way to let cbGenerateMoves know whether it is generating for the AI's search, or for highlighting user input moves; in AI mode it could then just return the cbGeneratePseudoLegalMoves result, and do away with this costly cbQuickApply / cbGetAttackers / cbQuickUnapply loop.
Another silly design characteristic is that the material scoring in the evaluation fuction is done by looping over the entire board to add up the value of all pieces it finds there. This is something that can very cheaply be updated incrementaly, by just subtracting the value of pieces that get captured in cbApplyMove. It already does such incremental updating for the hash key zSign, so why not for the material score? Same for counting pieces of each type. This really makes Evaluate orders of magnitude slower than it could be.
OK, I see why it didn't work: Instead of downloading the file I had copy-pasted the text on the into Notepad, and saved that. But then I had to pick the filename myself. In the file-browse dialog that opens upon pressing Load, the file-type pulldown was by default set for *.js files. So I saved it with .js extension. But then I never saw the file, only folders.
Turns out the pulldown did not say .js, but .json, but that the "on" part was clipped off because of the button width. When it had .json extension as in the downloaded one, I had no trouble loading it into Jocly. I still haven't figured out how I could view the entire game, other than playing it in reverse through takebacks. But at least I can see the final position where the trouble manifests itself.
I think the problem is that Jocly's test for being in check (through base-model's cbCollectAttackers function) cannot see attacks through burning or area moves. So it happily plays on in this checkmated position. Which in the look-head by the AI of course leads to the King being captured. The Jocly code chokes on that, because it assumes that a King is always present. It keeps track of where it moves, but that tracking is left at the square where it was last seen before it got captured. But that square is then empty (code -1 on the board), and when it tries to update the hash key for a piece of that type it gets out of bounds in the Zobrist table, as -1 is not a valid piece type, so that no keys were defined for it.
The playing-on seems acceptable here, as officially Tenjiku games do not end by checkmate but by King capture. (Purists might complain that with normal checkmates, not involving burning or area moves, which Jocly does recognize, it really terminates the game one move too early.) That it then crashes is of course not acceptable. The pullreq branch contains a commit that fixes that; the evaluation in base-model now tests for presence of the King, and considers its absence a game-terminating condition as well. That prevents further processing of positions without King, and thus the crash. But of course the version you are playing here is not based on the pullreq branch. The tenjiku-chess-model.js still contains the original base-model.js. I could of course hack the patch for detecting King absence in there.
This touches on an issue that has bugged me from the beginning; the Jocly AI really is an extremely inefficient search engine, as far as chess engines go. Michel coding skills in JavaScript are uncountably many leagues above mine, but he obviously is not an engine programmer. The largest flaw is that in the search he generates legal moves only. This has enormous computational cost, as he does it by playing all pseudo-legal moves one by one, then looking with cbGetAttackers whether the King is under attack, and taking the move back. And then delete the move if it was illegal.
The point is that normally only a very small fraction of the moves puts your own King in check. So most of the time the test for this was a waste of time; the move is legal and you have to try it anyway to get its score. Almost all chess engines therefore use pseudo-legal moves in their search; if they occasionally try an illegal move the opponent will see he can capture the King, which gets maximum score, so that the illegal move will have maximum negative score, and would be discarded. On most moves this would not happen, and you would have saved the time for separately testing whether the move was legal; even in cases where the move was illegal it is a question of whether detecting that by letting the oponent generate all his pseudo-legal moves, than by using the dedicated check test.
Now the problem is that this cbGetAttackers function can get horrendously complex in a game with unconventional pieces. It works by reversely tracing all paths in the move graphs of all pieces that visit the square, to see if it finds the corresponding piece at the origin of that path. To this end it initializes a ThreatGraph, which combines these reverse paths into a tree (so that coinciding parts just before they hit the King only have to be traversed once). If you are dealing with orthodox Chess there might be some merit in this; you only have to deal with Knight jumps and Queen slides, the latter quickly finding an obstacle in their path when you step through them from the King, during most of the game. But even then the case for the Knight is dubious: you would have to test 8 squares around the King for Knight presence. The alternative method of just generating all opponent moves would make you generate 8 moves for each Knight, to test for King presence. If the opponent has two Knights, that is indeed twice as much work. But if he has none...
The point, however, is that when the variety of moves in the variant gets larger, this threat graph gets unweildly large. If Xiangqi Cannons participate, you cannot stop tracing the reverse path at the first obstacle, but will have to look beyond it for Cannons. If Tenjiku-style jumping generals participate, you have to trace the Queen moves all the way to the board edge. If Griffons participate you have to follow paths around corners. Camels, Zebras, Antelopes each give you 8 extra squares around the King to test. Before you know it, you have to test almost any square on the board for presence of a particular piece. And when you don't keep track of which pieces are stil present, (as Jocly doesn't), you have to keep doing that for the entire game, even if the pieces that could make these strange moves are long gone.
I think the Jocly AI would benefit enormously by just abandoning this legality testing, and let it search until King capture, the huge value assigned to the King taking care of the illegal moves never being preferred. For testing the legality of the user's move it would remain essential to do it, though. So there should be a way to let cbGenerateMoves know whether it is generating for the AI's search, or for highlighting user input moves; in AI mode it could then just return the cbGeneratePseudoLegalMoves result, and do away with this costly cbQuickApply / cbGetAttackers / cbQuickUnapply loop.
Another silly design characteristic is that the material scoring in the evaluation fuction is done by looping over the entire board to add up the value of all pieces it finds there. This is something that can very cheaply be updated incrementaly, by just subtracting the value of pieces that get captured in cbApplyMove. It already does such incremental updating for the hash key zSign, so why not for the material score? Same for counting pieces of each type. This really makes Evaluate orders of magnitude slower than it could be.