Thank you for your donation!   Download the book!   Join the group!   Public source code repository
Showing posts with label plans. Show all posts
Showing posts with label plans. Show all posts

Status update

Hello, everyone! Here's a (bi)monthly update on things and stuff. I haven't wrote anything for last two months since I didn't have anything intelligent to say, except maybe "I'm still working on stuff". I still do, but now I wanted to share current status and a few thoughts with you.

First of all, as you might have seen it in my Codeberg repository, I'm still working on classical pieces, previously I supported all usual suspects (Bishop, Rook, Queen), then added support for Knight. Now I'm still working on King, I finished support for movement and castling on all variants, and wrote all relevant tests.

Now I'm working on checks if a field (and a piece on it) is under attack; or, should I say, again. Reason for rework is me being "clever" to speed-up development. Code was finished, tests (mostly) passed, everything was fine, except I overlooked pieces positioned between an attacker and a target. Sure, some are transparent to attacker, but not all. And so I had to get back to a drawing board, and the change isn't as simple as one would expect based on previously done code.

After support for King is finished, I'll start working on Pawns. I don't like to try to predict how long it'll take; but I'd like to finish it by early-to-mid October, since I might have some other (family) obligations, and most likely I won't be able to work at all for a week, or so (I hope); period of forced inactivity might be longer. Anyway, when support for Pawns is finished, I'll publish the very first public code release.

Generally, I agree with Drew DeVault that developers should do only code, and administrators should do distribution, but in this day and age that stance isn't very appealing, or convenient. So, I'll take a look at ways to make executables available for different platforms. So far, I have been ignoring CI/CD, or any other builders; on the other hand, application which isn't easily accessible is effectively dead.

After that, I plan on adding support for canonical variants in order of appearance, starting with Mayan Ascendancy; Croatian Ties is already supported. Recently, I started indulging myself again into thinking about changing some pieces and rules. I have already complained that Centaur might be too OP, even as I did significantly cut its reach. I already come up with a solution to straighten its course, but I'll leave this idea to take a proper shape on its own, rather then being forced into existence. You see, I really like its jumpy frolicking movement as-is, and would like to keep it if possible; problem is that at the moment I  really don't see a simple solution. Of course, if this come to pass, Waves activated by Unicorns and Centaurs would also get their straightening treatment.

There are also some other candidates likely to get rules updated, namely Starchild; regular visitors know I  already promised it'll get a proper revision, or at least a polish. Another candidate is Monolith, I don't like its diamond shaped movement pattern, it simply doesn't belong to it; but at that time I couldn't make my mind about simple to visualize, accelerating pattern. Yet another candidate is Serpent, although this change would be very simple; I'll just restrict its movement a bit, this time after I calculate its power compared to other pieces.

For now, this is mostly it. Take care!

The very first move

So far, I was trying to build game engine library which can do all variants and all pieces from the book right out-of-the-box. Recently, it occurred to me that might be a bite too big to chew. So, I decided I'll focus on simple and randomized variants, and support only classical pieces (+ Pegasus) at first. That way, I'll build complete stack, something useful for users, even if it's just a console application. Let me know if you'd prefer GUI application; depending on feedback, I might also do it. Of course, that would  mean more advanced variants won't be supported for quite some time. Currently, I plan to add them one by one, in order of appearance in the book.

Oki-doki, so I added support for all randomized variants, and simple pieces without special movement are all supported; that is Bishop, Knight, Rook, Queen, Pegasus. King can move, but currently castling is not supported. Pawns are also not supported at all, including en passant and promotion. So, only one side-effect is supported, that is capturing. Before I can publish first public version, I'll also have to add test if King is in check, and if a field is under attack (to test for legality of castling). Saving and loading current chessboard is also not planned for the very first release; simple (and randomized) variants can be played in one sitting. The same applies to in-game chess clock, I presume no one will play new variants in tournaments from the get-go.

How does it look like? Well, I took screen-full of texts from console application:

> new cc14u
   a b c d e f g h i j k l m n
   ---------------------------
