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

Welcome aboard!

For some reason, people tend to cling to things how they were used to be, useful or not, even in presence of something better, or -at least- newer. Of course, this happens to me as well, maybe even more than average, since I don't like a change if it's not for something markedly better, which was also worth the trouble. Maybe it's matter of age, I don't recall myself to be leaning that much towards "don't fix it, if it isn't broken" mentality before.

Anyway, ever since I put up my Sponsors page, I always viewed it as a place to mention people who donated to the cause directly. Just recently I recognized that I already have a sponsor, only that he didn't provided  donations, but we had good times together. To give him a proper credit (since it's due) I already put Marko K. onto my Sponsors list on this blog, and onto newly added Sponsors page in the book.

If you wish to join him, I'll allow you to bribe me with pizza and a drink, if you know me personally. Heck, you don't even have to know me, it's enough if you can reach me. For those who don't or can't, donating is also completely fine. 😉

Thank you!

So long, Dr. Ludwig

... it was good to know you.

Unfortunately, with his YouTube channel also goes the best interpretation of Radetzky Marsch I have encountered. I have found a replacement; hopefully, this will stay available for longer then my original choice.

Moved!

Well, that didn't took all that long. I was worried because, honestly, I'm not much of an administrator. There are still some loose ends, of course, but nothing that should impact on a daily development. So, new repository is hosted at Codeberg: https://codeberg.org/mmlacak/crochess.

Old repository on GitHub at https://github.com/mmlacak/crochess was updated with new location, and then it was archived. Old repository is not mirrored, so it won't receive any further updates, but will be kept as read-only.

For now, this blog will stay as-is, I don't have much new content for it. You see, I thought I'd write in great detail about intricate design choices I made in code. Turns out, writing in great detail requires quite a bit of effort and time, if you want to introduce designs, and thinking behind them properly. Even worse, when I tried to actually write something, sooner rather than later I ended up with obsolete text, since in the meantime I also changed source code.

For instance, I wanted to write text describing CcPathNode, which is a building block for all possible paths traversed by a piece in a ply. Before I finished it, I removed subs link, because to compare each path in a tree with user notation I had to assemble complete path from root node down to ending leaf node, resulting in CcPathLink linked list. Substitute side-effects were used for displacements, e.g. every time a Serpent encounters a Pawn, there might be multiple valid choices, which do not alter moving piece path (e.g. Serpent in this example).

To prevent tree from eating all available memory, I made a simple linked list effectively just for displacements in CcPathNode. Problem is that substitute side-effect does not belong to any particular step, and so might end on e.g. the last one. Serpent can displace Pawns in each of its steps, so each CcPathNode would carry only one step (so that displacements list can be connected to their rightful step), which would be quite wasteful.

Moreover, choice made is not known in advance, so all choices has to be carried over for comparison, while still being attached to their proper step. Because user notation and generated paths share more-or-less the same data, the same struct is used for both. So, I had to add list of possible displacements to a CcStep, rendering list in CcPathNode obsolete, and so original subs list was removed. So, now each step in a ply could have either a displacement (for user notation) or a list of tentative displacements (for generated path tree). And then, after I finished changes, I recalled that Serpent has two choices after each step, so each CcPathNode in its tree will always contain only one step anyways, and with no bounds its path tree could contain up to 524,288 nodes, at 60 bytes each, giving a grand total of 30 MB ... so much for preserving memory. There are displacements in trance-journey, though, so not everything is lost ðŸ˜….

This explanation isn't very good, but you get the idea how difficult it is to convey the reasoning behind some design choices. Problem is, code is riddled with such intricate decisions, and sometimes I'm not even sure what is the best approach at times, until I try to do something, and then it turns out it has to be changed. On top of that, I have to write and maintain documentation (even if it mostly just enumerates what functions, macros exists with very little explanations) because it might also contain valuable warnings, concepts explained, without which I'd be also lost at code, with no navigation helpers.

So, now you can see why blog will mostly contain announcements when new book update is available, or when application goes live. LinkedIn group will also stay as-is, with mostly just links to blog posts.

No guessing, only counting

Newly introduced randomized variants also pose a good question: how much there are different initial setups? Let's calculate!

Note that randomized Classical Chess variants and randomized Croatian Ties variants of the same size has the same number of possible initial setups. In Croatian Ties variants Knights are replaced by Pegasuses, but otherwise number of different pieces and their count is the same. Pawns in all variants are irrelevant, since they can be arranged in only one way. So, the only difference is the order of figures arranged in the first and last rank. Both mirrored and symmetrical flavors of randomized variants has the same number of combinations, so it's enough to calculate only once, then double the result.

