Thank you for your donations!   Download the book!   Public source code repository   Join the group!

Even more guessing!

Previously, I wrote down my guesstimates how much One variant is more complex than Classical Chess, turns out a lot. Now, it's time to do the same for new, simplified variants. I'll do just Classical Chess 26, smaller variants are of lesser interest here. As for Croatian Ties variants, I haven't yet got around how to calculate complexity factor due to increased mobility; so, using previous method Croatian Ties variants would have exactly the same complexity as their Classical Chess counterparts, which doesn't feel right, but it is what it is.

If you haven't already, read blog post linked above; it explains how complexity factors are calculated, and why. So, let's start with size:

cf size = 1 + ln ( 26 2 8 2 ) = 1 + ln ( 676 64 ) = 3.357310

Next, it's total number of pieces on the chessboards:

cf pieces = 1 + ln ( 104 32 ) = 2.178654996

There are no new pieces, so complexity factor for different types of pieces is one:

cf types = 1 + ln ( 6 6 ) = 1.0

The same applies to Croatian Ties variants, since every Knight is replaced by Pegasus, so there are the same number of different types of pieces.

There are also no new interactions, so complexity factor also goes to one (this one too applies to Croatian Ties variants):

cf interactions = 1 + ln ( 3 3 ) = 1.0

Our complexity c is then defined as a product of all factors calculated above:

c regular = cf size cf pieces cf types cf interactions = 7.314420189

This is complexity scaling factor of regular games from Classical Chess into Classical Chess 26 variant, i.e. all games should be 7.314 times longer. For instance, the longest recorded tournament game was 538 moves (269 FIDE moves, aka cycles), which turns into 3835 moves (1968 cycles) for Classical Chess 26 variant. Average on-line match lasts about 80 moves (40 cycles), in Classical Chess 26 variant that would become 585 moves (292.5 cycles). Average tournament match lasts about 88 moves (44 cycles), which becomes 644 moves (322 cycles).

The same, however, does not apply when calculating maximal possible game length, because players will try to maximize each and every metrics available to prolong the game. So, for maximum game length we have to calculate linear scaling factors; for chessboard sizes factor becomes:

cf size = 26 2 8 2 = 676 64 = 10.562500

Next, for total number of pieces on the chessboards we have:

cf pieces = 104 32 = 3.25

Complexity number for different types of pieces is still one:

cf types = 6 6 = 1.0

Finally, complexity factor for number of different interactions is also one:

cf interactions = 3 3 = 1.0

Taken together, our complexity c becomes:

c longest = cf size cf pieces cf types cf interactions = 34.328125

This is scaling factor for the longest possible games, i.e. the longest games should be 34.33 times longer in Classical Chess 26 variant compared to Classical Chess. For instance, previously mentioned 11797 moves (5898.5 cycles) game as the longest possible with 50-cycle rule in Classical Chess 26 variant becomes 404,968 moves (202,484 cycles) game. Even longer 17697 moves (8848.5 cycles) game with 75-cycle rule in Classical Chess 26 variant turns into 607,505 moves (303,752.5 cycles) game.

These doesn't appear to be large numbers, if you recall estimates for One variant, but should not be underestimated; even "just" 7.314 times increase in complexity results in some prolonged games, especially if increase in complexity is allowed to also translate into longer time allowance per turn. So, 15 seconds per player's turn in bullet game now becomes approx. 110 seconds per turn; given that average Classical Chess 26 game length would be 585 turns, it would last for approx. 17.834 hours of gameplay time; or, 2.23 days if we assume 8-hour gameplay in a day. If we don't increase time allowance per turn, 15 second per turn bullet game would take approx. 2.438 hours of gameplay time.

In short, new Classical Chess variants does pose a challange, even if only just by scaling up. Croatian Ties variants builds more on top of that challenge, by replacing Knights with more mobile siblings, and also allowing Pawns to move sideways, which throws off known gameplay patterns, tactics.

New variants finished!

Well, that was surprisingly quick, but all new variants are done, including Summary. To be fair, I was  being overly cautious, thinking of what took me to finish Miranda's Veil. Turns out, simplified variants are simple, most additional stuff (in Summary) has already being done, and just needs a little edit, here and there.

Since new, simplified variants are quite a chunk, I'm also updating the book; changes include:

  • fixed displacement notation examples
  • fixed side-effect summary spacing
  • fixed typos (thanks to @RainRat)
  • new Classical Chess 14, 20, 26 variants
  • new Croatian Ties 14, 20, 26 variants
The book was compiled on September 8, 2025, version is 20250908.191123, and can be found behind that red button above, or in other usual places.

New variants!

Quite some time ago I wrote that I'd like to add some enlarged, but otherwise Classical Chess variants, but dismiss them as not belonging to the book, and requiring their own, separate book which would also discuss mobility. In the meantime, I kinda warmed-up to the idea that enlarged Classical Chess variants do belong to the book presenting new variants, especially since their objective is to make playing on large chessboards more approachable to average, casual player.

Currently, I plan on adding enlarged Classical Chess and Croatian Ties variants as remarks at the very end of the book; those variants won't be fully featured, but will include images. I'm not entirely happy with this design choice, since it will disrupt the flow of the book; but it should be worth it, given that this new book on mobility and such is still very far away, if it will be written at all.

I plan on adding 3 new Classical Chess variants, those will feature only pieces found in Classical Chess, with exactly the same rules, except longer rushes and castlings. I'll also add 3 new Croatian Ties variants, those would be nearly identical to their Classical Chess counterparts, but all Knights would be upgraded to Pegasuses (Pegasi?), and all Pawns will be of side-ways variety; this is to compensate somewhat for decreased mobility of Pawns, Knights on a larger chessboards. New variants will be played on 14 x 14, 20 x 20 and finally 26 x 26 chessboards.

New variants won't bring neither any new pieces, nor any new interactions. Still, I'll have to expand Python application which generates images for the book to support all new variants; later, library will have to be expanded as well. This will take some time, given my usual tempo of writing (which is very slowly) I hope I'll have the book finished by the end of this year.

Join us at LinkedIN

As is a standard trope with older (software) engineers, I'm also bad at socializing, online and off. It's not that I'm internet illiterate, quite the opposite, but somehow casually connecting with strangers is one of my Achilles' heels. Maybe the issue is that I grew up in an disjoint world where each and every service stood only on its own, and rarely had been linked to another. Or, maybe it's that I value privacy, but data gathering and profiling is so prevalent that I have no desire to engage.

Anyway, here it is: a link to Croatian Chess group at LinkedIN; it's still a small, cozy group, with even smaller amount of posts (hey, if you join, you could improve things!). Usually I post when there is something new or relevant to Croatian Chess; usually it's about the most recent blog post. The group itself is not dedicated strictly to Croatian Chess; all posts about all chess variants, and chess in general are welcome, memes included. If you join, please avoid controversial topics like politics, religion or any other ragebaity content; there are plenty of those elsewhere.

Thank you for joining!

One step at a time

I changed how Pawn-sacrifice is initiated, by limiting Serpent to its neighboring fields. As a consequence, Pyramid is now activated with only one momentum, so sacrificing Pawn is also limited to only one step. While change itself is rather small, and it applies to only one special movement, there are a few design choices worth pointing out.

The issue with Pawn-sacrifice was that one could lose quite a few Pawns, and in turn have promotion opportunities severely limited or completely gone, all in only one move. Also, in its original form, Serpent could initiate Pawn-sacrifice by activating Pyramid from across a chessboard. It was also possible for a Serpent to slither around pieces and still find a way to its own Pyramid. Similarly, Pyramid activated with a lot of momentum could sacrifice Pawn at the other side of a chessboard.

In my defense, when Pawn-sacrifice was originally conceived, Serpent's movement was much more limited, up to 9 fields in the largest variant, 8 otherwise. In the mean time, I extended Serpent's reach, but failed to notice its impact on Pawn-sacrifice. By limiting Serpent to its neighboring fields, one now has at least some warning signs (Serpent, Pyramid and Pawn placed close to each other) what is about to happen, and an opportunity to counteract that kind of a move.

I'm also updating the book, Pawn-sacrifice is the only meaningful change. The book was compiled on July 29, 2025, version is 20250729.034138, and can be found in other usual places.