14|r r n r n n r k b q b b n b|14
13|p p p p p p p p p p p p p p|13
12|. , . , . , . , . , . , . ,|12
11|, . , . , . , . , . , . , .|11
10|. , . , . , . , . , . , . ,|10
 9|, . , . , . , . , . , . , .| 9
 8|. , . , . , . , . , . , . ,| 8
 7|, . , . , . , . , . , . , .| 7
 6|. , . , . , . , . , . , . ,| 6
 5|, . , . , . , . , . , . , .| 5
 4|. , . , . , . , . , . , . ,| 4
 3|, . , . , . , . , . , . , .| 3
 2|P P P P P P P P P P P P P P| 2
 1|N R N B B N R B B K R Q N R| 1
   ---------------------------
   a b c d e f g h i j k l m n

this creates new chessboard for Classical Chess 14 unbalanced variant. As is custom across console chess applications; dark pieces are lowercase, while light ones are uppercase; in notation all pieces are written uppercase, regardless of color. Since Pawns can't be moved, today there won't be much of a game-play, but Knights can jump over them:

> move Nd3
   a b c d e f g h i j k l m n
   ---------------------------
14|r r n r n n r k b q b b n b|14
13|p p p p p p p p p p p p p p|13
12|. , . , . , . , . , . , . ,|12
11|, . , . , . , . , . , . , .|11
10|. , . , . , . , . , . , . ,|10
 9|, . , . , . , . , . , . , .| 9
 8|. , . , . , . , . , . , . ,| 8
 7|, . , . , . , . , . , . , .| 7
 6|. , . , . , . , . , . , . ,| 6
 5|, . , . , . , . , . , . , .| 5
 4|. , . , . , . , . , . , . ,| 4
 3|, . , N , . , . , . , . , .| 3
 2|P P P P P P P P P P P P P P| 2
 1|N R , B B N R B B K R Q N R| 1
   ---------------------------
   a b c d e f g h i j k l m n

and, there it is!

In short, there is still a long way to first release, this is just a peek into progress made so far.

One step back, two forward

So, I moved to new online Git repository, but since then there was no update on project status. Well, this is it; somewhat overdue, I admit, but with a (good?) reason. You see, most of my followers are chess enthusiasts, not programmers; so, I postponed my initial post since it's not that interesting, then got side-tracked, again (as one does).

In the meantime, there has been some progress on generating paths a piece can make, then comparing those generated paths with user notation, and finally executing a move if a unique match has been found. Due to a sheer scale and count of cases, tests has been separated into different executable:


All tests run One variant, since it's the most complex one, and features one of the largest chessboards in the book. One of tests (out of a few dozens!) is this one: "ta 9" command simulates user who typed "Bg3*N", and given the situation on a chessboard bellow, test then tries to establish if there is a full path (step-by-step) and side-effect (capturing), that matches user notation: 


The first thing to do is to find moving piece and its starting position. This isn't as straight-forward as one might think: there might be multiple pieces of the same kind, some with or without a tag, and sometimes opponent's pieces qualify as well, e.g. if activated in a cascade.


After finding a moving piece, all possible paths were generated; in the printout those are indented since they're all connected to each other, in one big, branching tree. The first line shows starting position ("d6"), then piece found at that position ("B", that is light Bishop) and its tag ("!", that is no tag found)., then activator (empty, since this is the first piece in a move), then momentum ("0"), which is still being accumulated ("+"). Lines starting with "<" are forking paths, i.e. all paths connected to it would inherit previous path segment(s), while lines starting with "^" are alternative paths, i.e. would replace other previous segments. Forking paths are used after the starting position, and after divergence. Alternative paths are used if there are multiple possible side-effects (interactions) between moving and stationary pieces; or, as an alternative path segment to a fork in a path. Note, alternative paths do not include displacements since there are too many possible destinations; those are handled differently (as a list of tentative (i.e. all possible) displacements, for each step).