First, a very brief introduction to binomial coefficients:

c = ( n k ) = n ! k ! ⋅ ( n - k ) !

where n≥k≥0, and n!=n⋅(n-1)⋅(n-2)⋅...⋅2⋅1.

Our factor c is number of combinations when placing k pieces of the same kind (e.g. 4 Rooks) onto n available fields (e.g. 10 empty fields).

So, we'll start with randomized Classical Chess 14, and with Bishops, since we have to make sure we have the same number of Bishops on light and dark fields. There are 4 Bishops in this variant, so that would be 2 Bishops on light and other 2 Bishops on dark fields. In these variants there are 14 fields at each rank (surprising, I know!), so that gives us 7 light and 7 dark fields. Obviously, each set of light and dark fields is completely separated from each other, and so numbers of possible arrangements of Bishops on different fields are the same:

c light = c dark = ( 7 2 ) = 7 ! 2 ! ⋅ 5 ! = 21

where 7 is the number of either light or dark fields; and 2 is count of Bishops on those fields. So, our factor clight is number of combinations of 2 Bishops arranged over 7 light fields; and cdark is the same over dark fields.

Next, we have to arrange 4 Rooks over 14-4=10 fields, where 14 is size of a variant, and 4 is number of fields already occupied by Bishops:

c Rooks = ( 10 4 ) = 10 ! 4 ! ⋅ 6 ! = 210

Next, we have to arrange 4 Knights over 14-8=6 fields, where 14 is still size of a variant, and 8 is number of fields already occupied by Bishops and Rooks:

c Knights = ( 6 4 ) = 6 ! 4 ! ⋅ 2 ! = 15

Queen can now pick between two remaining fields (ladies are choosers! 😎):

c Queen = 2

King will have to be satisfied with whatever field is left empty:

c King = 1

So, our number of combinations for randomized Classical Chess 14 variants is:

c 14 = c light ⋅ c dark ⋅ c Rooks ⋅ c Knights ⋅ c Queen ⋅ c King = 2,778,300

that is for either mirrored or symmetrical flavor. If flavor is also randomized choice, total number of initial setups is doubled:

c ∑ 14 = c 14 ⋅ 2 = 2,778,300 ⋅ 2 = 5,556,600

both those numbers also apply to randomized Croatian Ties 14 variant(s).

Calculation of number of different initial setups for randomized Classical Chess 20 variant(s) -and, by extension, Croatian Ties 20 variant(s)- is the same as above, but numbers are slightly bigger. Size of a chessboard is now 20, there are 10 light fields, and 10 dark fields, there are 6 Rooks, 6 Knights and 6 Bishops (of which 3 are on light fields, and other 3 on dark ones). Taking all into account gives the number of initial setups as:

c 20 = 2,421,619,200

that is for either mirrored or symmetrical flavor. If flavor is also randomized choice, total number of initial setups is doubled:

c ∑ 20 = c 20 ⋅ 2 = 2,421,619,200 ⋅ 2 = 4,843,238,400

both those numbers also apply to randomized Croatian Ties 20 variant(s).

Number of different initial setups for randomized Classical Chess 26 variant(s) is calculated the same as above, but numbers are bigger still. Size of a chessboard is now 26, there are 13 light fields, and 13 dark fields, there are 8 Rooks, 8 Knights and 8 Bishops (of which 4 are on light fields, and other 4 on dark ones). So, number of initial setups is:

c 26 = 2,013,316,519,500

that is for either mirrored or symmetrical flavor. If flavor is also randomized choice, total number of initial setups is doubled:

c ∑ 26 = c 26 ⋅ 2 = 2,013,316,519,500 ⋅ 2 = 4,026,633,039,000

both those numbers also apply to randomized Croatian Ties 26 variant(s).

As an interesting tidbit, if we try to calculate number of initial setups for randomized Classical Chess, we get:

c 8 = 2,880

that is for either mirrored or symmetrical flavor. If flavor is also randomized choice, total number of initial setups is doubled:

c ∑ 8 = c 8 ⋅ 2 = 2,880 ⋅ 2 = 5,760

Obviously, these numbers are somewhat bigger than Fischer Random Chess would have it (i.e. 960), since it also imposes an additional constraint on how initial setups are generated; namely, "the King must be placed on a square between the Rooks", and does not support symmetrical flavor, only mirrored.

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.

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 n≥m.

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.

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.

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