Remove the rule, update the book

I have removed the rule which stated that the first piece in a move cannot return to its initial position, regardless if it was the only piece in a move, the first in a cascade, or in divergence. Since this is a major change I'm also updating the book, the other changes include:

  • clarified double checkmate, added notation and status grammar,
  • reworded Starchild intro,
  • clarified castling notation, fixed grammar,
  • clarified optional notation, fixed outro,
  • reorganized sections, 
  • fixed formatting in tables, 
  • other tiny fixes.

If the rule stayed, it would actually mean that all pieces would have to be uniquely tracked, which would mean that each piece would have to be assigned unique number at a start of a match, and then for everything else it's type and tag would have to be fetched from look-up-table. This would lead to a major  shift of underlying API in a library; but more concerning, also in paradigm shift, where chessboard wouldn't host pieces anymore, but their unique identifiers. This change would be even more of a tectonic shift than the previous one; doable, but got me thinking; is it really worth it, why did I impose such a rule, and such.

For one, it wasn't a movement rule per se (belonging to any particular piece), but it was a restriction imposed on a movement rules of all pieces. As such, it doesn't belong in the book, but among other FIDE or tournament rules. More specifically, any piece starting a move cannot do anything more than just to initiate a permutation of Waves, if that starting piece is about to return onto its initial position in the same move. What I overlooked is that permutation necessary leads to repetition of positions, and that has already being handled by FIDE; for instance, see FIDE 9.2 point in FIDE Handbook.

Another reason for the removal of the rule is physicality; all pieces of the same color and type look the same; this is especially true if displayed on-screen, on a web site, or in a computer game. And yet, the rule called for recognizing (and accounting for) that one specific e.g. dark Rook which started a cascade vs. the other(s) which did not. Of course, computers can be programmed to distinguish those easily; however, a player would have hard time tracking which dark Rook is which, especially in a long-winded cascade.

In short, the above rule would be difficult to implement, goes against a physical reality of a game it tries to regulate, and there is already available better, easier alternative; so, no wonder it has been removed.

Anyway, the book was compiled on June 6, 2025, version is 20250620.014531, and can be found behind that juicy red button above, or in other usual places.

Guessing game

Merging pieces and tags mentioned in a previous post have gone much smoother than I expected, and it's finished now. I also wrote in that post my estimates how long a game in the largest variant could take. In the meantime I have revised my estimates, and so I present you with bigger, better numbers. Again, these are very rough guesstimates, it's difficult to even assess how much numbers presented here could deviate from real-world matches; in short, those shouldn't be taken too seriously.

Estimates here are based on the fact that most large, complex systems settle its metrics somewhat in the middle, since most extremes tend to cancel each other out. For this analysis we'll be comparing easy to calculate metrics such as:

  • size of a chessboards,
  • count of all pieces in a variant,
  • number of different types of pieces,
  • number of possible interactions,
and will be comparing One variant against Classical Chess. For each metrics we'll calculate its contribution to overall complexity, then multiply them all together, since they are all (mostly) independent; although, total number of pieces is always larger than number of different piece types.

All complexity factors have the same form, so let's define generic complexity factor cf as a simple ratio between new (n) and old (m) metrics, like so:

cf = n m

Edit: with provision that nm.

This definition is all well and good, but applies only if corresponding metrics contribute to system's complexity directly, in a linear fashion. Most of the time, this is not the case. For instance, adding two ranks and files to a classical chessboard is a much larger change (as a percentage) then adding the same to the second largest variant, Discovery. So, each increase in metrics yields diminishing increase in complexity; for such a non-linear increase there is a function which sets limits to growth, and that's natural logarithm (ln):

cf = ln ( n m )

There is still a small issue to solve here, before calculations can take place. Observe what happens if we compare e.g. Classical Chess with its own self:

cf = ln ( m m ) = ln ( 1 ) = 0

Our complexity factor cf gets to 0. This is actually fine, all that calculation is showing us is that there is no additional complexity when comparing a variant to itself. Still, we'd like to multiply our complexity factors, as independent variables should be. So, we'll add 1 to formulae, like so:

cf = 1 + ln ( n m )

Now that we have generic formulae for complexity factors sorted out, we can actually calculate something; lets start by comparing sizes of chessboards:

cf size = 1 + ln ( 26 2 8 2 ) = 1 + ln ( 676 64 ) = 3.357310

Next, we can compare total number of pieces on the chessboards:

cf pieces = 1 + ln ( 190 32 ) = 2.781288

Another comparison is between number of different types of pieces:

cf types = 1 + ln ( 18 6 ) = 2.098612

Finally, we can compare number of different interactions:

cf interactions = 1 + ln ( 19 3 ) = 2.845827

Our complexity c is then defined as a product of all factors calculated above:

c regular = cf size cf pieces cf types cf interactions = 55.767104

This is actual length scaling factor of regular games from Classical Chess into One variant, i.e. all games should be 55.767 times longer. For instance, the longest recorded tournament game was 538 moves (269 FIDE moves, aka cycles), which turns into 30002 moves (15001 cycles) for One variant. Average on-line match lasts about 80 moves (40 cycles), in One variant that would become 4461 moves (2230.5 cycles). Average tournament match lasts about 88 moves (44 cycles), which becomes 4907 moves (2453.5 cycles).

The same, however, does not apply when calculating maximal possible game length, because players will try to maximize each and every metrics available to prolong the game. This can be seen in Classical Chess games alone; the longest possible game with 50-cycle rule is 11797 moves (5898.5 cycles), while with 75-cycle rule it's 17697 moves (8848.5 cycles). If we calculate ratio between the two rules:

75 50 = 1.5

and game lengths, we can see that contribution to game length by rules extension was almost perfectly linear (50% increase in movement rule resulted in 50% longer game):

17697 11797 = 1.500127151

So, for maximum game length we have to calculate linear scaling factors; for chessboard sizes factor becomes:

cf size = 26 2 8 2 = 676 64 = 10.562500

Next, for total number of pieces on the chessboards we have:

cf pieces = 190 32 = 5.937500

For number of different types of pieces we get:

cf types = 18 6 = 3.000000

Finally, we can calculate factor for number of different interactions:

cf interactions = 19 3 = 6.333333

Taken together, our complexity c becomes:

c longest = cf size cf pieces cf types cf interactions = 1191.582031

This is scaling factor for the longest possible games, i.e. the longest games should be 1191.58 times longer in One variant compared to Classical Chess. For instance, previously mentioned 11797 moves (5898.5 cycles) game as the longest possible with 50-cycle rule in One variant becomes 14,057,093 moves (7,028,546.5 cycles) game. Even longer 17697 moves (8848.5 cycles) game with 75-cycle rule in One variant turns into 21,087,427 moves (10,543,713.5 cycles) game.
Edit: all this without resurrections, with those used it's -for all we know- infinite.

These are all very large numbers, even "just" 55.767 times increase in complexity results in some ludicrous (as in, almost completely impractical) estimates. For instance, increase in complexity should also translate into longer time allowance per turn, simply because there is so much more stuff a player has to handle. So, 15 seconds per player's turn in bullet game (10 minutes, spread over average of 40 turns per match, see https://en.wikipedia.org/wiki/Time_control#Classification) now becomes approx. 13.941776 minutes per turn; given that average One game length would be 4461 turns, it would last for approx. 1036.5710456 hours of gameplay time; or, 129.5713807 days if we assume 8-hour gameplay in a day. If we don't increase time allowance per turn, 15 second per turn bullet game would take on average 18.5875 hours of gameplay time, or 2.3234375 days with the same 8 hours of gameplay per day.

And that's just bullet, lets not talk about classical time controls here, those numbers would be depressingly huge. One thing that is sorely missing from complexity estimate is mobility, and associated with it, piece powers. These are not easily estimated; also, increase in mobility alone does not add to complexity, rather it's ratio between mobility and available space (i.e. chessboard size), and I'm not sure that ratio has been increased by much. Anyway, this post is already too long, so I'll leave it for some future post.

Tectonic shift

It's unusual to have very base data model change this late in a project; any yet, here we are. Currently, I was implementing generators of all legal paths every piece can make in a ply. Since this change will disrupt development for quite some time, let me try to explain it.