All possible steps a piece can make are enumerated in a list, separated for each piece; enumeration starts from x-axis (3 o'clock) and then goes anti-clockwise. This is why here the first segment after the starting position goes all the way to "x26", then to "a9", then "a3", and finally to "g3". At that last path segment, application found dark Knight ("n"), with no tag ("!"), and established it can be captured ("*N" as a side-effect to the last step of a generated path segment). Momentum of a light Bishop at this moment is "3+", meaning that Bishop had already made 3 steps, and is still accumulating momentum.

Now all paths has to be generated by traversing path tree, and stitching together path segments from starting position to the very last step; each leaf node in a tree ends one path. Those generated paths are then compared to user notation, to see if there is a unique match. Except, that's not entirely correct; due to the need to maximize accumulated and minimize spent momentum, paths are searched for the shortest possible path, and then for the longest, if different. So, the longest path is preferred for the first piece in a cascade, otherwise the shortest path is used. Here, there is only one path possible, so it's saved as the shortest one, e.g. "d6.e5.f4.g3*N".

After unique path has been found, it's time to apply it to the chessboard:


As one might imagine, light Bishop left its starting position, and replaced dark Knight on a chessboard. Except, that is how it would have been done in a physical world. In virtual, digital world light Bishop on its starting position was replaced with None piece, i.e. the one used when there is no piece on a particular position; and then dark Knight on a destination field has been replaced by light Bishop after it has been stripped of its tag, even if it didn't had any. After movement all pieces lose their tag; but, tag stripping is such a simple operation that I didn't bother to check if a piece doesn't have any.

As you can see from a very cursory glance into game engine, it's not that simple to explain it, and it's even worse to implement. In the meantime, I was also trying to think of a simpler, more elegant solution to the problem, and it seems that I have found one. This is why I'll be ditching all this generating of a path tree, extracting each full path from that tree, then comparing it to user notation; and replacing all of this with functions for each piece specifically. That way, a lot of guesswork (but, what if a piece can diverge? is it transparent? to what?) can be eliminated, because in a specific function one has to handle only one piece (e.g. a Bishop) and can safely ignore interactions that are not relevant.

Why I didn't made such a transition earlier? Well, it took me quite some time to figure out that in a cascade I could use intermediary chessboards to communicate all the changes made in a previous ply, and then accumulate all those changes into the final chessboard for a move. The one thing I don't like about piece-specific functions is that can easily lead to a lot of code duplication, since similar code can be embedded in many piece-specific blocks; usually a lot of variables are shared between the two, making it difficult to refactor similar code into a function of its own. The other thing I don't like is that algorithm replaces data, and so no intermediary data is generated, and so the only way to check correctness of such a function is to debug. Oh, well ... nothing is perfect.

Moving (closer to) home

I have been using GitHub to host my online repository for over a decade now. The problem is that I'm getting errors -seemingly at random- like this one:

Too many requests

You have exceeded a secondary rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.
Signing in may provide a higher rate limit if you are not already signed in.

For more on scraping GitHub and how it may affect your rights, please review our Terms of Service.
Contact Support — GitHub Status — @githubstatus

even if all I did was try to access a page with my own commits. Even more infuriating, those errors now  persists even if I delete all the cookies.

Also, in not-so-distant future (I hope!) I might want to use CI/CD. However, broken GitHub implementation was one of the reasons why e.g. Zig moved over to Codeberg, and I'm inclined to do the same.

So, I'll be moving my online repository to Codeberg, and also primary email and probably even this blog. In short, there will be delays before I can continue development. In theory, it should be simple to switch from one online git host to another; in practice, there is a difference.

Home? you ask. Well, this time around I'll prefer European services, preferably non-profit.

Last edit: 2026-01-26 8:31 UTC

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.

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.

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.

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.

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.

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 ...

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.

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.

No title, just plans

Since my last post I changed Serpent to displace only Pawns, not all of pieces. I deem change necessary, otherwise Serpent would be able to break any formation, not just Pawn fortresses, which would be a little too OP. Breaking Pawn formations is good though, it opens up gameplay, and effectively limits static play.

This goes in as a preparation for another planned change, movement of Serpent should be unrestricted. Currently, there is some arbitrary cap in play, and you already know how I dislike arbitrary designs. So, plan is to remove cap, but also forbid loops. So, Serpent could visit any field, but only once in a ply.

Before you ask, Wave activated by Serpent will stay limited to two initially chosen directions. If I'd allow for such a Wave to move as unrestricted Serpent does, it would have half of a chessboard at its disposal, because Wave is transparent, and does not spend momentum while moving. Which all means, Wave activated by Serpent would be way too OP. So, that restriction has to stay where it is.

As for immediate to-do, I'll change way Shamans get into trance-journey. Currently, I sort-of abused Waves to activate the other Shaman, which can then optionally go into trance-journey. I'll simply relieve Waves from that duty, and have one Shaman directly activate the other one. This all will be done on neighboring fields, i.e the ones which are not step-, not capture-fields of neither light nor dark Shaman, so it'll be very specific, and very special movement.

Reasons for the change, you ask? For one, it provides build-up to trance-journey, and a warning to the other side what a player is up to, and also provides (a little) room to counteract. This is also similar how Shaman captures opponent's pieces; first it has to close a distance to its prey, then in next move it can go capturing. Second, trance-journey is now deliberate move, not optional, mixed with other side-effects. And this also makes it so much easier to figure out in parser, analyzer code; all good in my book B).

One thing that still hasn't clicked the right way is how Starchild is  activated, namely separation between activation on step- and miracle-fields, combined with all the other Starchild rules, and exceptions to them. Sure, it all have logical explanations why they are that way, that doesn't make them right. So, I'll probably have to revisit those, before deciding what to do. One option is to forbid Starchild to be activated at all, that would simplify designs, and since Starchild still has a lot of other own stuff to do, that might not be too much of a loss.

Another thing that I stumbled-upon is a realization that complex mechanisms are not explained properly, i.e. one simple mechanism at a time, and only once. I figured out, I have a tendency to stuff all of mechanics into one example, and then repeat that poorly explained mechanics over-and-over again. No good. I mean, that was main reason why I rewrote Miranda's Veil. This is, of course, completely my fault; such is a price of learning things by doing them.

But now, it left me wondering, what if I revisit all of examples from the very beginning, and rewrite all that needs to be redone? This can be done, and I think I should, since it would make the book so much better. The only problem I see is that it'll take months to finish, quite possibly to the end of a year. Again, this is something that I won't be rushing into, I'll take my time to decide if, and when I want to take the plunge.

Just to clarify, complex should not be confused with complicated; complex things are comprised of a few other, smaller things, all of which are -in, and off itself- simple. Complicated things are just spaghetti-designs, many things arbitrarily bolted on top of each other, without any regard for consequences.

Divergence on the run

I made two relatively small changes to Serpent, namely now it can displace pieces in its path. This is similar to Shaman, but without the need to be bothered with super-special, secondary movement. Given that Serpent's meandering movement lends itself nicely against opponent's Pawn structures, this might also help break those fortifications, even without capturing anything.

Another change is that I finally extended the range of a Serpent, it can now do up to 16 steps, up from 9 steps. I'm still not completely satisfied with Serpent's design. Issue I have is with arbitrary limit which has to be put onto Serpent, otherwise it would be able to loop forever, and build infinite momentum. Either I'll make loops illegal, or straighten Serpent's path in some capacity. Although, having a piece preloaded with Bongcloud-level of pure, unadultered fun is not below me. 

I won't be updating the book just yet, these changes are too small to warrant that, especially because I plan to do larger changes in the immediate future. One planned change is to move divergence from Wave onto Shaman, Wave would stay transparent. Obviously, this means moving all divergence sections into Conquest of Tlalocan variant, and redo all the examples, and reword all the texts. Not difficult, just physically large change.

One other change I was thinking about was to change how Monolith moves. Currently, it has uninspired, fidgety, but still unrewarding pathing. I was thinking about changing it into accelerating Centaur, with each jump longer than previous one, preferably without an arbitrary limit to its movement. Obviously, each step has to be chosen independently from any previous choice; problem is that might turn Monolith into super-duper OP Centaur, which can reach any single field from any position on a chessboard. This is not good, even if Monolith cannot interact with any piece, so I'll try to find something more reasonable. 

One crazy possibility is to limit Monolith to the number of Pawns a player posses. For instance, if light player has 5 Pawns, Monolith moved by light player can do only up to 5 steps. This also fits nicely into gameplay; at the beginning Monoliths can do a lot of steps, but are cramped on board, as game progresses Monoliths are not so confined by sheer number of pieces, but are limited by number of Pawns still on board.

And last (but not least), there is a common, recurring task; that is to sit down, and reread last two variants, and simplify (or, at least, clarify descriptions of) syzygy, and other rules regarding Monolith, and Starchild. I don't like it, but those needs to be done, to be able to hold all rules in ones head at the same time.

Book is updated

I'm updating the book, quite some time has passed since the last update, and only two small changes have been made in the meantime.

Changes since the last update:

  • simplified description of Wave movement, if activated by Serpent
  • removed Terms from Prerequisites

The latest update to the book was made on September 9, 2022, and the version is 20220908.223634.

I also removed all links to book preview. 

Book is close to finished, I don't plan any major changes, and certainly not stretched over many months, or years. Some smaller, but still significant changes could make it into the book, e.g. extended Serpent movement. Again, this is not something I'll be doing in a hurry.

For now, I'll try to work more on library.

Edit: just as I wrote "work more on library", it occurred to me that Wave should be made transparent, i.e. it makes sense to allow other pieces to pass-through Wave, just as Wave can pass-through all the other pieces. This would also make defending Wave easier, since it has to stretch out to activate anything, and most interesting pieces to activate are opponent's.

Since the book is the most important part of the project, changes will be made immediately, after which coding will resume as usual.

Stuck in the middle of the book

I planned to redo complete parser thingy from scratch back in February, but before that a short detour to revisit book, more precisely, activation rules and do quick fixes here-and-there, then get back to coding.

Except, one thing leads to another, and here I am, two months in and still at quick detour. One reason is that I have to explain all emerging effects of rules, and new concepts in greater detail, and slower pace; so I have to redo quite a few examples. Another is that I wasn't happy with Miranda's Veil for quite some time now, so I took the opportunity, and rewrote the whole chapter. 

I prefer to have a few simple rules from which all other emerging effects can be derived following logic. Sometimes, I get it wrong. For instance, last piece in a cascade can never check opponent's King, even if it has enough momentum and King is within range. This is so because activated piece, once it starts moving, can't change direction of its movement. So, to be checked, opponent's King would have to be positioned in a chosen direction before cascade even starts, which would mean King was checked before cascade even started. So, precheck and precheckmate can never happen. This is not the only thing I got wrong, or simply overlook, but it illustrates how nuanced things can become. 

It's not all fixes and rewrites, either. I recalled that I read a paper on AlphaZero evaluating Classical Chess variants, so I recently added sideways moving Pawns into the fray, from Nineteen variant onward, to spicy things a little bit. I mean, c'mon, how can you say no to: "This is the most perplexing and “alien” of all variants of chess that we have considered. Even after having looked at how AlphaZero plays Pawn-side chess, the principles of play remain somewhat mysterious – it is not entirely clear what each side should aim for. The patterns are very different and this makes many moves visually appear very strange, as they would be mistakes in Classical chess. Lateral pawn moves change all stages of the game. Endgame theory changes entirely, given that the pawns can now “run away” laterally to the edge of the board, and it is hard to block them and pin them down." (assessment by Vladimir Kramnik). 

It doesn't hurt that sideways Pawns are very roughly twice as valuable as ordinary cousins (which is very much welcomed for variants on an ever growing chessboards!), they offer more potential moves from the very beginning of a match, doesn't upset the balance of the game, doesn't slow down gameplay, ... all the good stuff! Would you be surprised if I tell you that I'm seriously thinking into doubling-down on sideways Pawns? I'm considering to introduce 2 new pieces, Scout and Grenadier, both remains in Pawns category (can be promoted, demoted-to, captured in Pawn-sacrifice, ...), but each with different movement. Issue is that now I'd have 3 different Pawns, and so I'd need to change en passant, and all other examples that involve Pawns. Also, introduction of Pawns category means now old Pawn piece has to be reintroduced as Private, to be able to distinguish between Pawns (category) and Pawn (old piece); this is huge undertaking. I'd like to postpone it, but I also very much like the idea, especially because thematically if fits so neatly  into the book.

This is The Avocado!

With capital T. And capital A. Compared to which Sparta is a very mild chamomile.

No matter how you try to slice it, you'll end up in an unbreakable kernel. And, if you try to force it, you'll end up with just a few annoying, inedible bits, and kernel still barely scratched. That is an avocado. 

Good engineering practice, and really the only one to enable reasonable rate of progress, is to divide any problem into smaller and smaller bits, until you can build from solutions to the smallest problems, up to the whole. And, of course, you'll want least possible amount of special cases, since those ruin your division into smaller and smaller bits.

Enter The Avocado Croatian Chess. Its algebraic notation features mild context-sensitive grammar (I was reasonable about it). It also has external data (game status, and chessboard, more precisely positions and tags of all pieces on it) not just as a dependency, but as a context; because to be able to parse any ply in a cascading move, one has to apply all previously parsed plies to chessboard, since those are changing positions and tags of pieces. To top it off, it also features self-evident, reasonable requirement for a convenient notation, i.e. almost all movement can be noted with just a piece + destination field (+ side-effects, if present).

For trance-journey, the same applying to context chessboard thing has to be done for steps, since those are also changing positions, tags. Congratulations, this is a very first special case, and to handle it via unified interface, now every step of every ply has to be applied to a context chessboard. In fact, there is barely any rule that doesn't have a special case, making any unified interface a nightmare to implement. While it might look like a self-inflicted pain (which it is), the matter of fact is that special cases are the meat of the game, without them it would be just a scaling game. I have to confess, I was thinking about ditching the whole Croatian Chess shebang, and regress to scaled-up Classical Chess, just by copying 3 side figures, and accompanying Pawns a few times over, resulting in 14 x 14, 20 x 20, and finally 26 x 26 chessboard, with no special cases pain. While that might do for a while, it's ultimately boring, and brings nothing new to the table.

Now you see why you can't just take notation alone and try to parse it, you'll need live chessboard (positions, tags), and game status (who is on the move). You can't even say if move notation taken alone is valid, some plies aren't legal, depending if e.g. activation of pieces are made on step- versus capture-fields. I could've opted to do most of validity tests, and forego those which can't be done without chessboard, but that would pose at least three problems. First, most tests would be done, but some, seemingly arbitrarily, would be missing. As a consequence, validity would be restricted, and non-intuitive compared to what most users (me including) would expect. And there is a problem that validity checks are done on notation, and would be repeated again during parsing, now with greater scope since chessboard is available, and most likely again while actually applying movement of pieces, side-effects to chessboard.

So, it seems to me that whole game engine has to be put upside-down, like a pyramid with a pointy-bit at the very bottom. That means, most of work done so far is actually useless, and it should be deleted. Better to start from scratch, then try to salvage garbage; this includes almost all of tests application. Next, movement data has to be considered correct, so there would be no wasting time trying to validate it. This is probably the hardest part of implementation, as it too goes against well ingrained engineering practices, where all of user inputs are considered invalid, until proven otherwise. Both major components (parsing, applying move) would have to produce user-readable error messages. Actually, there would be only one major component, as the only difference between parsing and applying notation would be on the last leg, when the latest context chessboard is returned from parser, or it's set as a new live chessboard, and game status updated accordingly, if applying a move.

On top of all that, a few days ago I found out that activation rules are not thought through, or at very least, not formulated exactly. Problem is that Pyramid can't be activated on a step-fields directly, but currently it can be done in a cascade indirectly, via Wave, and with no restrictions. Since activation is a keystone of the whole lot, I'll have to do it before any coding can take place. Needless to say, I'll also have to revisit every single example in the book which includes activations, and change those accordingly.

In short, I have done very little so far, a lot of book rewriting has to be done, before any real coding work could commence.

const considered (mostly) harmful

I started salvaging algebraic notation (AN) parser from top down (as posted by the end of August), when I stumbled upon a serious issue with iterators. My fault for sure, but what was peculiar about it is that I was somewhat subconsciously trying to write Python in C, and longing for more expressive language. In fixing this issue, I also had to unlearn quite a few things, and re-learn some I mostly forgotten. After a few iterations, I ditched static variables inside function, for input/output parameters. While, at first, this looks like a eyebrow-rising design, it's thread safe, clear how to use it, without need for an awkward initialize_iterator parameter.

While I was fixing iterator in string utils, I stumbled upon another issue, variable and parameter names weren't consistent. So, I started fixing those, when in the middle of the changes I stepped into a turd of a const-correctness, especially involving pointer-to-pointer parameters. Looks like I'm not the only one; what is actually surprising is how long code peppered with consts lasted. I was searching for answers, and I found out it's by (bolted-on) design, from the very onset.

Some pondering later, I figured out that const is not meant to communicate constraints of underlying function algorithm, but to designate initializer data (strings, arrays, tables, ...) which won't change as such, and so do not slap const carelessly onto every thing in sight.

So, rules for applying const I now use are simple:
1. const is mostly for parameters
2. char * parameters, and any pointer to simple* struct, union
3. module or global variables, if used for initialization, and won't change
4. anything else should be const free

* simple in this context means it does not contain pointer

This change has already being made, and it's refreshing to see code free-ed from all that const noise. Now, I'm finishing renaming of variables, parameters, while I also occasionally double as a plumber (no, not by saving Princess Peach, but by fixing some (memory) leaks). After that I have to do a couple of  relatively simple TODOs, then re-implement a few iterators. After all that, I'll get back to my original task, re-doing parser. I won't try to predict how long this all will take, I'm notoriously really bad at reading from crystal ball.