The issue I'm talking about is that currently piece and tag enumerations are separated; which would be fine in almost all designs, since most of the time one data entity is indeed independent from any other, e.g. one person's year of birth is very separated from their phone number. This is not the case here, Bishop can never get "can rush" tag, nor Knight can ever castle.
Edit: Tags and pieces have very few, and very intimate relationships; usually tag can be attached to a few pieces (e.g. rush and en passant tags for privates). Technically, tag is a link between a piece and a field at which that piece is located. Once that link is broken (e.g. a Pawn has been activated and moved away), there is no more tag present (e.g. activated Pawn has lost its promotion tag) even if both a piece and its originating field are still present in a game. Most of the time the best data model is the one designed after real-life; this is why original design featured tags separated from pieces. 

Another issue with separated piece and tag enumerations is that, well, they are separated. So, every function working with pieces (and in a chess game that means all of them) has to have two separate parameters. Yes, you can combine then in a neat struct, together with some other bits (e.g. a position) to bring number of parameters down; but, they both are now present in every struct you have to pass around.

Plus, they still take too much space, in fact, twice as much as needed; and that's after a change has been made quite some time ago, so that only 1 byte (char) is stored per enumeration instead of default 4 (enums are just fancy ints). You might think that we have moved past storage issues since like forever, but that is true only for local apps. For libraries, one has to consider possibility that it might serve many users at once, also it might need to do it on a restricted hardware (e.g. micro-controllers).

There is another issue with enumeration storage, and that's space it takes in a chessboard struct; again, currently it's double the amount it actually needs. Parsing user notation and applying it to a current chessboard is not an easy task; if undo is supported then one has to apply all moves performed until that point. To speed things up (and avoid doing the same job twice) position after performed move can be stored, and later retrieved. Only problem is, the largest variant has 676 fields, 190 pieces and 14 different interactions (losing tags are not counted, as they're result of interactions), which means it can last much longer than classical chess game. The longest recorded classical chess match in tournament was 269 moves, but legal match can stretch up to 5898.5 moves with 50-moves draw rule, or up to 8848.5 moves if 75-move draw rule is used instead.

For the record, move to me always means all actions performed by one player in one turn; this is different from FIDEs definition used above which define a move as white player action followed by black player action; for FIDE definition I use term cycle. Reason why I refer to move as such is because each player moves their pieces independently to each other (current chessboard position notwithstanding), there is a meaningful choice to be made; in fact, making a choice is the whole point of a game.

So, how long can chess game go in the latest and greatest variant of them all, the One? Honest answer, I don't know. I tried to guess-timate the thing, but it's probably wildly inaccurate. My guess is that tournament games won't last much longer than 18.000 moves, and technically legal games could probably go for 10.000.000+ moves; both with 50-cycle draw rule. This post is already too long, if you're interested to hear my reasoning, let me know in comments below.

As you can see, if undo is supported by storing chessboards, just having variant enumeration as an int in a chessboard struct can easily eat up to 40+ MB of space, just for that one enum. Undo chessboards could currently use 13+ GB of RAM in total; with changes proposed here implemented, that could drop down to 6.5+ GB. This is why I'll merge piece and tag enums, and also change variant enum storage to byte. Such a change will affect everything in the project; for the time, there will be development without (much) progress.

New book update

I'm updating the book even though less than a month has passed since the previous update; the newest changes include:

  • rewrote checking opponent's King by Serpent,
  • tiny clarification, cascading en passant,
  • filled-in, clarified piece activations table,
  • removed activations on miracle-fields by Starchild, Wave,
  • removed Wave divergence on miracle-fields,
  • a bunch of tiny fixes, clarifications.

In a previous update I planned on making an exception to Wave's transparency, so that King behind it is not in check anymore. That has been revised, and so Wave transparency stays the same, and King behind it is still in check. Due to Shaman being able to capture multiple pieces in a single ply, I had to put forward rule that King is in check if it could be captured, if it was opponent's turn. Then everything else followed from there: if a Wave can be passed over by a piece due to its transparency, then attacker already have direct access to a King; and hence, King is already in check.

I also removed all activations on miracle-fields, except Starchild can still activate a Star. This is due to miracle- and uplifting-fields being the same, so it was hard to determine on-the-spot (when parsing user notation, building legal path, ...) if interaction is just an ordinary activation (on miracle-field), or it's uplifting a piece; because uplifting is a two-stage process, and so activation context has to be passed between plies, before anything conclusive can be known.

The book was compiled on April 2, 2025, version is 20250402.230028, and can be found in usual places.

En passant finally described! And checking opponent's King! More news at 11! Also, the book has been updated ...

I'm updating the book after only two months, since there has been some significant changes, including en passant being thoroughly described, for real. More detailed list of changes follows:

  • fixed side-effects table, added footnote
  • clarified displacement
  • described checking opponent's King
  • clarified static Serpent
  • clarified castling blocked
  • clarified piece actions
  • clarified Scout can be rerouted around any non-empty field
  • described en passant blocked, denied, turned into capture, divergence, ...
  • described activation after en passant
  • described multiple rushes, en passants in a cascade
  • described en passant in close quarters
  • described en passant affected by a Star, Starchild
  • switched to non-shifted tilde
  • and many more tiny edits, fixes, ...

While I was reviewing changes I made to the book since the last update, it also occurred to me that I gave too much leverage to pieces attacking opponent's King. Most pieces grew significantly more powerful, especially in late variants, while King remained the same it ever was, in effect making it much weaker against any opposing force. This is fine, and as it should be; the tricky part here is finding the right balance. This is why I already started changes to limit checks only to pieces directly "in line of sight" of opponent's King, meaning that King is in check only if all capture-fields between an attacker and a King are empty. In hindsight, what happened here is just me always leaning towards giving a player more choices, a piece more mobility; in short, more power for all; sometimes more power is just too much.

I also lean towards doing the same with Wave. Currently, due to its transparency, Wave cannot be hard-pinned to its King. With upcoming changes, Wave on a capture-field would nullify any check to a King behind it. The reason is the same one used to make Pyramid incapable of checking opponent's King, while at the same time that very same Pyramid can capture any other opponent's piece; it is to ensure all checks, checkmates are direct, simple to see, and reason about. It also helps that in doing so, it makes rules (and code implementing them) less fiddly.

It could be argued that transparency of Wave is hard principle, i.e. it should always work like that, without exceptions (which is true), and also that King would be sufficiently protected just by aforementioned changes, without changing Waves (also true). Counter-argument might be that directness of checks and checkmates is also hard design principle, i.e. no pieces between checking piece and checked King. Good game design promotes, and sticks to its own design principle hierarchy. To me, directness of checks, checkmates have precedence over any other rule; which means, transparency of a Wave will have to have an addendum.

I plan finishing changes mentioned here, then continue working on the code; book update will follow its own (give, or take) quarterly schedule. In the meantime, I'm also starting to think about revising One variant, namely Starchild could be reverted to its initial design, where any piece could activate it. Still, this is very low priority, and in very early stage; so, it most likely won't make it in time for next book update.

The book was compiled on March 9, 2025, version is 20250309.071052, and can be found in usual places.

Updating the book!

I'm updating the book, since previous update was three months ago, and there were some meaningful changes, which include:

  • changed reposition symbol to backslash,
  • removed unsupported castling notation examples,
  • added delayed column to variants table, description,
  • removed monogamous promotion,
  • changed draw offer cancelled symbol,
  • clarified resurrecting converted pieces,
  • clarified only captured and oblationed pieces can be resurrected,
  • clarified resurrecting Waves, Starchilds,
  • fixed grammar: Starchild can be activated,
  • and many more fixed edits, typos.

Some of changes were made to ease parsing user notation; for instance, repositioning symbol used to be just comma, which is also used for list of captured pieces during (double) trance-journey. Another example, cancelled draw offer was previously written as (-), now minus sign has been removed from brackets, since it's also used to separate destination from any previous step.

For castling notation, previously one could specify for Rook starting, any or all intermediate fields; now it accepts only destinations, either full position or just a file, optionally preceded by Rook symbol. So, Kh1-d1&Re1 is acceptable notation, but Kh1-d1&Ra1-e1 is not anymore; because King is not transparent to Rook, it's just a very special move. Another reason is that it also simplifies parsing user notation, without losing any valuable information.

I also removed monogamous promotion; after some thinking it was obvious to me that promotion does not add anything to the game, but only complicates things for players, and for no good reason. I thought I had one when I was setting promotion rules, but certain choices doesn't make a good story. I prefer freedom of choice over (unnecessary) rules. There is also a moment when one has to consider simplifying design, when possible. 

The book was compiled on Jan 13, 2024, version is 20250113.203449, and can be found in usual places.

Grepping over history

In a series of posts for a future, forgetful me; today's topic is a way to search for changes in a file content over past git commits. Turns out it's not that easy, it's either a two step process; or, one gets laundry list of every occurrence of whatever is searched for that ever existed.

I opted for two step process; first search for commit IDs of interest, then get files in that commit:

  • git log --grep=<regexp> lists all commits with a message pattern,
  • git log -G <regexp> lists all commits with a content pattern,
  • git log -S <regexp> lists all commits with different count of content pattern (additions vs. deletions),
  • every search can be further restricted to a file (or folder), e.g. git log ... -- path/to/file/.
Now that commit IDs are filtered-out, one can get file by using:
git cat-file --textconv <commit-ID>:path/to/file;  --filters can be used instead of --textconv. I find it more convenient to just dump committed file into a temporary file, like so: git cat-file ... > temp.c, then open said file in a text editor. Every text editor nowadays is aware of external content change in opened files; so, to repeat search with another commit-ID one has to do as little as just dump into the same file. It's also convenient if temporary file has the same extension as committed file, that way text editor can do syntax highlighting, without having to be set manually.

For a laundry list of everything everywhere, one can use git grep <regexp> $(git rev-list --all); the problem is that it's very long, even if restricted to only one file both in grep and in rev-list, like so: git grep <regexp> $(git rev-list --all -- path/to/file) -- path/to/file.

Too much coffee

Since the very last post, I reverted most of the changes to the repository. Too little sleep, and too much coffee will do that to you. You see, I overlooked that out of 8 divergent pieces in the latest variant, 6 are available to any one player, and 4 of those are also transparent. Which means that every single piece in a move (and especially the ones starting a cascade) has to recursively build its path along chessboard, to find out its longest path.

Except, that is not completely correct; generated path for the first piece has to maximize momentum, not its length; and obviously enough, those two things are not necessarily the same. Also, I still need a way to filter out all generated paths according to parsed user notation, since it might contain specific fields visited, and side-effects exerted. And so, I do need a parser; hence revert.

Not all is lost, most of development on now archived branch was also merged back into mainline development; including newly assigned reposition symbol. I also renamed modules storing parsed notation, because those were all too easily confused with modules parsing user notation. Storage for parsed notation (at very least, steps and side-effects) should also be part of generated paths, since paths also has to contain everything encountered on a current chessboard.

Before I delve more deeply into generating paths, I plan to clean-up losing tags, try to resolve TODOs in parse modules, and also have parsing user notation covered with tests. As for tests, one can easily get drown in those, and still fail to test some peculiar interaction. I think, I should give up on testing all of interactions since there are simply too many of those, and cover only the simplest forms.

For instance, I should have one battery of tests just for step separators, the other one just for side-effects, and another still for ply separators, and one for move statuses; each of those should test only one separator, side-effect, status. It might be possible to generate tests based just on a chessboard set-up, and test all interactions that way. However, without a proper way to generate all legal moves for a given situation on a chessboard, it's too early to  think about it.

Early spring clean-up time it is, I guess. And after all of that, on to generating and filtering paths.

Conveyor-belt no more

You might have noticed in the repository that I already scrubbed clean C source code of all kinda working, but not all that useful modules. The problem is that design consists of all special cases, where every special case has its own super-special case; special cases all the way down. Trying to implement this in a super-uniform, context-agnostic code based on a conveyor-belt design is nigh on impossible.

So, this time I'll try different approach, and handle each piece and each interaction separately. Also, instead of trying to implement all of pieces and side-effects all at once, I'll start with one simple case (say, Bishop), and then do everything from parsing notation to applying that parsed ply to chessboard, just for that one piece. In short, finish vertical implementation, before going sideways (except for new Pawns ;). This will also allow for testing full stack before adding more pieces, interactions.

Downside to this approach is that adding each new piece, interaction will also require changes to already existing, and tested, API. Unfortunately, there isn't much I can do about that. Still, slow progress is much better than no progress at all.

Conveyor-belt, you ask? Well, in what seems like eternity, when dinosaurs roamed the Earth Flash-based games on the web were popular, there was one fun and engaging lil' puzzler, even if it featured sometimes wonky physics. So, when objective is to move balls to the other side of a valley, and gain some height in the process, what the most obvious solution immediately comes to mind? Conveyor-belt, of course! It works for sure, it's easy to understand, a bit grindy to implement; but hey, upsides surely outweighs its downsides, right?

If you'd like to try it yourself, here it is. Spoiler alert, conveyor-belt might not be the best solution, and by far.

YouTube strikes again

Don't you love it when your favorite source of entertainment, amusement, even education drops an adorable little note of fr*ck off:

Video unavailable

This video is no longer available because the YouTube account associated with this video has been terminated.

But, copyright claims could be easily resolved without ever terminating anything, or anyone. Instead of meeting every DMCA claim with an axe and bleeding good, quality content in the process, YouTube could just divert any monetization to its proven, rightful owner. If attribution is wanted, YouTube could insert short notice, saying something like "This content is owned by such-and-such copyright holder", and provide link to their web site, or YT channel.

But no; axe very fast, is automated, much law, wow. Look ma, no workers!

Usually, most music for me is just some pleasant background noise, no need to get upset about a particular interpretation, if they are all very similar to each other. This one, however, is part of the book, and it's the most sublime; in comparison, all the others are almost as good, but not quite. Luckily, original poster was kind enough, and persistent enough to already repost missing music.

On the side note, YT seems really desperate to be fishing for phones used by real people:

Verify to do more on YouTube

To add custom thumbnails, verify your phone number. 

BTW, choosing different playlist thumbnail worked in the past. Putting it behind a phone-wall is downright phishy, and sleazy.

The worst part? Google and -by extension- YT already have my phone number, and it's already verified because of 2FA.

MBAs seems all forget that a company has to be useful to own customers if they want their business in the long run, and with as few annoyances as possible. If company is getting more and more annoying, it's also getting less and less useful, and so customers will go to alternatives, no matter how big a company is, and how impossible it might seem to fail. OTOH, we had been in a downward spiral before; now, given that MBAs copy each other, we might be in for another.

Edit: tried to explain myself better.

A new book update

I just finished the most recent changes, and so I pushed a new book update. There are some slight corrections, clarifications, but also conceptual change, and complete activations overhaul. I was comparing activation and divergence, and especially for a Wave, their differences; and it made me thinking: "why activated Wave can move over only one type of field, while diverged Wave can choose any?", "how is this fair?", ... So, I decided to level the playing fields, so to speak, and make all activator's steps, fields accessible to activated Wave.

Now, Wave does not inherit type of field at which it has been activated anymore, and instead it can choose from any of steps its activator can at the beginning of a ply. For the most part, activation works just like it was before, changes are relevant only for activators which have separated step- and capture-fields, like Pawn, and Shaman. For those two, Wave can now choose any movement or capturing step as its initial direction.

I was a little bit concerned about Wave activated by Shaman being OP. But, it's just one new activator, which is still more restricted than the other one OP already present in the game; namely, Centaur. So, in a way, it's more fair, since Centaur is now less of an outlier.

At the moment, I don't have any planned, or outstanding changes for the book; so, I'll say, it's as good as it gets. Of course, it's quite possible that I missed something, that should be corrected. With so many moving parts it's difficult to stay on top of every new version. In any case, if you notice something that looks like discrepancy between various texts, tables, examples, ...; please, do let me know.

I'll take this time between the book and the code, to take some more side-questing, and invest at least a few days to get to know NeoVim better. While I don't like vi, nor any derivatives, and have never been a fan, there is no denying that Pulsar is getting more and more annoying, the more I use it. I'm not sure what Pulsar devs are using, but I'm kinda appalled by the lack of performance on older, although still middle-of-the-road CPU, with plenty of memory. I also tried disabling tree-sitter, heck, even all of auto-complete stack, restarting Pulsar without plugins; all to no avail. I mean, everything works ok if edited file is well under 1k SLOC, otherwise it's a lot of pain. In a 4k SLOC Python file, every edit takes at least a second (!) before editor shows the change. As it is right now, this is not a proper tool for work, it's a toy. Bright, shiny, fairly extensible, beautiful; yet, ultimately, next to useless. Which is a shame, really; I do like it a lot.

Geany, you ask? Well, I did use it, it was good, I kinda liked it; but, after Pulsar, it's like going back to your first bike. Sure, it works, it can make you go places, but it's not the same anymore. For me, it's plan B, if NeoVim does not work for me. Especially since with the newest Geany version (2.0.0) very little has been changed compared to previous stable version, except devs bumped version number, and introduced C++17 dependency. So, it's painful to get the upgrade if your Linux repo is LTS, and it's simply not worth it. All together paint a bleak picture for future development of the IDE.

Anyway, the book can be found in usual places, it was compiled on November 14, 2024, and the version is 20241114.064539.

Gentle sounds of Hilti in the morning

As you might have noticed, last few months were much slower than my usual. As I have announced last year, skyscraper I live in is undergoing major renovation works, even if it's one year late. Company managed to get additional year for works to complete, and now whole building sounds like, walks like and quacks like a busy building site; in short, it is properly noisy in my apartment during any work day.

While I do prefer to work during night, when there are as few distractions as possible, it's still a challenge to get some sleep, or do anything else in such a noisy environment. So, while I'll try to do my best, this mess will probably last for at least a year. Unfortunately, I don't have notebook PC anymore, so I can't even take my work to e.g. library and work from there. Will try to see with friends what can be done ... though, not holding my breath.

Undoing git push

This is just a quick note on how to undo push already made to git repo. This will undo changes to your workspace, local and remote repo.

First, do reset:

git reset --hard HEAD~1

Instead of just resetting last commit (to previous HEAD~1 commit), you can reset e.g. last three by entering HEAD~3, or enter SHA-1 of last-good commit.

Then, force changes from local repo onto remote:

git push --force

Obviously, all changes made to repo after chosen commit will be lost, if they are not in some other branch.

Your colleagues will hate you if you screw their work. Take care!

Pulsar, Pulsar, shining so very, very brightly

... yet ever so very, very briefly.

When it's at its best, Pulsar is so bright you gotta wear shades, it's that good. Its default theme (One Dark) is great, optional Dark One Dark is just gorgeous. Plain and simple project management, as-in collection of files. GUI is uncluttered. Editor split into two panes is joy to use, especially given that split panes aren't supported by many editors, or only in some hybrid form. Add to that a large selection of easy-to-install, easy-to-use plugins.

Things are getting dimmer from here on, I'm afraid. Plugins are mostly leftovers from Atom era, some fail to install, other do not work as intended. While plugin dependencies are handled when installing, they aren't when disabling. For instance, disabling autocomplete-plus also makes otherwise working autocomplete-python non-functional, without any visible clue; and even with "Output Debug Logs" on, I haven't been able to find error message in DevTools console, though it might be buried under the pile. Once installed, there is no telling what dependencies a certain plugin has. So, if I disable open-on-github what will stop working?

Plugin resolution is just by its name, name clashes are also not handled. For instance, if you search for "ctags", you'll find symbol-provider-ctags plugin made by savetheclocktower, with version 0.0.5, and no installs as of yet in package manager, and 55 on website. If you click on said plugin, both in editor and on website you'll encounter the same name plugin, but it'll be the one bundled with editor, made by pulsar-edit, and with version 1.0.0.

Pulsar's worst isn't any worse than any other editor, but leaves you blinded, and befuddled how people who took their time to put sublime "Ignore Whitespace On Current Line" option (in whitespace plugin) could also put fixed syntax highlight list into language-todo plugin. I know it's about managing one's expectations, and not every plugin is ready for prime time; but c'mon, it's not done in C, there are no worries if all strings are properly terminated, or if an array has enough space, lists and dicts  are so very easy, settings are also already persisted.

There are other annoyances, too. One that almost made me rage-quit Pulsar is "Atomic Soft Tabs" (in Editor Settings); until I found the bugger I thought I was getting tab chars, even though I clearly set indents with spaces. Some annoyances are spillovers, terms from Mac. Keyboard shortcuts having +cmd; what's cmd key on a PC? Another one, tab size defaults to 2. Also, what's with tabulation choices, "soft", "hard", "Soft Tabs", and their interactions? If you have to explain them, maybe it's time to rename? Or, better yet, simplify; one reasonable way to handle tabs is in Geany, feel free to copy its design.

There are some idiosyncrasies, as well. What is buffer, and why it's exposed to end-user? Is it a file? What if a file is really large (e.g. 40+ MB), does the equivalence still holds? Is "Find in Buffer" always the same as "Find in File"? Maybe rename it if it is? Or, better yet, implement "Find/Replace in File" that works on files of all sizes, even if only portion of that file is loaded into a buffer?

Also, why "Max Screen Line Length" is even an option? Why very long line can't be displayed as such? Is there a limit scrollable pane can handle? Does it considerably slows down editor? If so, why its numeric field accepts 19-digit numbers? I'd prefer editor to show me the content of a file as-is, with no modifications, except UTC-8 ones.

I could continue rambling, as Pulsar has it's fair share of annoyances and idiosyncrasies; but all editors have, you can only choose which ones you hate the least. Most of Pulsar's annoyances can be solved, others are not relevant to me. In fact, taken just as an editor it's great, and I like it a lot. It's only when I try to hold it by its devs promises ("Hyper-Hackable Text Editor", "Packages make Pulsar do amazing things."), then it comes a bit short. I tried Code::Blocks, CodeLite, Kate, even return back to Geany; in short, it was like a trip down the very bumpy memory lane, all the way back to 90s.

So, the blinky star it is ...

Book update and stuff

I'm updating the book, since previous update is already two months old, even though there aren't that many changes, but then again, there are no reasons to hold them back.

Changes from the previous update include:

  • divided, moved piece actions tables
  • fixed action tables for Pawn, Shaman, Wave
  • described mometum restrictions of actions
  • fixed notation, grammar for double side-effect (promotion + capture)
  • added examples, Pawns (not) blocked by Wave
  • described singe-step pieces and transparency
  • clarified diverging from opponent's Starchild

The book was compiled on July 21, 2024, version is 20240721.112914.

In a bit surprising, unexpected move (pun intended!), last month I decided to convert all of DoxyGen documentation into Sphinx, and also ditch my editor of choice (MS Visual Code, at the time) for something else. This was done mostly on some sort of an intuition, feeling; which is strange, since I'd usually try to do some (strategic) thinking, e.g. "syntax hilight is broken again, for xyz times", "folding comments is borked, again", "editor is getting too slow", ...

Each documentation system has its own strengths and weaknesses, just like everything else in life. I'm already missing DoxyGen warnings when e.g. functions parameters do not match content of a C file. Also, with DoxyGen, it's immediately clear what is documented, and what is not. On the other hand, for DoxyGen one better have editor capable of folding (unusual) comments.

Sphinx is much more crude, you have to specify everything by hand, write everything down explicitly, and even then stumble upon random bricks on the (yellow) road. For instance, files can be organized hierarchically; labels generated automatically from section titles are flat by default (!?), there is only option to prefix them with a filename (!?). As a result, all your sections has to be prefixed with context (by file name, by parent title, etc.); so you now have titles:

  • Piece
    • Piece data
    • Piece functions
  • Tags 
    • Tags data
    • Tags functions

instead of what should be default:

  • Piece
    • Data
    • Functions
  • Tags
    • Data
    • Functions

Sure, second option can be done, but then files might have to be split, sometimes into very small ones. It's no good.

On the other hand, Sphinx does not bloat source code files. It's free-form, and lets you easily organize any way you want, and document key concepts, designs, informal agreements, and so on. Currently, I plan to document libcrochess in parallel to its development; later I might add documentation for various build scripts (gfx.sh, pdf.sh, build.py, py/), and docs for off-screen-shot generator.

Converting documentation proved to be a bit grindy, but relaxing experience, although there were way more text to convert than I'd ever imagine I has written. Anyway, it's done now.

Changing the editor was a bit more pain. Unlike some (most?) developers, I'm not attached to editor I use. Still, I do like the ones that tend to disappear when I'm working, and have all the essentials: 

  • proper dark-mode
  • simple project management, as in a collection of files
  • find in (project) files, and with regex
  • search and replace in (project) files, also with regex
  • visual editor, e.g. commands are on clickable menu, or at keypress, not on a command line (i.e. vi is not for me)
  • split text panes, preferably both panes are proper editors

I tried Kate, but only very briefly, I wasn't able to set it into proper dark mode, since some GUI, window elements have either hard-coded colors, or under non-KDE desktop it defaults to some light colors. Tried to install some KDE control panel app, tried to  fiddle with some settings, only to fail, time and again. It seems I'd have to install full-blown KDE desktop just to set Kate right. Thanks, but no thanks.

So, I returned back to Geany, which is reasonably good, fast, small, and with selection of useful plugins. It only fails at the last item, and in a strange ways; you can split editor into two panes, but only one (left, in my case) is a proper editor with working key shortcuts, the other one can be edited, but most shortcuts don't work.

I asked devs, quite some time ago, it seems it's quite a challenging issue, since Geany was designed from the very beginning around assumption that one file will be ever edited by only one editor widget. There is a 2.0 version out there, but it does not come in Mint repository, since default gcc version does not support C++17; so I can't test if new version solved the issue. For what it is, old version is still quite usable. Shame it's not more popular, and made better.

Which left me wanting more. So, I tried Pulsar editor, and it's great. So far, I only find that it does not have "save all" option. Other than that, I have to say I'm not fond of Electron apps (and 750+ MB for an editor!), but here we are. I think I'll stick with it, for now.

Updating the book

I'm updating the book mostly due to constant interest from readers. There aren't too many changes, since previous update was just two months old. What surprised me is that there are some meaningful changes at all, I was trying to do much more on the programming side, and will continue the same (although, it's tough avocado to crack. Mind you, that text was written before divergence and transparency were introduced!).

Changes from the previous update include:

  • described tags in introduction
  • changed diverging rushed Pawn, now it can't rush again
  • clarified check, checkmate after activating a piece
  • clarified check, checkmate while diverging a piece
  • clarified Scout's forking steps
  • clarified Starchild's divergence
  • added rushing limits table, description
  • added castling limits table, description
  • described forward-displacement notation

The book was compiled on May 14, 2024, version is 20240514.045357, and can be found in usual places.

Finished once more

Oki, so the book is updated once more, and there are no more planned additions to it, so I'll call it done. That is, if I don't stumble upon a special interaction which was somehow left undocumented. For instance, I only recently stumbled upon rushing Pawn starting a cascade (nothing special here), which blocks capture-field of opponent's Pawn, so that en passant is not possible anymore (whoops!). Missing details like this are always a possibility, the best I can do is update the book as needed.

What I really wanted to write about is what didn't made into the book. First thing is a (semi-)transparency of Unicorn and Shaman. This isn't really a problem, but a nuisance; it adds so much in complexity, without enhancing game-play really.
It also does not make sense. I always tried to have all pieces congruent with their role, their story. And having physical entities suddenly becoming transparent to physical is not it.

Other things that didn't make it into the book are resized and expanded Classical Chess variants. I started doing it as casual remarks at the end of the book, but then realized that (if described in sufficient detail) these variants would significantly overgrow its casual remark status.
Worse, those variants actually do not belong to the book. Just as each piece has its story, so does the book as a whole. You most likely don't want to be reading synopsis for 1984, while finishing Alice's Adventures in Wonderland.

I was thinking for quite some time about a new book, where I'd  discuss mobility and calculated values of pieces in different variants. There is some chance that new book will be written, and  then alternative Classical Chess variants would be described in it. While I'd like to do it, right now is not the right time for it. That new book would be a major undertaking, and there are more important things I have to do.

My current plan is to finish game engine library and console application first. After that, I'll add enhanced PGN and other chess file formats support, and obviously document all enhancements done to adapt them for all Croatian Chess variants. And in a distant future, bot and networking support, then GUI application.

The book has been updated!

After almost half of a year, I'm finally updating the book. Changes from the last update include:

  • fixed grammar (castling, Serpent cannot diverge, Pawn-sacrifice)
  • clarified rushing, en passant
  • clarified blocked castling
  • changed Starchild transparency
  • clarified diverging to starting field
  • cleaned-up Wave, Starchild, Shaman intro
  • simplified resurrection destinations
  • described Starchild entering existing syzygy
  • redo Shaman's movement, capturing
  • clarified activating Wave by Shaman
  • added Shaman, Unicorn (semi-)transparency
  • removed Shaman, Unicorn transparency (yes, really!)
  • rewrote capturing, diverging Shaman
  • fixed Wave blocking castling
  • clarified Wave activated by Pawn
  • added Classical Chess chapter as an intro on how to read the book
  • added en passant turned capture
  • added blocked en passant
  • added transparency of pieces table, description
  • added piece actions table, description
  • fixed typos (thanks, RainRat!)
  • redo Pawn-sacrifice
  • started adding expanded Classical Chess variants, then discard them all (yes, really! #2)
  • improved images rendering (field-marker per corner, B&W per variant)
  • clarified trance-journey interactions
  • and more!
The latest update to the book was made on March 15, 2024, version is 20240315.011526, and can be found in usual places.

LinkedIn group

Recently, I noticed quite a few people checking on this blog. If you're interested, there is Croatian Chess group at LinkedIn: https://www.linkedin.com/groups/8989938/. At the moment, group is still small and cozy, but world of chess is large enough, and you can share anything you like 😉

Simplifying

Changes described in the previous post are mostly done. I'll continue working on the book, hence no update just yet. There would be no changes to rules, pieces, designs; I'll be just clarifying descriptions, most notably, movement of Shaman really needs to be simplified. Another issue is that I put a few examples in parallel into just one image. Obviously not ideal, but also not sure if it would really benefit from splitting it up.

As for changes described in the previous post, Starchild has been made transparent to all pieces, Unicorn is now transparent to Shaman, and Shaman is now transparent to all own pieces (i.e. in the same color), and to opponent's Shaman. Sometimes you just have to take the plunge; I'm not really happy with this kind of a blunt design, lumping all pieces into just three categories. On the other hand it does make sense, and can't be really more selective, while also keeping its simplicity.

One planned change that didn't make it, is that Starchild can be activated only on trance- and miracle-fields. While that can be done, both Waves and Starchilds are kinda life-line; if player ever looses all of Waves and Starchilds, (s)he cannot cascade anymore, and cannot resurrect any captured pieces, which is a major setback. To leave opportunity to save at least some of those pieces, I decided to keep activation of Starchilds and Waves on its step-fields.

While castling is special, one-off move, in reality is not that special compared to e.g. resurrection, and so it can stand to a reason that it too should participate in a mundane cascades. So, Wave is now set as not blocking when castling, and Starchild is blocking only destination fields of castling pieces. As a result, castling can now also start a cascade.

With all of those changes made, I do plan on revisiting movement of Starchild, its activation rules, just to check if all of those are sound. In fact, the book as a whole could receive a little reading from me. Yes, really. 

While I did wrote the book, changes are always made to one page, one example, one paragraph at a time. So, keeping track of all rules (and exceptions to those rules) is nigh on impossible. And yet, it's necessary if one is to check that all things are inherently congruent, to themselves, and between each other. So, I'm going to re-read the book to see if rules (and their exceptions) could be simplified while keeping their original spirit intact.

Streamlining

Usually, I would preface talk about the book with an (also, usually overdue) book update, then write something about plans for the future. Not this time. Changes done so far were minimal, and so it didn't make sense to update the book this time around, given that I'm thinking about reversing some of the changes made. Right now, I'm kinda stuck in the middle of a coding session. As soon as I put together minimal implementation for paths, routes, I'll do changes to the book, since it has priority over any code.

For example, one change committed to repository, but not yet in an updated book is clarification that all step-fields must to be empty when castling. This however is one of the carry-overs from classical chess, which doesn't have transparent pieces, and can be reverted back. After the change, Wave could be placed in-between castling Rook and King, and it still wouldn't prevent said castling.

Things do get dicey from here on, since then Wave could also be activated by either King or Rook. Sure, it could be done, and momentum could be calculated by simply counting step-fields traveled over by e.g. Rook. But, I don't like activating Wave while castling, since Rook is sort-of stepping over King, and castling is meant as an one-time super-special move, not a regular one. Maybe solution is to simply state that castling pieces cannot activate Wave, but are not obstructed by it, either; that seems the most reasonable design so far, will see.

Speaking of transparency, I'm also thinking about making Starchild transparent. You see, it kinda makes sense, but not all of the time. One design was to make Starchild transparent to pieces travelling over step-fields, but not over capture-fields. This would mostly just complicate things, but wouldn't do much for gameplay, since almost all pieces have the two kinds of fields lumped together, anyway. I tried to reconcile the two opposing design choices, but so far couldn't really make it work.

A solution (although, kinda cheesing it) could be to have Starchild transparent to some, but not all of pieces. For instance, Starchild could be transparent to e.g. Unicorn, Shaman, Starchild and naturally Wave, but not other pieces. Again, not really happy with this design, so I'll have to take a look into it. Although, past experience thought me not to relay too much on first impressions, sometimes necessary evil is necessary.

I have to admit I made a blunder: currently Starchild cannot be activated, and it's just by a simple decree ("you can't do that"). This is not good. What I should have done is describe interactions, everything else should be derived from that. In this instance, I should have written that Starchild can only be activated on miracle-fields (by other Starchilds), or on trance-fields (by Shamans). While net result is the same, one does not impose arbitrary limitations (and you already know how I feel about those), it just enumerates interactions.

Together with bad no-activation rule will go rule that material pieces gain one momentum from Starchild, by simply diverging from it. I don't know what kind of a brain-fart I had that day, but oh boy, it's still smelly. Solution is simple, if a piece has enough momentum, and Starchild is transparent to it, great; if not, it'll be blocked from moving any further, just like any other piece.

Another design that I'd like to simplify is set of potential destination fields for resurrecting syzygy. Other things that desperately needs simplifying are rules regarding multiple syzygies, be it a piece moving from one into another, or standing on a shared field, or something else.

In short, while the book is finished, some things are still settling, and it will take its time, just like everything else. On the other hand, if you look at classical chess, which is much simpler design, it took roughly a millennia to have rules more-or-less in its current form. As an additional bonus, I'm very, very slow; both in writing, and in coding. If you ask me, I'd say don't prepare your popcorn just yet ...

Updating the book & license

I'm updating the book, even though not much has changed since the last update. In fact, the only thing that has been changed is clarification of side-effects on pieces. Reason why I'm updating the book is because of licensing.

I always thought that simply stating "this book is published as public domain work" should be enough, anywhere in the world. Recently, I stumbled upon Creative Commons site, and I quote: "Dedicating works to the public domain is difficult if not impossible ...", and "... many legal systems effectively prohibit any attempt by these owners to surrender rights automatically conferred by law, particularly moral rights ...".

Now, I'm not sure what are any additional rights automatically conferred by law, beyond moral rights mentioned on Wikipedia site:

  • the right of attribution
  • the right to have a work published anonymously or pseudonymously
  • the right to the integrity of the work

I assume that situation is complicated, since every country has its own  copyright law, each unique in its own way; I'm not even sure how this is treated in a country I live in.

However, to me moral rights as listed above seems completely fine, they should not impinge on any major right granted by Creative Commons Zero 1.0 Universal Public Domain Dedication (henceforth CC0) at all, namely:

  • free access, and freedom to use the work as user wishes ("use" includes to run a program or to execute a music score)
  • freedom to access the "source" and use it as user wishes, for study or change it for personal use
  • freedom to redistribute copies
  • right to quote (freedom to redistribute copies of fragments)
  • freedom to distribute copies of user's modified versions to others 

From what I understand, if I have moral rights retained, only the last item would be affected somewhat; modified versions should be distributed under a new title, and with new authors, due to the right to the integrity of the work. I'm not sure if right to attribution applies to modified versions; for instance, if modified book should contain "this book is based on ..." clause somewhere in a colophon. It would be nice if it does, but it's not that important to me.

If that's all there is to it, then I'd like to retain moral rights, even if I have had put the book into the Public Domain. If there are some other rights that would prohibit any of freedoms listed above to any person, then CC0 should come into play, and waive those rights away; this is what I meant with "where Public Domain is not applicable".

The reason I put my book into Public Domain in the first place is to prevent any publisher from closing access to my book behind a pay-wall, and limiting its usage by the public, especially given that some publishers are getting very creative, when it comes to their own benefits. And the reason why I choose to go with CC0 is because it seems that simply stating "this book is in public domain" isn't exactly enough.

To summarize, the book itself (PDF file), source texts (TEX files), generated images (PNG files), photo (NEF, and JPG files) are all in  Public Domain, under CC0. Note that all scripts (SH, and PY files, including those used to generate images for the book) are published under GNU GPL v3+ license, as are the rest of source code (C, and H files). Licenses, and how to apply them are found in COPYING, and LICENSING files; in book folder for the book, and in the root folder of the project for source code, and scripts.

Edit: it's actually way worse than I thought. So, I decided to apply CC0 unconditionally, and to hell with moral rights; they are not worth risking any legal loophole which I might have unintentionally introduced, along with possibility to creatively interpret intended usage, and applied license. The book is already updated, and uploaded, both onto GitHub repository, and Google Drive.

Edit 2: CC0 is a dedication, not a license.

Of style, and braces

I always subscribed to Allman style when programming in C; granted, before this project I never had any larger amount of code. Now I do have, and I'm finding that style to be getting in my way more and more.

You see, I do like to have empty lines in my code to separate small, logical chunks in a single block; usually, that means every few lines of code there is a separation. That way, code isn't all clumped together in one giant, incomprehensible block; it reads "light", and is much easier to understand.

Having intro and outro around every block, and code becomes more difficult to read, because it's visually more separated, and no matter how big your monitor is, it can only display so much. The thing is, I prefer to set my own separations, and the ones dictated by style I found useless, at best.

So, yesterday, I had a sort-of satori: what if I move braces around? Sure enough, there are already plenty of styles beside Allman's, you just need to pick one, and refactor code.

So, I went from Allman style:
if ( foo )
{
    bar();
    bar2();
}
else
{
    baz();
    baz2();
}

to one-true-brace-style, and found it okay-ish:
if ( foo ) {
    bar();
    bar2();
} else {
    baz();
    baz2();
}

That left me wanting more, so I decided to try to move outro braces out of sight as well:
if ( foo ) {
    bar();
    
bar2(); }
else {
    baz();
    
baz2(); }

Surprisingly, I found it to be readable, understandable code. As the saying goes, beauty is in the eye of a beholder; so I won't claim it's beautifully styled code, it certainly takes time to start appreciating it. Still, if you can ignore braces, it's reasonably formatted.

Gains are significant, too. With just one simple trick, I went from almost 10k SLOC down to slightly over 8k; difference is about 1500 SLOC, or about 15%. But more importantly than just numbers, code is so much easier to read, and understand, because related functions are shorter, and thus much less visually apart.

As everything in life, this style too has it's own fair share of downsides. First, and foremost, braces aren't visual fences of code blocks anymore; they are now just for compiler. If you have any of those fancy code editors/IDEs which can color braces, and maybe even indicate block between them, that would be major help. But even so, it's PITA to have to click at code element you're interested in, just to check if it really belongs to block you think it should.

Another issue is that you now relay on proper indentation to convey intended code blocks, formatting. Python was designed that way from the very beginning, but in C it takes time to get used to it. Arguably, that's not really an issue, most programmers do indent their code properly anyway.

Which brings me to final downside: it's possible to encounter code where indentation does not match real blocks, because braces somehow got mismatched. In newly written code, that shouldn't ever happen. Still, it's possible to end with spaghettified code blocks, when one refactors existing code base, and is not careful enough with search-replace, regex. Fortunately, there is always undo.

Still, I like this indent-style, I'll keep it for now.

Edit: well, that didn't last for a long. The indent-style, that is.

You see, the problem is, braces still determine to which code block a particular line belongs, but they aren't "visible", you have to parse code to find them. Syntax highlighting and good editor can help, but usually only one code block at the time. Maybe VS Code can put visual hints around every code block, but I didn't bother, visual cacophony most likely would be overwhelming. 

So, I already switched back to 1TBS, a few days ago. When in doubt, wisdom of the commons (most popular choice) might be, if not the best choice, the least atrocious.

A bit more finished

... the book, that is.

I'm updating it since grammar is now finished, and all the polish it needs shouldn't mess with designs, rules, pieces. I say shouldn't, because I bit my tongue so many times already.

Updates include mostly grammar, and some side clarifications, like how to combine multiple side-effects, added some examples on how to diverge,  material pieces are now gaining 1 momentum when diverging from Starchild, all small stuff.

One thing that still bothers me, although much less so then before is that grammar alone (that is, without context) is not be-all-end-all reference. I have wrote it in the book, but it's worth repeating: entity (values) which are present only sometimes are not the same as optional entity (values). 

For instance, move status most of the time is not present, i.e. it's empty value. Except for checks, all other move statuses are mandatory to write. To sort-of convey that mandatory-ness to reader, I defined move status with an empty value, so that status after a move is mandatory not just in notation, but in grammar as well.

Similarly, Shaman stepping is not defined entirely correctly; issue is that Shaman has ordinary steps separated from capture-steps, and can switch between the two after diverging. Wave can be ignored only while making ordinary steps, but not capture-steps. However, both transparency and  capturing side-effects are optional to write, and so both steps could look the same. So, to keep things simple, I lumped all side-effects together, even though they are separated.

Lack of meaning isn't something that can be solved in grammar, and the book can only deliver so much, or so little. In the end, it's up to reader to build his/her own understanding. 

Anyways, back to the drawing coding board.

A look back, and forward

Well, that last update took way longer than I was expecting; there were no book updates for half a year. In my defense, life happens, and time flies, ever so faster. When you're young, it might seem you're invincible, nothing really bad can happen to you, and you'll live forever. Guess what, I'm in my fifties now, and this is no longer so for me. Sooner, or later, you'll too start noticing little annoyances, you'll slow down, you'll be vulnerable just like anyone else, ... if you still have parents, be nice to them.

Speaking of life, it seems it'll be happening more, and more in the future, too. Among other things, the skyscraper I live in is scheduled to have a major renovation, with works spanning a good year, or so. Or, maybe not, I'm not sure. You see, people involved in the project already tried to take advantage of naive owners at multiple levels, all the while it's mostly paid by the EU. I'm so tired of all the scummy local sheriffs; I wish EU would put a stop to it, but I'm pissimistic. Anyways, if project still goes forward, I'm not sure how much of work I'll be able to do, I assume I'll be all night-shifting for at least a year.

With the latest update to the book, I'll be so bold, and announce the book to be finished. Yes, you know, I know, it's finished, again. But unlike two-and-half years ago, this time I really don't see anything that needs to be added to the book. Sure, the book desperately needs a few finishing touches, and after that a good spanking polish, and before that I do need to finish grammar, and the last variant most likely needs rewrite. Still, all of this is non-essential in my view, and will be done at more leisurely pace, in parallel to the very next stuff I'll be doing.

What now needs to be done, is to start implementing all that new features I added in recent updates. That means, cleaning up existing code, and while it's not starting from scratch, it's not that far off, either. Just divergence added a major plot in the twist, so to speak, by adding a new layer of complexity when analyzing movement notation, and trying to reconstruct what actually was meant to happen.

On the other hand, starting almost from scratch does have liberating effect on some of code designs that are sub-par. For instance, when parsing notation, I also tried to validate some, if not most, of rules applicable to notation at hand. Prior to that, I was also going back-and-forth on validating things as soon as possible, and wasn't happy either way. Now it's clear to me, validating too early just complicated parser, while also made my job a lot harder. 

So, in the future, parser has to be completely separated from validating code. But more importantly, this little lesson also makes me rethink some of design choices I follow because they're good engineering practice. Good practice is a form of a generic design pattern, not necessary applicable to all situations, so maybe I should give up on them, just  like I did on trying to catch errors in input as early as possible. Sometimes, one has to relax, have another coffee, and accept that all errors will be caught when their (validation) time comes.

Updating the book

After quite some time, I'm finally updating the book. Changes from the last update include:

  • Monolith is opaque
  • Wave is not divergent any more
  • Shaman is now divergent
  • Centaur, Wave activated by Centaur cannot diverge
  • Unicorn can diverge
  • Wave activated by Unicorn cannot diverge
  • Serpent can displace Pawns
  • Monolith is noble
  • extended Serpent's movement limit
  • Monolith now constantly accelerates while moving
  • Serpent cannot diverge
  • Wave activated by Serpent cannot diverge
  • removed Monolith's movement limits
  • Serpent cannot loop anymore (in a single ply)
  • simplified trance-journey, fixed notation
  • added sense-journey
  • removed odd variants
  • added a new pieces: Scout, Grenadier
  • changed Pegasus symbol (G --> E)
  • and much more!
The latest update to the book was made on July 9, 2023, version is 20230709.134133, and can be found in usual places.

Putting some sense into a journey

Month has already past since the last post, and it doesn't seem much to be done. Anyway, more, bigger, and better plans to follow ;)

Sometimes, it seems when I put forward a plan, the opposite find its way to prove to be superior choice. For instance, I was ranting how I don't like arbitrary designs when discussing limits on Shaman's movement. Well, it turns out, it's way better to have arbitrary limitation in place, then deal with yet another massively OP piece, which isn't all that tricky to move, and so fails to reward skilled gameplay. This also fits nicely into general design of variants, where almost every possible rule has an exception to it. If Shaman's movement has to be that exception to the "no arbitrary limitations" rule, so be it.

I changed the way Shamans get entranced into trance-journey, and in doing so, I also wanted the same for Starchilds. Then I realized, it's a good time as ever to have two journeys divorced, at least in name, preferably also in named functions of pieces involved. So, trance-journey will stay in its original form, involving entrancing and entranced Shamans. Newly named sense-journey would involve at least one Starchild; starting with initiating piece (Shaman, or Starchild), then uplifting Starchild, and then uplifted arbitrary piece. Not sure about function names of pieces in sense-journey, maybe I should find different terms? Anyway, the two journeys would stay related to each other; the way entranced Shamans and uplifted pieces move would stay the same, as it would notation using @ sign. This is less then ideal, I'd prefer to have different symbol for encoding sense-journey. The problem is, I'm kinda out of ASCII symbols, and it would make no sense to use anything other than  ASCII for English-based notation.

Another change that I plan to do, is to finally add Scouts and Grenadiers into the mix. I was thinking about it a while ago, but wasn't so sure about designs. Even though I put it on a slow burner, and never took time to think about it thoroughly, it bothered me for quite a bit, and primary reason is because current design adds large swaths of plain, old Pawns[*] which drown out all the other pieces, just with sheer numbers. Now I have made up my mind, even though not everything is clear; I still have to have movement rules and designs of pieces sorted out, before they can appear on a chessboard. Still, Scouts would be much more mobile version of a Pawn, while Grenadiers would be more dangerous, and more tactical ones. Collectively, Scouts and Grenadiers would be called Troopers, while Privates would be any of Pawns, Scouts and Grenadiers. I'll also leave promotion/demotion limited to just Pawns; so Troopers cannot be promoted outright, and has to be demoted to Pawns before they can be promoted. Movement limit of Monolith would also stay based on count of Pawns alone. In showing their Pawn descendancy, Troopers would be able to rush, and could be subjected to en passant.
[*] sideways movement notwithstanding

My immediate plan is to deal with some fixes to notation, namely divergence, displacements of Pawns by Serpent, then review/fix as needed trance-journey. After that, I'll do sense-journey, hopefully covering its notation right after it's done. And after that, I'll do Scouts and Grenadiers. And after that still, I'll update the book; it's been quite some time, and changes, both done and planned, are significant.